Add invoice model with metadata and tags; update search and templates for invoice handling

Progress 
This commit is contained in:
Edgar P. Burkhart 2025-01-05 16:01:26 +01:00
parent 608da4be55
commit c153000d3d
Signed by: edpibu
GPG key ID: 9833D3C5A25BD227
8 changed files with 87 additions and 9 deletions
nummi
main
search
transaction
pkgbuild

View file

@ -7,3 +7,12 @@ def get_icons():
data = json.loads(request.urlopen(url).read())
return [i.removesuffix("-line") for i in data.keys() if i.endswith("-line")]
def pdf_outline_to_str(outline):
return " ".join(
(
dest.title if not isinstance(dest, list) else pdf_outline_to_str(dest)
for dest in outline
)
)

View file

@ -41,7 +41,13 @@
{% transaction_table transactions n_max=8 transactions_url=t_url %}
</section>
{% endif %}
{% if not accounts and not categories and not transactions %}
{% if invoices %}
<section>
<h3>{% translate "Invoices" %}</h3>
{% invoice_table invoices=invoices %}
</section>
{% endif %}
{% if not accounts and not categories and not transactions and not invoices %}
<p>{% translate "No results found." %}</p>
{% endif %}
{% endblock body %}

View file

@ -26,5 +26,6 @@ class SearchView(LoginRequiredMixin, TemplateView):
context["transactions"] = _user.transaction_set.search(self.kwargs["search"])
context["accounts"] = _user.account_set.search(self.kwargs["search"])
context["categories"] = _user.category_set.search(self.kwargs["search"])
context["invoices"] = _user.invoice_set.search(self.kwargs["search"])[:10]
return context

View file

@ -0,0 +1,22 @@
# Generated by Django 4.2.7 on 2025-01-05 14:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("transaction", "0004_remove_transaction_account"),
]
operations = [
migrations.AddField(
model_name="invoice",
name="metadata",
field=models.TextField(blank=True),
),
migrations.AddField(
model_name="invoice",
name="tags",
field=models.TextField(blank=True),
),
]

View file

@ -8,7 +8,9 @@ from django.db import models
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from main.models import NummiModel, NummiQuerySet
from main.utils import pdf_outline_to_str
from media.utils import get_path
from pypdf import PdfReader
from statement.models import Statement
@ -74,6 +76,13 @@ class Transaction(NummiModel):
verbose_name_plural = _("Transactions")
class InvoiceQuerySet(NummiQuerySet):
fields = {
"metadata": "B",
"tags": "C",
}
class Invoice(NummiModel):
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
name = models.CharField(
@ -88,12 +97,35 @@ class Invoice(NummiModel):
transaction = models.ForeignKey(
Transaction, on_delete=models.CASCADE, editable=False
)
metadata = models.TextField(blank=True)
tags = models.TextField(blank=True)
objects = InvoiceQuerySet.as_manager()
def save(self, *args, **kwargs):
if Invoice.objects.filter(id=self.id).exists():
_prever = Invoice.objects.get(id=self.id)
if _prever.file and _prever.file != self.file:
Path(_prever.file.path).unlink(missing_ok=True)
reader = PdfReader(self.file)
self.metadata = " ".join(
(
m
for m in (
reader.metadata.title,
reader.metadata.author,
reader.metadata.subject,
)
if m
)
)
_tags = pdf_outline_to_str(reader.outline)
_tags += " ".join((page.extract_text() for page in reader.pages))
self.tags = " ".join((tag for tag in _tags.split() if len(tag) >= 3))
super().save(*args, **kwargs)
def __str__(self):

View file

@ -3,14 +3,19 @@
<ul class="invoices">
{% for invoice in invoices %}
<li>
{% if not transaction %}<span>{{ invoice.transaction.name }}</span>{% endif %}
<a class="title" href="{{ invoice.file.url }}">{{ "file"|remix }}{{ invoice.name }} [{{ invoice.file|extension }}]</a>
<a href="{{ invoice.get_absolute_url }}">{{ "file-edit"|remix }}{% translate "Edit" %}</a>
{% if transaction %}
<a href="{{ invoice.get_absolute_url }}">{{ "file-edit"|remix }}{% translate "Edit" %}</a>
{% endif %}
</li>
{% endfor %}
<li class="new">
<span>
<a href="{% url "new_invoice" transaction.pk %}">{{ "file-add"|remix }}{% translate "New invoice" %}</a>
</span>
</li>
{% if transaction %}
<li class="new">
<span>
<a href="{% url "new_invoice" transaction.pk %}">{{ "file-add"|remix }}{% translate "New invoice" %}</a>
</span>
</li>
{% endif %}
</ul>
</div>

View file

@ -36,10 +36,12 @@ def transaction_filters(context, **kwargs):
@register.inclusion_tag("transaction/invoice_table.html")
def invoice_table(transaction, **kwargs):
def invoice_table(transaction=None, **kwargs):
if transaction:
kwargs.setdefault("invoices", transaction.invoice_set.all())
return kwargs | {
"transaction": transaction,
"invoices": transaction.invoice_set.all(),
}

View file

@ -11,6 +11,7 @@ depends=(
"python-toml"
"python-psycopg"
"python-dateutil"
"python-pypdf"
)
makedepends=("git")
optdepends=("postgresql: database")