facturation: imprimer un bordereau de remise de règlements (#88701) #180
|
@ -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')),
|
||||
|
|
|
@ -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 %}
|
|
@ -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 %}
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 = [
|
||||
|
||||
_('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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue
Ç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.
Ca a été vu avec stef, ça lui allait comme ça.
On itèrera si besoin