invoicing: edit and refresh docket (#88699) #178

Merged
lguerin merged 1 commits from wip/88699-invoicing-docket-refresh into main 2024-04-08 09:58:04 +02:00
6 changed files with 182 additions and 12 deletions

View File

@ -886,13 +886,17 @@ class PaymentDocketForm(forms.ModelForm):
}
def __init__(self, *args, **kwargs):
self.regie = kwargs.pop('regie')
if kwargs.get('data') is None:
# set initial through data, so form is valid on page load
kwargs['data'] = {
'payment_types': [p.pk for p in self.regie.paymenttype_set.all()],
'date_end': now().date(),
}
instance = kwargs['instance']
if not instance.pk:
self.regie = kwargs.pop('regie')
if kwargs.get('data') is None:
# set initial through data, so form is valid on page load
kwargs['data'] = {
'payment_types': [p.pk for p in self.regie.paymenttype_set.all()],
'date_end': now().date(),
}
else:
self.regie = instance.regie
pmarillonnet marked this conversation as resolved Outdated

J’ai pas compris ce qui empêche de faire tout le # set initial through data de l’autre embranchement aussi ici et d’avoir seulement dans le if … else la façon dont self.regie est initialisé.

J’ai pas compris ce qui empêche de faire tout le `# set initial through data` de l’autre embranchement aussi ici et d’avoir seulement dans le `if … else` la façon dont `self.regie` est initialisé.

si on est en update (=il y a une pk), alors qu'on a un formulaire initialisé avec les données du docket, on ne veut pas les écraser par quelque chose qui se trouve peut-être en GET param

si on est en update (=il y a une pk), alors qu'on a un formulaire initialisé avec les données du docket, on ne veut pas les écraser par quelque chose qui se trouve peut-être en GET param

Ah oui bien sûr, ce détail m’avait échappé :)

Ah oui bien sûr, ce détail m’avait échappé :)
super().__init__(*args, **kwargs)
self.fields['payment_types'].queryset = self.regie.paymenttype_set.all()
@ -908,7 +912,11 @@ class PaymentDocketForm(forms.ModelForm):
)
if filterset.form.is_valid():
payment_queryset = filterset.qs
payment_queryset.update(docket=self.instance)
with transaction.atomic():

Pas besoin de gérer une atomicité de ces deux update successifs ?

Pas besoin de gérer une atomicité de ces deux `update` successifs ?

ça serait pas mal oui, j'ajoute ça

ça serait pas mal oui, j'ajoute ça
Payment.objects.filter(regie=self.regie, docket=self.instance).exclude(
pk__in=payment_queryset
).update(docket=None)
payment_queryset.update(docket=self.instance)
return self.instance

View File

@ -80,4 +80,11 @@
{% endblock %}
{% block sidebar %}
{% if object.draft %}
<aside id="sidebar">
<h3>{% trans "Actions" %}</h3>
<a class="button button-paragraph" href="{% url 'lingo-manager-invoicing-regie-docket-edit' regie.pk object.pk %}">{% trans "Edit" %}</a>
</aside>
{% endif %}
{% endblock %}

View File

@ -1,17 +1,18 @@
{% extends "lingo/invoicing/manager_docket_payment_list.html" %}
{% extends "lingo/invoicing/manager_docket_list.html" %}
{% load gadjo i18n %}
{% block breadcrumb %}
{{ block.super }}
{% if form.instance.pk %}
<a href="{# url 'lingo-manager-invoicing-regie-docket-edit' regie_pk=regie.pk pk=object.pk #}">{% trans "Edit" %}</a>
<a href="{% url 'lingo-manager-invoicing-regie-docket-detail' regie_pk=regie.pk pk=form.instance.pk %}">{{ form.instance }}</a>
<a href="{% url 'lingo-manager-invoicing-regie-docket-edit' regie_pk=regie.pk pk=form.instance.pk %}">{% trans "Edit" %}</a>
{% else %}
<a href="{% url 'lingo-manager-invoicing-regie-docket-add' regie_pk=regie.pk %}">{% trans "New docket" %}</a>
{% endif %}
{% endblock %}
{% block appbar %}
{% if object.pk %}
{% if form.instance.pk %}
<h2>{% trans "Edit docket" %}</h2>
{% else %}
<h2>{% trans "New docket" %}</h2>
@ -24,7 +25,11 @@
{{ form|with_template }}
<div class="buttons">
<button class="submit-button">{% trans "Save" %}</button>
<a class="cancel" href="{% url 'lingo-manager-invoicing-regie-docket-payment-list' regie.pk %}">{% trans 'Cancel' %}</a>
{% if form.instance.pk %}
<a class="cancel" href="{% url 'lingo-manager-invoicing-regie-docket-detail' regie_pk=regie.pk pk=form.instance.pk %}">{% trans 'Cancel' %}</a>
{% else %}
<a class="cancel" href="{% url 'lingo-manager-invoicing-regie-docket-payment-list' regie.pk %}">{% trans 'Cancel' %}</a>
{% endif %}
</div>
</form>
{% endblock %}

View File

@ -228,6 +228,11 @@ urlpatterns = [
regie_views.regie_docket_detail,
name='lingo-manager-invoicing-regie-docket-detail',
),
path(
'regie/<int:regie_pk>/docket/<int:pk>/edit/',
regie_views.regie_docket_edit,
name='lingo-manager-invoicing-regie-docket-edit',
),
path(
'regie/<int:regie_pk>/docket/<int:pk>/payment-type/<int:payment_type_pk>/',
regie_views.regie_docket_payment_type_edit,

View File

@ -897,6 +897,29 @@ class RegieDocketDetailView(DetailView):
regie_docket_detail = RegieDocketDetailView.as_view()
class RegieDocketEditView(UpdateView):
template_name = 'lingo/invoicing/manager_docket_form.html'
model = PaymentDocket
form_class = PaymentDocketForm
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.filter(draft=True)
def get_context_data(self, **kwargs):
kwargs['regie'] = self.regie
return super().get_context_data(**kwargs)
def get_success_url(self):
return reverse('lingo-manager-invoicing-regie-docket-detail', args=[self.regie.pk, self.object.pk])
regie_docket_edit = RegieDocketEditView.as_view()
class RegieDocketPaymentTypeEditView(UpdateView):
template_name = 'lingo/invoicing/manager_docket_payment_type_form.html'
model = PaymentDocket

View File

@ -432,6 +432,128 @@ 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_edit(app, admin_user):
regie = Regie.objects.create(label='Foo')
PaymentType.create_defaults(regie)
other_docket = PaymentDocket.objects.create(regie=regie, date_end=now().date(), draft=False)
docket = PaymentDocket.objects.create(regie=regie, date_end=now().date(), draft=True)
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',
)
payment1.created_at = now() - datetime.timedelta(days=2)
payment1.set_number()
payment1.save()
payment2 = Payment.objects.create(
regie=regie,
amount=55,
payment_type=PaymentType.objects.get(regie=regie, slug='check'),
payer_external_id='payer:1',
payer_first_name='First1',
payer_last_name='Name1',
)
payment2.created_at = now() - datetime.timedelta(days=1)
payment2.set_number()
payment2.save()
payment3 = Payment.objects.create(
regie=regie,
amount=2,
payment_type=PaymentType.objects.get(regie=regie, slug='creditcard'),
payer_external_id='payer:3',
payer_first_name='First3',
payer_last_name='Name3',
)
payment3.created_at = now() - datetime.timedelta(days=1)
payment3.set_number()
payment3.save()
payment4 = Payment.objects.create(
regie=regie,
amount=2,
payment_type=PaymentType.objects.get(regie=regie, slug='check'),
payer_external_id='payer:3',
payer_first_name='First3',
payer_last_name='Name3',
)
payment4.set_number()
payment4.save()
payment5 = Payment.objects.create(
regie=regie,
amount=2,
payment_type=PaymentType.objects.get(regie=regie, slug='check'),
payer_external_id='payer:3',
payer_first_name='First3',
payer_last_name='Name3',
cancelled_at=now(),
)
payment5.set_number()
payment5.save()
payment6 = Payment.objects.create(
regie=regie,
amount=2,
payment_type=PaymentType.objects.get(regie=regie, slug='check'),
payer_external_id='payer:3',
payer_first_name='First3',
payer_last_name='Name3',
docket=other_docket,
)
payment6.set_number()
payment6.save()
app = login(app)
resp = app.get('/manage/invoicing/regie/%s/docket/%s/' % (regie.pk, docket.pk))
resp = resp.click('Edit')
resp.form['payment_types'] = [
PaymentType.objects.get(slug='cash').pk,
PaymentType.objects.get(slug='check').pk,
]
resp.form['date_end'] = now().date()
resp = resp.form.submit()
assert resp.location.endswith('/manage/invoicing/regie/%s/docket/%s/' % (regie.pk, docket.pk))
docket.refresh_from_db()
assert docket.draft is True
assert docket.date_end == now().date()
assert list(docket.payment_types.all()) == list(PaymentType.objects.filter(slug__in=['cash', 'check']))
assert list(docket.payment_set.all().order_by('-pk')) == [payment2, payment1]
resp = app.get('/manage/invoicing/regie/%s/docket/%s/edit/' % (regie.pk, docket.pk))
resp.form['payment_types'] = [p.pk for p in PaymentType.objects.all()]
resp.form['date_end'] = now().date() + datetime.timedelta(days=1)
resp = resp.form.submit()
assert resp.location.endswith('/manage/invoicing/regie/%s/docket/%s/' % (regie.pk, docket.pk))
docket.refresh_from_db()
assert docket.draft is True
assert docket.date_end == now().date() + datetime.timedelta(days=1)
assert list(docket.payment_types.all()) == list(PaymentType.objects.all())
assert list(docket.payment_set.all().order_by('-pk')) == [payment4, payment3, payment2, payment1]
resp = app.get('/manage/invoicing/regie/%s/docket/%s/edit/' % (regie.pk, docket.pk))
resp.form['payment_types'] = [
PaymentType.objects.get(slug='cash').pk,
PaymentType.objects.get(slug='check').pk,
]
resp = resp.form.submit()
assert resp.location.endswith('/manage/invoicing/regie/%s/docket/%s/' % (regie.pk, docket.pk))
docket.refresh_from_db()
assert docket.draft is True
assert docket.date_end == now().date() + datetime.timedelta(days=1)
assert list(docket.payment_types.all()) == list(PaymentType.objects.filter(slug__in=['cash', 'check']))
assert list(docket.payment_set.all().order_by('-pk')) == [payment4, payment2, payment1]
docket.draft = False
docket.save()
app.get('/manage/invoicing/regie/%s/docket/%s/edit/' % (regie.pk, docket.pk), status=404)
def test_regie_docket_payment_type_edit(app, admin_user):
regie = Regie.objects.create(label='Foo')
PaymentType.create_defaults(regie)