facturation: imprimer un bordereau de remise de règlements (#88701) #180

Merged
lguerin merged 2 commits from wip/88701-invoicing-docket-csv into main 2024-04-15 15:46:08 +02:00
7 changed files with 584 additions and 68 deletions

View File

@ -1392,6 +1392,17 @@ class PaymentDocket(models.Model):
qs = self.payment_set.filter(cancelled_at__isnull=False).select_related('payment_type')
return {'list': qs.order_by('-created_at'), 'amount': qs.aggregate(amount=models.Sum('amount'))}
def html(self):
template = get_template('lingo/invoicing/docket.html')
context = {
'regie': self.regie,
'object': self,
'active': self.get_active_payments(),
'cancelled': self.get_cancelled_payments(),
'payment_info': PAYMENT_INFO,
}
return template.render(context)
PAYMENT_INFO = [
('check_issuer', _('Issuer')),

View File

@ -0,0 +1,152 @@
{% extends "lingo/invoicing/print_document_base.html" %}
{% load i18n %}
{% block css %}
<style>
html {
padding: 0;
margin: 0;
color: #14213d;
font-family: "DejaVu Sans", sans-serif;
font-size: 9pt;
line-height: 1.2;
}
body {
margin: 0;
}
@media screen {
body {
margin: auto;
width: 21cm;
position: relative;
}
}
@page {
margin: 0.5cm;
margin-bottom: 1cm;
size: landscape;
@bottom-right {
content: "{% trans "Page" %} " counter(page) "/" counter(pages);
height: 1cm;
text-align: right;
width: 2cm;
}
}
body {
font-family: sans-serif;
font-size: 8pt;
}
table {
border-collapse: collapse;
}
th {
padding: 0.5em 0.5ex;
border: 0.5px solid black;
}
td {
border: 0.5px solid black;
padding: 0.5em 0.5ex;
}
</style>
{% endblock %}
{% block document-label %}{{ object }}{% endblock %}
{% block header %}{% endblock %}
{% block content %}
<h1>{{ regie }} - {% blocktrans %}List of the payments of docket {{ object }}{% endblocktrans %}</h1>
{% for value in active %}
{% if value.list %}
<h2>{{ value.payment_type }}</h2>
<div>
<p>
{% trans "Number of payments:" %} {{ value.list|length }}
<br />
{% trans "Total amount:" %} {% blocktrans with amount=value.amount.amount|floatformat:"2" %}{{ amount }}€{% endblocktrans %}
<br />
{% trans "Additionnal information:" %}
<br />
{{ object.payment_types_info|get:value.payment_type.slug|default:""|linebreaksbr }}
</p>
<table>
<thead>
<tr>
<th>{% trans "Number" %}</th>
<th>{% trans "Date" %}</th>
<th>{% trans "Payer ID" %}</th>
<th>{% trans "Payer first name" %}</th>
<th>{% trans "Payer last name" %}</th>
<th>{% trans "Total amount" %}</th>
{% for k, v in payment_info %}
<th>{{ v }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for payment in value.list %}
<tr>
<td>{{ payment.formatted_number }}</td>
<td>{{ payment.created_at|date:"d/m/Y" }}</td>
<td>{{ payment.payer_external_id }}</td>
<td>{{ payment.payer_first_name }}</td>
<td>{{ payment.payer_last_name }}</td>
<td>{% blocktrans with amount=payment.amount|floatformat:"2" %}{{ amount }}€{% endblocktrans %}</td>
{% for k, v in payment_info %}
<td>{{ payment.payment_info|get:k|default:'' }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% endfor %}
{% if cancelled.list %}
<h2>{% trans "Cancelled payments" %}</h2>
<div>
<p>
{% trans "Number of payments:" %} {{ cancelled.list|length }}
<br />
{% trans "Total amount:" %} {% blocktrans with amount=cancelled.amount.amount|floatformat:"2" %}{{ amount }}€{% endblocktrans %}
</p>
<table>
<thead>
<tr>
<th>{% trans "Number" %}</th>
<th>{% trans "Date" %}</th>
<th>{% trans "Payer ID" %}</th>
<th>{% trans "Payer first name" %}</th>
<th>{% trans "Payer last name" %}</th>
<th>{% trans "Total amount" %}</th>
{% for k, v in payment_info %}
<th>{{ v }}</th>
{% endfor %}
<th>{% trans "Cancelled on" %}</th>
<th>{% trans "Cancellation reason" %}</th>
</tr>
</thead>
<tbody>
{% for payment in cancelled.list %}
<tr>
<td>{{ payment.formatted_number }}</td>
<td>{{ payment.created_at|date:"d/m/Y" }}</td>
<td>{{ payment.payer_external_id }}</td>
<td>{{ payment.payer_first_name }}</td>
<td>{{ payment.payer_last_name }}</td>
<td>{% blocktrans with amount=payment.amount|floatformat:"2" %}{{ amount }}€{% endblocktrans %}</td>
{% for k, v in payment_info %}
<td>{{ payment.payment_info|get:k|default:'' }}</td>
{% endfor %}
<td>{{ payment.cancelled_at|date:"d/m/Y" }}</td>
<td>{{ payment.cancellation_reason|default:'' }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% endblock %}

View File

@ -20,7 +20,7 @@
{% block content %}
{% url 'lingo-manager-invoicing-regie-payment-list' regie_pk=regie.pk as regie_payment_list_url %}
{% for value in object.get_active_payments %}
{% for value in active %}
{% if value.list %}
<div class="section">
<h3>
@ -54,38 +54,38 @@
{% endif %}
{% endfor %}
{% with object.get_cancelled_payments as cancelled %}
{% if cancelled.list %}
<div class="section">
<h3>{% trans "Cancelled payments" %}</h3>
<div>
<p>
{% trans "Number of payments:" %} {{ cancelled.list|length }}
<br />
{% trans "Total amount:" %} {% blocktrans with amount=cancelled.amount.amount|floatformat:"2" %}{{ amount }}€{% endblocktrans %}
</p>
<table class="main pk-compact-table invoicing-element-list">
{% for payment in cancelled.list %}
<tr>
<td colspan="4">
{% blocktrans with payment_number=payment.formatted_number cdate=payment.created_at|date:'d/m/Y' payer_id=payment.payer_external_id payer_name=payment.payer_name amount=payment.amount payment_type=payment.payment_type %}Payment <a href="{{ regie_payment_list_url }}?number={{ payment_number }}">{{ payment_number }}</a> dated {{ cdate }} from {{ payer_name }}, amount {{ amount }}€ ({{ payment_type }}){% endblocktrans %}
</td>
</tr>
{% endfor %}
</table>
</div>
{% if cancelled.list %}
<div class="section">
<h3>{% trans "Cancelled payments" %}</h3>
<div>
<p>
{% trans "Number of payments:" %} {{ cancelled.list|length }}
<br />
{% trans "Total amount:" %} {% blocktrans with amount=cancelled.amount.amount|floatformat:"2" %}{{ amount }}€{% endblocktrans %}
</p>
<table class="main pk-compact-table invoicing-element-list">
{% for payment in cancelled.list %}
<tr>
<td colspan="4">
{% blocktrans with payment_number=payment.formatted_number cdate=payment.created_at|date:'d/m/Y' payer_id=payment.payer_external_id payer_name=payment.payer_name amount=payment.amount payment_type=payment.payment_type %}Payment <a href="{{ regie_payment_list_url }}?number={{ payment_number }}">{{ payment_number }}</a> dated {{ cdate }} from {{ payer_name }}, amount {{ amount }}€ ({{ payment_type }}){% endblocktrans %}
</td>
</tr>
{% endfor %}
</table>
</div>
{% endif %}
{% endwith %}
</div>
{% endif %}
{% endblock %}
{% block sidebar %}
{% if object.draft %}
<aside id="sidebar">
<aside id="sidebar">
<h3>{% trans "Actions" %}</h3>
<h3>{% trans "Actions" %}</h3>
{% if object.draft %}
<a class="button button-paragraph" href="{% url 'lingo-manager-invoicing-regie-docket-edit' regie.pk object.pk %}">{% trans "Edit" %}</a>
<a class="button button-paragraph" href="{% url 'lingo-manager-invoicing-regie-docket-validate' regie.pk object.pk %}" rel="popup">{% trans "Validate" %}</a>
</aside>
{% endif %}
{% endif %}
<a class="button button-paragraph" href="{% url 'lingo-manager-invoicing-regie-docket-csv' regie.pk object.pk %}">{% trans "CSV export" %}</a>
<a class="button button-paragraph" href="{% url 'lingo-manager-invoicing-regie-docket-pdf' regie.pk object.pk %}">{% trans "PDF export" %}</a>
</aside>
{% endblock %}

View File

@ -3,8 +3,8 @@
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>{% block title %}{{ object.formatted_number }}{% endblock %}</title>
<meta name="author" content="Entr'ouvert">
<style>
{% block css %}
{% block css %}
<style>
html {
padding: 0;
margin: 0;
@ -172,45 +172,47 @@
content: "{% trans "Page" %} " counter(page) "/" counter(pages);
}
}
{% endblock %}
</style>
</style>
{% endblock %}
</head>
<body>
<header>
<aside>
{% if appearance_settings.logo %}
<img id="logo" src="data:{{appearance_settings.logo.content_type}};base64,{{ appearance_settings.logo_base64_encoded }}">
{% endif %}
{% if appearance_settings.address %}
<address id="from">
{{ appearance_settings.address|safe }}
</address>
{% endif %}
{% if appearance_settings.extra_info %}
<div id="extra-info">
{{ appearance_settings.extra_info|safe }}
</div>
{% endif %}
{% if invoice.pool.campaign.invoice_custom_text %}
<div id="extra-info">
{{ invoice.pool.campaign.invoice_custom_text|safe }}
</div>
{% endif %}
</aside>
<div>
<h1 id="document-label">{% block document-label %}{% endblock %}</h1>
{% block regie-label %}<h2 id="regie-label">{{ regie.label }}</h2>{% endblock %}
{% block address-to %}
<address id="to">
{% block address_to %}
{{ object.payer_first_name}} {{ object.payer_last_name}}
<br />
{{ object.payer_address|linebreaksbr }}
{% endblock %}
</address>
{% endblock %}
</div>
</header>
{% block header %}
<header>
<aside>
{% if appearance_settings.logo %}
<img id="logo" src="data:{{appearance_settings.logo.content_type}};base64,{{ appearance_settings.logo_base64_encoded }}">
{% endif %}
{% if appearance_settings.address %}
<address id="from">
{{ appearance_settings.address|safe }}
</address>
{% endif %}
{% if appearance_settings.extra_info %}
<div id="extra-info">
{{ appearance_settings.extra_info|safe }}
</div>
{% endif %}
{% if invoice.pool.campaign.invoice_custom_text %}
<div id="extra-info">
{{ invoice.pool.campaign.invoice_custom_text|safe }}
</div>
{% endif %}
</aside>
<div>
<h1 id="document-label">{% block document-label %}{% endblock %}</h1>
{% block regie-label %}<h2 id="regie-label">{{ regie.label }}</h2>{% endblock %}
{% block address-to %}
<address id="to">
{% block address_to %}
{{ object.payer_first_name}} {{ object.payer_last_name}}
<br />
{{ object.payer_address|linebreaksbr }}
{% endblock %}
</address>
{% endblock %}
</div>
</header>
{% endblock %}
<main>
{% block informations-container %}
<dl id="informations">

View File

@ -228,6 +228,16 @@ urlpatterns = [
regie_views.regie_docket_detail,
name='lingo-manager-invoicing-regie-docket-detail',
),
path(
'regie/<int:regie_pk>/docket/<int:pk>/export/csv/',
regie_views.regie_docket_csv,
name='lingo-manager-invoicing-regie-docket-csv',
),
path(
'regie/<int:regie_pk>/docket/<int:pk>/export/pdf/',
regie_views.regie_docket_pdf,
name='lingo-manager-invoicing-regie-docket-pdf',
),
path(
'regie/<int:regie_pk>/docket/<int:pk>/edit/',
regie_views.regie_docket_edit,

View File

@ -891,12 +891,142 @@ class RegieDocketDetailView(DetailView):
def get_context_data(self, **kwargs):
kwargs['regie'] = self.regie
kwargs['active'] = self.object.get_active_payments()
kwargs['cancelled'] = self.object.get_cancelled_payments()
return super().get_context_data(**kwargs)
regie_docket_detail = RegieDocketDetailView.as_view()
class RegieDocketCSVView(DetailView):
model = PaymentDocket
def dispatch(self, request, *args, **kwargs):
self.regie = get_object_or_404(Regie, pk=kwargs['regie_pk'])
return super().dispatch(request, *args, **kwargs)
def get_queryset(self):
return self.regie.paymentdocket_set.all()
def get(self, request, *args, **kwargs):
self.object = self.get_object()
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="docket-%s.csv"' % self.object
writer = csv.writer(response)
for value in self.object.get_active_payments():
if not value['list']:
continue
writer.writerow(
[
_('Number of payments'),
_('Total amount'),
_('Payment type'),
_('Additionnal information'),
]
)
writer.writerow(
[
len(value['list']),
value['amount']['amount'],
value['payment_type'],
self.object.payment_types_info.get(value['payment_type'].slug) or '',
]
)
headers = [
Review

Ça va être exploité comment ce CSV ? C’est les agents et les régisseurs qui directement vont le consulter en l’ouvrant dans un tableur ?
J’ai un peu peur de la lisibilité lorsqu’on a un seul CSV global comme ça avec des lignes qui correspondent à plusieurs choses différentes (d’abord un récapitulatif de tous les paiements, puis les paiements actifs, puis les paiements annulés), intuitivement j’aurais pensé qu’on aurait éclaté cela en plusieurs CSV.

Ça va être exploité comment ce CSV ? C’est les agents et les régisseurs qui directement vont le consulter en l’ouvrant dans un tableur ? J’ai un peu peur de la lisibilité lorsqu’on a un seul CSV global comme ça avec des lignes qui correspondent à plusieurs choses différentes (d’abord un récapitulatif de tous les paiements, puis les paiements actifs, puis les paiements annulés), intuitivement j’aurais pensé qu’on aurait éclaté cela en plusieurs CSV.
Review

Ca a été vu avec stef, ça lui allait comme ça.
On itèrera si besoin

Ca a été vu avec stef, ça lui allait comme ça. On itèrera si besoin
_('Number'),
_('Date'),
_('Payer ID'),
_('Payer first name'),
_('Payer last name'),
_('Payment type'),
_('Total amount'),
] + [v for k, v in PAYMENT_INFO]
writer.writerow(headers)
for payment in value['list']:
writer.writerow(
[
payment.formatted_number,
payment.created_at.date().isoformat(),
payment.payer_external_id,
payment.payer_first_name,
payment.payer_last_name,
payment.payment_type.label,
payment.amount,
]
+ [payment.payment_info.get(k) or '' for k, v in PAYMENT_INFO]
)
cancelled = self.object.get_cancelled_payments()
if cancelled['list']:
writer.writerow(
[
_('Number of payments'),
_('Total amount'),
]
)
writer.writerow(
[
len(cancelled['list']),
value['amount']['amount'],
]
)
headers = (
[
_('Number'),
_('Date'),
_('Payer ID'),
_('Payer first name'),
_('Payer last name'),
_('Payment type'),
_('Total amount'),
]
+ [v for k, v in PAYMENT_INFO]
+ [
_('Cancelled on'),
_('Cancellation reason'),
]
)
writer.writerow(headers)
for payment in cancelled['list']:
writer.writerow(
[
payment.formatted_number,
payment.created_at.date().isoformat(),
payment.payer_external_id,
payment.payer_first_name,
payment.payer_last_name,
payment.payment_type.label,
payment.amount,
]
+ [payment.payment_info.get(k) or '' for k, v in PAYMENT_INFO]
+ [
payment.cancelled_at.isoformat(),
payment.cancellation_reason or '',
]
)
return response
regie_docket_csv = RegieDocketCSVView.as_view()
class RegieDocketPDFView(PDFMixin, DetailView):
model = PaymentDocket
def dispatch(self, request, *args, **kwargs):
self.regie = get_object_or_404(Regie, pk=kwargs['regie_pk'])
return super().dispatch(request, *args, **kwargs)
def get_queryset(self):
return self.regie.paymentdocket_set.all()
def get_filename(self):
return self.object
regie_docket_pdf = RegieDocketPDFView.as_view()
class RegieDocketEditView(UpdateView):
template_name = 'lingo/invoicing/manager_docket_form.html'
model = PaymentDocket

View File

@ -402,7 +402,7 @@ def test_regie_docket_detail(app, admin_user):
resp = resp.click('Dockets')
resp = resp.click('Dockets')
resp = resp.click(docket.formatted_number)
assert [PyQuery(h3).text() for h3 in resp.pyquery('h3')] == [
assert [PyQuery(h3).text() for h3 in resp.pyquery('#main-content h3')] == [
'Cash',
'Check',
'Cancelled payments',
@ -434,6 +434,217 @@ def test_regie_docket_detail(app, admin_user):
assert PyQuery(resp.pyquery('p')[2]).text() == 'Number of payments: 1\nTotal amount: 43.00€'
def test_regie_docket_csv(app, admin_user):
regie = Regie.objects.create(label='Foo')
PaymentType.create_defaults(regie)
docket = PaymentDocket.objects.create(
regie=regie,
date_end=now().date() + datetime.timedelta(days=1),
draft=True,
payment_types_info={
'cash': 'foo bar\nblah',
'check': 'foo bar',
},
)
docket.payment_types.set(PaymentType.objects.all())
payment1 = Payment.objects.create(
regie=regie,
amount=35,
payment_type=PaymentType.objects.get(regie=regie, slug='cash'),
payer_external_id='payer:1',
payer_first_name='First1',
payer_last_name='Name1',
docket=docket,
)
payment1.set_number()
payment1.save()
payment2 = Payment.objects.create(
regie=regie,
amount=42,
payment_type=PaymentType.objects.get(regie=regie, slug='check'),
payer_external_id='payer:2',
payer_first_name='First2',
payer_last_name='Name2',
docket=docket,
)
payment2.set_number()
payment2.save()
payment3 = Payment.objects.create(
regie=regie,
amount=43,
payment_type=PaymentType.objects.get(regie=regie, slug='check'),
payer_external_id='payer:3',
payer_first_name='First3',
payer_last_name='Name3',
docket=docket,
cancelled_at=now(),
)
payment3.set_number()
payment3.save()
payment4 = Payment.objects.create(
regie=regie,
amount=23,
payment_type=PaymentType.objects.get(regie=regie, slug='check'),
payer_external_id='payer:3',
payer_first_name='First3',
payer_last_name='Name3',
docket=docket,
)
payment4.set_number()
payment4.save()
app = login(app)
resp = app.get('/manage/invoicing/regie/%s/docket/%s/' % (regie.pk, docket.pk))
resp = resp.click('CSV export')
assert resp.headers['Content-Type'] == 'text/csv'
assert resp.headers['Content-Disposition'] == 'attachment; filename="docket-TEMPORARY-%s.csv"' % docket.pk
assert len([a for a in resp.text.split('\r\n') if a]) == 13
assert resp.text == (
'Number of payments,Total amount,Payment type,Additionnal information\r\n'
'1,35.00,Cash,"foo bar\nblah"\r\n'
'Number,Date,Payer ID,Payer first name,Payer last name,Payment type,Total amount,Issuer,Bank/Organism,Number,Reference\r\n'
'R%02d-%s-0000001,%s,payer:1,First1,Name1,Cash,35.00,,,,\r\n'
'Number of payments,Total amount,Payment type,Additionnal information\r\n2,65.00,Check,foo bar\r\n'
'Number,Date,Payer ID,Payer first name,Payer last name,Payment type,Total amount,Issuer,Bank/Organism,Number,Reference\r\n'
'R%02d-%s-0000004,%s,payer:3,First3,Name3,Check,23.00,,,,\r\n'
'R%02d-%s-0000002,%s,payer:2,First2,Name2,Check,42.00,,,,\r\n'
'Number of payments,Total amount\r\n'
'1,\r\n'
'Number,Date,Payer ID,Payer first name,Payer last name,Payment type,Total amount,Issuer,Bank/Organism,Number,Reference,Cancelled on,'
'Cancellation reason\r\n'
'R%02d-%s-0000003,%s,payer:3,First3,Name3,Check,43.00,,,,,%s,\r\n'
) % (
regie.pk,
payment1.created_at.strftime('%y-%m'),
payment1.created_at.strftime('%Y-%m-%d'),
regie.pk,
payment4.created_at.strftime('%y-%m'),
payment4.created_at.strftime('%Y-%m-%d'),
regie.pk,
payment2.created_at.strftime('%y-%m'),
payment2.created_at.strftime('%Y-%m-%d'),
regie.pk,
payment3.created_at.strftime('%y-%m'),
payment3.created_at.strftime('%Y-%m-%d'),
payment3.cancelled_at.isoformat(),
)
docket.draft = False
docket.set_number()
docket.save()
resp = app.get('/manage/invoicing/regie/%s/docket/%s/export/csv/' % (regie.pk, docket.pk))
assert resp.headers['Content-Type'] == 'text/csv'
assert resp.headers['Content-Disposition'] == 'attachment; filename="docket-B%02d-%s-0000001.csv"' % (
regie.pk,
docket.created_at.strftime('%y-%m'),
)
def test_regie_docket_pdf(app, admin_user):
regie = Regie.objects.create(label='Foo')
PaymentType.create_defaults(regie)
docket = PaymentDocket.objects.create(
regie=regie,
date_end=now().date() + datetime.timedelta(days=1),
draft=True,
payment_types_info={
'cash': 'foo bar\nblah',
'check': 'foo bar',
},
)
docket.payment_types.set(PaymentType.objects.all())
payment1 = Payment.objects.create(
regie=regie,
amount=35,
payment_type=PaymentType.objects.get(regie=regie, slug='cash'),
payer_external_id='payer:1',
payer_first_name='First1',
payer_last_name='Name1',
docket=docket,
)
payment1.set_number()
payment1.save()
payment2 = Payment.objects.create(
regie=regie,
amount=42,
payment_type=PaymentType.objects.get(regie=regie, slug='check'),
payer_external_id='payer:2',
payer_first_name='First2',
payer_last_name='Name2',
docket=docket,
)
payment2.set_number()
payment2.save()
payment3 = Payment.objects.create(
regie=regie,
amount=43,
payment_type=PaymentType.objects.get(regie=regie, slug='check'),
payer_external_id='payer:3',
payer_first_name='First3',
payer_last_name='Name3',
docket=docket,
cancelled_at=now(),
)
payment3.set_number()
payment3.save()
payment4 = Payment.objects.create(
regie=regie,
amount=23,
payment_type=PaymentType.objects.get(regie=regie, slug='check'),
payer_external_id='payer:3',
payer_first_name='First3',
payer_last_name='Name3',
docket=docket,
)
payment4.set_number()
payment4.save()
app = login(app)
resp = app.get('/manage/invoicing/regie/%s/docket/%s/' % (regie.pk, docket.pk))
assert '/manage/invoicing/regie/%s/docket/%s/export/pdf/' % (regie.pk, docket.pk) in resp
resp = app.get('/manage/invoicing/regie/%s/docket/%s/export/pdf/?html' % (regie.pk, docket.pk))
assert [PyQuery(h2).text() for h2 in resp.pyquery('h2')] == [
'Cash',
'Check',
'Cancelled payments',
]
assert len(resp.pyquery('table')) == 3
assert [PyQuery(tr).text() for tr in PyQuery(resp.pyquery('table')[0]).find('tr')] == [
'Number\nDate\nPayer ID\nPayer first name\nPayer last name\nTotal amount\nIssuer\nBank/Organism\nNumber\nReference',
'R%02d-%s-0000001\n%s\npayer:1\nFirst1\nName1\n35.00€'
% (regie.pk, payment1.created_at.strftime('%y-%m'), payment1.created_at.strftime('%d/%m/%Y')),
]
assert [PyQuery(tr).text() for tr in PyQuery(resp.pyquery('table')[1]).find('tr')] == [
'Number\nDate\nPayer ID\nPayer first name\nPayer last name\nTotal amount\nIssuer\nBank/Organism\nNumber\nReference',
'R%02d-%s-0000004\n%s\npayer:3\nFirst3\nName3\n23.00€'
% (regie.pk, payment4.created_at.strftime('%y-%m'), payment4.created_at.strftime('%d/%m/%Y')),
'R%02d-%s-0000002\n%s\npayer:2\nFirst2\nName2\n42.00€'
% (regie.pk, payment2.created_at.strftime('%y-%m'), payment2.created_at.strftime('%d/%m/%Y')),
]
assert [PyQuery(tr).text() for tr in PyQuery(resp.pyquery('table')[2]).find('tr')] == [
'Number\nDate\nPayer ID\nPayer first name\nPayer last name\nTotal amount\nIssuer\nBank/Organism\nNumber\nReference\nCancelled on\nCancellation reason',
'R%02d-%s-0000003\n%s\npayer:3\nFirst3\nName3\n43.00€\n%s'
% (
regie.pk,
payment3.created_at.strftime('%y-%m'),
payment3.created_at.strftime('%d/%m/%Y'),
payment3.cancelled_at.strftime('%d/%m/%Y'),
),
]
assert len(resp.pyquery('p')) == 3
assert (
PyQuery(resp.pyquery('p')[0]).text()
== 'Number of payments: 1\nTotal amount: 35.00€\nAdditionnal information:\nfoo bar\nblah'
)
assert (
PyQuery(resp.pyquery('p')[1]).text()
== 'Number of payments: 2\nTotal amount: 65.00€\nAdditionnal information:\nfoo bar'
)
assert PyQuery(resp.pyquery('p')[2]).text() == 'Number of payments: 1\nTotal amount: 43.00€'
def test_regie_docket_edit(app, admin_user):
regie = Regie.objects.create(label='Foo')
PaymentType.create_defaults(regie)