invoicing: use common PDF document model for payment certificates (#80894) #109

Merged
fpeters merged 1 commits from wip/80894-payment-certificate-pdf into main 2023-09-26 16:45:55 +02:00
3 changed files with 41 additions and 158 deletions

View File

@ -678,7 +678,9 @@ class AbstractInvoice(models.Model):
context = {
'regie': self.regie,
'invoice': self,
'object': self,
'payments': InvoiceLinePayment.objects.filter(line__invoice=self).order_by('created_at'),
'appearance_settings': AppearanceSettings.singleton(),
}
return template.render(context)

View File

@ -1,158 +1,41 @@
{% load static i18n lingo %}
<!doctype html><html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>{{ invoice.formatted_number }}</title>
<meta name="author" content="Entr'ouvert">
<style>
html {
color: #14213d;
font-family: Source Sans Pro;
font-size: 8pt;
line-height: 1.2;
}
body {
margin: 0;
}
{% extends "lingo/invoicing/print_document_base.html" %}
{% load i18n lingo %}
h1 {
color: #df5a13;
font-family: Pacifico;
margin: 0.4em 0;
font-size: 12pt;
}
h2 {
margin: 2em 0;
font-size: 10pt;
}
{% block document-label %}{% trans "Payments certificate" %}{% endblock %}
aside {
display: flex;
margin: 2em 0 4em;
}
aside address {
font-style: normal;
white-space: pre-line;
}
aside address#from {
color: #a9a;
flex: 1;
}
aside address#to {
text-align: right;
}
{% block informations %}
<dt>{% trans "Invoice number:" %}</dt>
<dd>{{ invoice.formatted_number }}</dd>
<dt>{% trans "Date:" %}</dt>
<dd>{{ invoice.created_at|date }}</dd>
{% endblock %}
dl {
position: absolute;
right: 0;
text-align: right;
top: 0;
}
dt, dd {
display: inline;
margin: 0;
}
dt {
color: #a9a;
}
dt::before {
content: '';
display: block;
}
dt::after {
content: ':';
}
table {
border-collapse: collapse;
width: 100%;
}
th {
border-bottom: .2mm solid #a9a;
color: #a9a;
font-size: 9pt;
font-weight: 400;
padding-bottom: .25cm;
text-transform: uppercase;
}
td {
padding-top: 7mm;
}
th.amount, td.amount {
text-align: right;
}
table#total {
background: #f6f6f6;
border-color: #f6f6f6;
border-style: solid;
border-width: 2cm 3cm;
bottom: 0;
right: 0;
font-size: 10pt;
margin: 0 -3cm;
position: absolute;
width: 12cm;
text-align: right;
}
div.break {
break-before: page;
}
@page {
@bottom-right{
content: "{% trans "Page" %} " counter(page) "/" counter(pages);
}
}
</style>
</head>
<body>
<h1>{% trans "Payments certificate" %}</h1>
<aside>
<address id="from">
{{ regie.label }}
</address>
<address id="to">
{{ invoice.payer_first_name}} {{ invoice.payer_last_name}}
<br />
{{ invoice.payer_address|linebreaksbr }}
</address>
</aside>
<dl id="informations">
<dt>{% trans "Invoice number" %}</dt>
<dd>{{ invoice.formatted_number }}</dd>
<dt>{% trans "Date" %}</dt>
<dd>{{ invoice.created_at|date }}</dd>
</dl>
<table id="lines">
<thead>
{% block content %}
<table id="lines">
<thead>
<tr>
<th class="invoice">{% trans "Number" context 'payment' %}</th>
<th class="date">{% trans "Date" %}</th>
<th class="type">{% trans "Payment type" %}</th>
<th class="amount">{% trans "Amount" %}</th>
</tr>
</thead>
<tbody>
{% for invoice_line_payment in payments %}
<tr>
<th class="invoice">{% trans "Number" context 'payment' %}</th>
<th class="date">{% trans "Date" %}</th>
<th class="type">{% trans "Payment type" %}</th>
<th class="amount">{% trans "Amount" %}</th>
<td class="invoice">{{ invoice_line_payment.payment.formatted_number }}</td>
<td class="date">{{ invoice_line_payment.created_at|date:"d/m/Y" }}</td>
<td class="type">{{ invoice_line_payment.payment.payment_type }}</td>
<td class="amount">{% blocktrans with amount=invoice_line_payment.amount|floatformat:"2" %}{{ amount }}€{% endblocktrans %}</td>
</tr>
</thead>
<tbody>
{% for invoice_line_payment in payments %}
<tr>
<td class="invoice">{{ invoice_line_payment.payment.formatted_number }}</td>
<td class="date">{{ invoice_line_payment.created_at|date:"d/m/Y" }}</td>
<td class="type">{{ invoice_line_payment.payment.payment_type }}</td>
<td class="amount">{% blocktrans with amount=invoice_line_payment.amount|floatformat:"2" %}{{ amount }}€{% endblocktrans %}</td>
</tr>
{% endfor %}
</tbody>
</table>
<table id="total">
<thead>
<tr>
<th>{% trans "Paid amount" %}</th>
</tr>
</thead>
<tbody>
<tr>
<td>{% blocktrans with amount=invoice.paid_amount|floatformat:"2" %}{{ amount }}€{% endblocktrans %}</td>
</tr>
</tbody>
</table>
</body>
</html>
{% endfor %}
</tbody>
<tfoot>
<tr class="grand-total">
<td class="grand-total-intro" colspan="3">{% trans "Paid amount:" %}</td>
<td class="amount total-amount">{% blocktrans with amount=invoice.paid_amount|floatformat:"2" %}{{ amount }}€{% endblocktrans %}</td>
</tr>
</tfoot>
</table>
{% endblock %}

View File

@ -1361,17 +1361,16 @@ def test_regie_invoice_payments_pdf(app, admin_user):
app = login(app)
resp = app.get('/manage/invoicing/regie/%s/invoice/%s/payments/pdf/?html' % (regie.pk, invoice.pk))
assert resp.pyquery('h1').text() == 'Payments certificate'
assert resp.pyquery('address#from').text() == 'Foo'
assert resp.pyquery('#document-label').text() == 'Payments certificate'
assert resp.pyquery('#regie-label').text() == 'Foo'
assert resp.pyquery('address#to').text() == 'First1 Name1\n41 rue des kangourous\n99999 Kangourou Ville'
assert resp.pyquery('dl#informations').text() == 'Invoice number\nF%02d-%s-0000001\nDate\n%s' % (
assert resp.pyquery('dl#informations').text() == 'Invoice number:\nF%02d-%s-0000001\nDate:\n%s' % (
regie.pk,
invoice.created_at.strftime('%y-%m'),
date_format(localtime(invoice.created_at), 'DATE_FORMAT'),
)
assert [PyQuery(tr).text() for tr in resp.pyquery.find('thead tr')] == [
'Number\nDate\nPayment type\nAmount',
'Paid amount',
]
assert [PyQuery(tr).text() for tr in resp.pyquery.find('tbody tr')] == [
'R%02d-%s-0000001\n%s\nCheck\n5.00€'
@ -1386,9 +1385,8 @@ def test_regie_invoice_payments_pdf(app, admin_user):
payment2.created_at.strftime('%y-%m'),
payment2.created_at.strftime('%d/%m/%Y'),
),
'40.00€',
]
assert resp.pyquery('table#total tbody').text() == '40.00€'
assert resp.pyquery('tfoot .total-amount').text() == '40.00€'
resp = app.get('/manage/invoicing/regie/%s//payment/%s/payments/pdf/?html' % (0, invoice.pk), status=404)
resp = app.get('/manage/invoicing/regie/%s//payment/%s/payments/pdf/?html' % (regie.pk, 0), status=404)