From a8d52d4c9da819587f165ef00aaef705d8fd40e5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Tue, 26 Jul 2022 15:55:17 +0200
Subject: [PATCH 07/14] pricing: billing date views (#67675)

---
 lingo/pricing/forms.py                        |  39 +++-
 ...ager_agenda_pricing_billing_date_form.html |  30 +++
 .../manager_agenda_pricing_detail.html        |  33 ++-
 lingo/pricing/urls.py                         |  15 ++
 lingo/pricing/views.py                        |  97 +++++++-
 tests/pricing/manager/test_agenda_pricing.py  | 218 +++++++++++++++++-
 6 files changed, 427 insertions(+), 5 deletions(-)
 create mode 100644 lingo/pricing/templates/lingo/pricing/manager_agenda_pricing_billing_date_form.html

diff --git a/lingo/pricing/forms.py b/lingo/pricing/forms.py
index 0d6823c..c3379e4 100644
--- a/lingo/pricing/forms.py
+++ b/lingo/pricing/forms.py
@@ -24,7 +24,7 @@ from django.utils.translation import ugettext_lazy as _
 
 from lingo.agendas.chrono import ChronoError, get_event, get_subscriptions
 from lingo.agendas.models import Agenda, CheckType
-from lingo.pricing.models import AgendaPricing, Criteria, CriteriaCategory, PricingError
+from lingo.pricing.models import AgendaPricing, BillingDate, Criteria, CriteriaCategory, PricingError
 
 
 class ExportForm(forms.Form):
@@ -216,6 +216,25 @@ class AgendaPricingForm(NewAgendaPricingForm):
                             None,
                             _('Agenda "%s" has already a pricing overlapping this period.') % agenda.label,
                         )
+            if (
+                old_flat_fee_schedule != new_flat_fee_schedule
+                and new_flat_fee_schedule is False
+                and self.instance.billingdates.exists()
+            ):
+                self.add_error(
+                    'flat_fee_schedule',
+                    _('Some billing dates are are defined for this pricing; please delete them first.'),
+                )
+            if (
+                old_flat_fee_schedule == new_flat_fee_schedule
+                and new_flat_fee_schedule is True
+                and (old_date_start != new_date_start or old_date_end != new_date_end)
+            ):
+                if (
+                    self.instance.billingdates.filter(date_start__lt=new_date_start).exists()
+                    or self.instance.billingdates.filter(date_start__gte=new_date_end).exists()
+                ):
+                    self.add_error(None, _('Some billing dates are outside the pricing period.'))
 
         return cleaned_data
 
@@ -241,6 +260,24 @@ class AgendaPricingAgendaAddForm(forms.Form):
         return agenda
 
 
+class AgendaPricingBillingDateForm(forms.ModelForm):
+    class Meta:
+        model = BillingDate
+        fields = ['date_start', 'label']
+        widgets = {
+            'date_start': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
+        }
+
+    def clean_date_start(self):
+        date_start = self.cleaned_data['date_start']
+        if (
+            date_start < self.instance.agenda_pricing.date_start
+            or date_start >= self.instance.agenda_pricing.date_end
+        ):
+            raise forms.ValidationError(_('The billing start date must be within the period of the pricing.'))
+        return date_start
+
+
 class PricingMatrixForm(forms.Form):
     def __init__(self, *args, **kwargs):
         matrix = kwargs.pop('matrix')
diff --git a/lingo/pricing/templates/lingo/pricing/manager_agenda_pricing_billing_date_form.html b/lingo/pricing/templates/lingo/pricing/manager_agenda_pricing_billing_date_form.html
new file mode 100644
index 0000000..4fb6f60
--- /dev/null
+++ b/lingo/pricing/templates/lingo/pricing/manager_agenda_pricing_billing_date_form.html
@@ -0,0 +1,30 @@
+{% extends "lingo/pricing/manager_agenda_pricing_detail.html" %}
+{% load i18n %}
+
+{% block breadcrumb %}
+{{ block.super }}
+{% if form.instance.pk %}
+<a href="{% url 'lingo-manager-agenda-pricing-billing-date-edit' object.pk form.instance.agenda_pricing.pk %}">{{ form.instance }}</a>
+{% else %}
+<a href="{% url 'lingo-manager-agenda-pricing-billing-date-add' object.pk %}">{% trans "New billing date" %}</a>
+{% endif %}
+{% endblock %}
+
+{% block appbar %}
+{% if form.instance.pk %}
+<h2>{{ form.instance.agenda_pricing }} - {% trans "Edit billing date" %}</h2>
+{% else %}
+<h2>{{ form.instance.agenda_pricing }} - {% trans "New billing date" %}</h2>
+{% endif %}
+{% endblock %}
+
+{% block content %}
+<form method="post" enctype="multipart/form-data">
+  {% csrf_token %}
+  {{ form.as_p }}
+  <div class="buttons">
+    <button class="submit-button">{% trans "Save" %}</button>
+    <a class="cancel" href="{% url 'lingo-manager-agenda-pricing-detail' object.pk %}">{% trans 'Cancel' %}</a>
+  </div>
+</form>
+{% endblock %}
diff --git a/lingo/pricing/templates/lingo/pricing/manager_agenda_pricing_detail.html b/lingo/pricing/templates/lingo/pricing/manager_agenda_pricing_detail.html
index 35bed3d..1feff4b 100644
--- a/lingo/pricing/templates/lingo/pricing/manager_agenda_pricing_detail.html
+++ b/lingo/pricing/templates/lingo/pricing/manager_agenda_pricing_detail.html
@@ -31,6 +31,9 @@
     <button aria-controls="panel-agendas" aria-selected="false" id="tab-agendas" role="tab" tabindex="0">{% trans "Agendas" %}</button>
     {% endif %}
     <button aria-controls="panel-debug" aria-selected="false" id="tab-debug" role="tab" tabindex="0">{% trans "Test tool" %}</button>
+    {% if object.flat_fee_schedule %}
+    <button aria-controls="panel-billing-dates" aria-selected="false" id="tab-billing-dates" role="tab" tabindex="0">{% trans "Billing dates" %}</button>
+    {% endif %}
     {% for matrix in iter_matrix %}
     <button aria-controls="panel-matrix-{{ matrix.criteria.slug }}" aria-selected="false" id="tab-matrix-{{ matrix.criteria.slug }}" role="tab" tabindex="-1">{% trans "Pricings" context 'amount' %}{% if matrix.criteria %} - {{ matrix.criteria.label }}{% endif %}</button>
     {% empty %}
@@ -119,10 +122,36 @@
             <pre>{{ pricing_data|pprint }}</pre>
         </div>
       </div>
-  {% endwith %}
-  {% endif %}
+      {% endwith %}
+      {% endif %}
     </div>
 
+    {% if object.flat_fee_schedule %}
+    <div aria-labelledby="tab-billing-dates" hidden id="panel-billing-dates" role="tabpanel" tabindex="0">
+      {% if billing_dates %}
+      <ul class="objects-list single-links">
+        {% for billing_date in billing_dates %}
+        <li>
+          <a rel="popup" href="{% url 'lingo-manager-agenda-pricing-billing-date-edit' object.pk billing_date.pk %}">
+            {{ billing_date.date_start|date:'d/m/Y' }} ({{ billing_date.label }})
+          </a>
+          <a class="delete" rel="popup" href="{% url 'lingo-manager-agenda-pricing-billing-date-delete' object.pk billing_date.pk %}">{% trans "remove"%}</a>
+        </li>
+        {% endfor %}
+      </ul>
+      {% else %}
+      <div class="big-msg-info">
+        {% blocktrans with date_start=object.date_start|date:'d/m/Y' %}
+        No billing dates. The start date of the pricing ({{ date_start }}) is used as the only available billing date.
+        {% endblocktrans %}
+      </div>
+      {% endif %}
+      <div class="panel--buttons">
+        <a class="pk-button" rel="popup" href="{% url 'lingo-manager-agenda-pricing-billing-date-add' object.pk %}">{% trans "New billing date" %}</a>
+      </div>
+    </div>
+    {% endif %}
+
     {% for matrix in iter_matrix %}
     <div aria-labelledby="tab-matrix-{{ matrix.criteria.slug }}" hidden="" id="panel-matrix-{{ matrix.criteria.slug }}" role="tabpanel" tabindex="0">
       <table class="main pricing-matrix-{{ matrix.criteria.slug }}">
diff --git a/lingo/pricing/urls.py b/lingo/pricing/urls.py
index 985862c..f10b570 100644
--- a/lingo/pricing/urls.py
+++ b/lingo/pricing/urls.py
@@ -198,6 +198,21 @@ urlpatterns = [
         views.agenda_pricing_agenda_delete,
         name='lingo-manager-agenda-pricing-agenda-delete',
     ),
+    url(
+        r'^agenda-pricing/(?P<pk>\d+)/billing-date/add/$',
+        views.agenda_pricing_billing_date_add,
+        name='lingo-manager-agenda-pricing-billing-date-add',
+    ),
+    url(
+        r'^agenda-pricing/(?P<pk>\d+)/billing-date/(?P<billing_date_pk>\d+)/$',
+        views.agenda_pricing_billing_date_edit,
+        name='lingo-manager-agenda-pricing-billing-date-edit',
+    ),
+    url(
+        r'^agenda-pricing/(?P<pk>\d+)/billing-date/(?P<billing_date_pk>\d+)/delete/$',
+        views.agenda_pricing_billing_date_delete,
+        name='lingo-manager-agenda-pricing-billing-date-delete',
+    ),
     url(
         r'^agenda-pricing/(?P<pk>\d+)/matrix/edit/$',
         views.agenda_pricing_matrix_edit,
diff --git a/lingo/pricing/views.py b/lingo/pricing/views.py
index 4166d5d..b111554 100644
--- a/lingo/pricing/views.py
+++ b/lingo/pricing/views.py
@@ -45,6 +45,7 @@ from lingo.agendas.models import Agenda, CheckType, CheckTypeGroup
 from lingo.agendas.views import AgendaMixin
 from lingo.pricing.forms import (
     AgendaPricingAgendaAddForm,
+    AgendaPricingBillingDateForm,
     AgendaPricingForm,
     CheckTypeForm,
     CriteriaForm,
@@ -60,7 +61,14 @@ from lingo.pricing.forms import (
     PricingTestToolForm,
     PricingVariableFormSet,
 )
-from lingo.pricing.models import AgendaPricing, Criteria, CriteriaCategory, Pricing, PricingCriteriaCategory
+from lingo.pricing.models import (
+    AgendaPricing,
+    BillingDate,
+    Criteria,
+    CriteriaCategory,
+    Pricing,
+    PricingCriteriaCategory,
+)
 from lingo.pricing.utils import export_site, import_site
 from lingo.utils.misc import AgendaImportError
 
@@ -780,6 +788,7 @@ class AgendaPricingDetailView(DetailView):
         if self.request.GET:
             form.is_valid()
         kwargs['test_tool_form'] = form
+        kwargs['billing_dates'] = self.object.billingdates.order_by('date_start')
         return super().get_context_data(**kwargs)
 
 
@@ -892,6 +901,92 @@ class AgendaPricingAgendaDeleteView(DeleteView):
 agenda_pricing_agenda_delete = AgendaPricingAgendaDeleteView.as_view()
 
 
+class AgendaPricingBillingDateAddView(FormView):
+    template_name = 'lingo/pricing/manager_agenda_pricing_billing_date_form.html'
+    model = AgendaPricing
+    form_class = AgendaPricingBillingDateForm
+
+    def dispatch(self, request, *args, **kwargs):
+        self.object = get_object_or_404(AgendaPricing, pk=kwargs['pk'], flat_fee_schedule=True)
+        return super().dispatch(request, *args, **kwargs)
+
+    def get_form_kwargs(self):
+        kwargs = super().get_form_kwargs()
+        kwargs['instance'] = BillingDate(agenda_pricing=self.object)
+        return kwargs
+
+    def get_context_data(self, **kwargs):
+        kwargs['object'] = self.object
+        return super().get_context_data(**kwargs)
+
+    def form_valid(self, form):
+        form.save()
+        return super().form_valid(form)
+
+    def get_success_url(self):
+        return '%s#open:billing-dates' % reverse('lingo-manager-agenda-pricing-detail', args=[self.object.pk])
+
+
+agenda_pricing_billing_date_add = AgendaPricingBillingDateAddView.as_view()
+
+
+class AgendaPricingBillingDateEditView(FormView):
+    template_name = 'lingo/pricing/manager_agenda_pricing_billing_date_form.html'
+    model = AgendaPricing
+    form_class = AgendaPricingBillingDateForm
+
+    def dispatch(self, request, *args, **kwargs):
+        self.agenda_pricing = get_object_or_404(AgendaPricing, pk=kwargs['pk'], flat_fee_schedule=True)
+        self.object = get_object_or_404(self.agenda_pricing.billingdates, pk=kwargs['billing_date_pk'])
+        return super().dispatch(request, *args, **kwargs)
+
+    def get_form_kwargs(self):
+        kwargs = super().get_form_kwargs()
+        kwargs['instance'] = self.object
+        return kwargs
+
+    def get_context_data(self, **kwargs):
+        kwargs['object'] = self.agenda_pricing
+        return super().get_context_data(**kwargs)
+
+    def form_valid(self, form):
+        form.save()
+        return super().form_valid(form)
+
+    def get_success_url(self):
+        return '%s#open:billing-dates' % reverse(
+            'lingo-manager-agenda-pricing-detail', args=[self.agenda_pricing.pk]
+        )
+
+
+agenda_pricing_billing_date_edit = AgendaPricingBillingDateEditView.as_view()
+
+
+class AgendaPricingBillingDateDeleteView(DeleteView):
+    template_name = 'lingo/manager_confirm_delete.html'
+    model = BillingDate
+    pk_url_kwarg = 'billing_date_pk'
+
+    def dispatch(self, request, *args, **kwargs):
+        self.agenda_pricing = get_object_or_404(AgendaPricing, pk=kwargs['pk'], subscription_required=True)
+        return super().dispatch(request, *args, **kwargs)
+
+    def get_queryset(self):
+        return self.agenda_pricing.billingdates.all()
+
+    def delete(self, request, *args, **kwargs):
+        self.get_object().delete()
+        return HttpResponseRedirect(self.get_success_url())
+
+    def get_success_url(self):
+        return '%s#open:billing-dates' % reverse(
+            'lingo-manager-agenda-pricing-detail', args=[self.agenda_pricing.pk]
+        )
+
+
+agenda_pricing_billing_date_delete = AgendaPricingBillingDateDeleteView.as_view()
+
+
 class AgendaPricingMatrixEdit(FormView):
     template_name = 'lingo/pricing/manager_agenda_pricing_matrix_form.html'
 
diff --git a/tests/pricing/manager/test_agenda_pricing.py b/tests/pricing/manager/test_agenda_pricing.py
index b48e73f..02c9c1c 100644
--- a/tests/pricing/manager/test_agenda_pricing.py
+++ b/tests/pricing/manager/test_agenda_pricing.py
@@ -7,7 +7,7 @@ from django.utils.timezone import now
 
 from lingo.agendas.chrono import ChronoError
 from lingo.agendas.models import Agenda, CheckType, CheckTypeGroup
-from lingo.pricing.models import AgendaPricing, Criteria, CriteriaCategory, Pricing, PricingError
+from lingo.pricing.models import AgendaPricing, BillingDate, Criteria, CriteriaCategory, Pricing, PricingError
 from tests.utils import login
 
 pytestmark = pytest.mark.django_db
@@ -124,6 +124,19 @@ def test_edit_agenda_pricing(app, admin_user):
     resp = resp.form.submit()
     assert resp.location.endswith('/manage/pricing/agenda-pricing/%s/' % agenda_pricing.pk)
 
+    agenda_pricing.flat_fee_schedule = True
+    agenda_pricing.save()
+    agenda_pricing.billingdates.create(
+        date_start=datetime.date(year=2021, month=9, day=1),
+        label='Foo',
+    )
+    resp = app.get('/manage/pricing/agenda-pricing/%s/edit/' % agenda_pricing.pk)
+    resp.form['flat_fee_schedule'] = False
+    resp = resp.form.submit()
+    assert resp.context['form'].errors['flat_fee_schedule'] == [
+        'Some billing dates are are defined for this pricing; please delete them first.'
+    ]
+
 
 def test_edit_agenda_pricing_overlapping_flat_fee_schedule(app, admin_user):
     agenda1 = Agenda.objects.create(label='Foo bar 1')
@@ -263,6 +276,80 @@ def test_edit_agenda_pricing_overlapping_date_end(app, admin_user):
     resp.form.submit().follow()
 
 
+def test_edit_agenda_pricing_billing_date_start(app, admin_user):
+    pricing = Pricing.objects.create(label='Model')
+    agenda_pricing = AgendaPricing.objects.create(
+        label='Foo Bar',
+        pricing=pricing,
+        date_start=datetime.date(year=2021, month=9, day=1),
+        date_end=datetime.date(year=2022, month=9, day=1),
+        flat_fee_schedule=True,
+    )
+    agenda_pricing.billingdates.create(
+        date_start=datetime.date(year=2021, month=9, day=1),
+        label='Foo',
+    )
+
+    app = login(app)
+    resp = app.get('/manage/pricing/agenda-pricing/%s/edit/' % agenda_pricing.pk)
+    # ok, date_start has not changed
+    resp.form.submit().follow()
+
+    resp = app.get('/manage/pricing/agenda-pricing/%s/edit/' % agenda_pricing.pk)
+    # ok, billing date inside period
+    resp.form['date_start'] = '2021-08-31'
+    resp.form.submit().follow()
+
+    resp = app.get('/manage/pricing/agenda-pricing/%s/edit/' % agenda_pricing.pk)
+    resp.form['date_start'] = '2021-09-02'
+    resp = resp.form.submit()
+    assert resp.context['form'].non_field_errors() == ['Some billing dates are outside the pricing period.']
+
+    # but don't check billing dates if not flat_fee_schedule
+    agenda_pricing.flat_fee_schedule = False
+    agenda_pricing.save()
+    # ok
+    resp = app.get('/manage/pricing/agenda-pricing/%s/edit/' % agenda_pricing.pk)
+    resp.form.submit().follow()
+
+
+def test_edit_agenda_pricing_billing_date_end(app, admin_user):
+    pricing = Pricing.objects.create(label='Model')
+    agenda_pricing = AgendaPricing.objects.create(
+        label='Foo Bar',
+        pricing=pricing,
+        date_start=datetime.date(year=2021, month=9, day=1),
+        date_end=datetime.date(year=2022, month=9, day=1),
+        flat_fee_schedule=True,
+    )
+    agenda_pricing.billingdates.create(
+        date_start=datetime.date(year=2022, month=9, day=1),
+        label='Foo',
+    )
+
+    app = login(app)
+    resp = app.get('/manage/pricing/agenda-pricing/%s/edit/' % agenda_pricing.pk)
+    # ok, date_end has not changed
+    resp.form.submit().follow()
+
+    resp = app.get('/manage/pricing/agenda-pricing/%s/edit/' % agenda_pricing.pk)
+    # ok, billing date inside period
+    resp.form['date_end'] = '2022-09-02'
+    resp.form.submit().follow()
+
+    resp = app.get('/manage/pricing/agenda-pricing/%s/edit/' % agenda_pricing.pk)
+    resp.form['date_end'] = '2022-09-01'
+    resp = resp.form.submit()
+    assert resp.context['form'].non_field_errors() == ['Some billing dates are outside the pricing period.']
+
+    # but don't check billing dates if not flat_fee_schedule
+    agenda_pricing.flat_fee_schedule = False
+    agenda_pricing.save()
+    # ok
+    resp = app.get('/manage/pricing/agenda-pricing/%s/edit/' % agenda_pricing.pk)
+    resp.form.submit().follow()
+
+
 def test_detail_agenda_pricing(app, admin_user):
     pricing = Pricing.objects.create(label='Model')
     agenda_pricing = AgendaPricing.objects.create(
@@ -402,6 +489,135 @@ def test_agenda_pricing_delete_agenda(app, admin_user):
     )
 
 
+def test_agenda_pricing_add_billing_date(app, admin_user):
+    pricing = Pricing.objects.create(label='Model')
+    agenda_pricing = AgendaPricing.objects.create(
+        pricing=pricing,
+        date_start=datetime.date(year=2021, month=9, day=1),
+        date_end=datetime.date(year=2022, month=9, day=1),
+        flat_fee_schedule=True,
+    )
+
+    app = login(app)
+    resp = app.get('/manage/pricing/agenda-pricing/%s/' % agenda_pricing.pk)
+    resp = resp.click(href='/manage/pricing/agenda-pricing/%s/billing-date/add/' % agenda_pricing.pk)
+    resp.form['date_start'] = '2021-08-31'
+    resp.form['label'] = 'Foo'
+    resp = resp.form.submit()
+    assert resp.context['form'].errors['date_start'] == [
+        'The billing start date must be within the period of the pricing.'
+    ]
+    resp.form['date_start'] = '2022-09-01'
+    resp = resp.form.submit()
+    assert resp.context['form'].errors['date_start'] == [
+        'The billing start date must be within the period of the pricing.'
+    ]
+    resp.form['date_start'] = '2022-08-31'
+    resp = resp.form.submit()
+    assert resp.location.endswith('/manage/pricing/agenda-pricing/%s/#open:billing-dates' % agenda_pricing.pk)
+
+    assert agenda_pricing.billingdates.count() == 1
+    billing_date = BillingDate.objects.latest('pk')
+    assert billing_date.date_start == datetime.date(2022, 8, 31)
+    assert billing_date.label == 'Foo'
+
+    agenda_pricing.flat_fee_schedule = False
+    agenda_pricing.save()
+    app.get('/manage/pricing/agenda-pricing/%s/billing-date/add/' % agenda_pricing.pk, status=404)
+
+
+def test_agenda_pricing_edit_billing_date(app, admin_user):
+    pricing = Pricing.objects.create(label='Model')
+    agenda_pricing = AgendaPricing.objects.create(
+        pricing=pricing,
+        date_start=datetime.date(year=2021, month=9, day=1),
+        date_end=datetime.date(year=2022, month=9, day=1),
+        flat_fee_schedule=True,
+    )
+    billing_date = agenda_pricing.billingdates.create(
+        date_start=datetime.date(year=2021, month=8, day=31),
+        label='Foo',
+    )
+
+    app = login(app)
+    resp = app.get('/manage/pricing/agenda-pricing/%s/' % agenda_pricing.pk)
+    resp = resp.click(
+        href=r'/manage/pricing/agenda-pricing/%s/billing-date/%s/$' % (agenda_pricing.pk, billing_date.pk)
+    )
+    resp.form['label'] = 'Bar'
+    resp = resp.form.submit()
+    assert resp.context['form'].errors['date_start'] == [
+        'The billing start date must be within the period of the pricing.'
+    ]
+    resp.form['date_start'] = '2022-09-01'
+    resp = resp.form.submit()
+    assert resp.context['form'].errors['date_start'] == [
+        'The billing start date must be within the period of the pricing.'
+    ]
+    resp.form['date_start'] = '2022-08-31'
+    resp = resp.form.submit()
+    assert resp.location.endswith('/manage/pricing/agenda-pricing/%s/#open:billing-dates' % agenda_pricing.pk)
+
+    assert agenda_pricing.billingdates.count() == 1
+    billing_date.refresh_from_db()
+    assert billing_date.date_start == datetime.date(2022, 8, 31)
+    assert billing_date.label == 'Bar'
+
+    agenda_pricing.flat_fee_schedule = False
+    agenda_pricing.save()
+    app.get(
+        '/manage/pricing/agenda-pricing/%s/billing-date/%s/' % (agenda_pricing.pk, billing_date.pk),
+        status=404,
+    )
+
+
+def test_agenda_pricing_delete_billing_date(app, admin_user):
+    pricing = Pricing.objects.create(label='Model')
+    agenda_pricing = AgendaPricing.objects.create(
+        pricing=pricing,
+        date_start=datetime.date(year=2021, month=9, day=1),
+        date_end=datetime.date(year=2022, month=9, day=1),
+        flat_fee_schedule=True,
+    )
+    billing_date1 = agenda_pricing.billingdates.create(
+        date_start=datetime.date(year=2021, month=9, day=1),
+        label='Foo',
+    )
+    billing_date2 = agenda_pricing.billingdates.create(
+        date_start=datetime.date(year=2021, month=9, day=1),
+        label='Bar',
+    )
+
+    app = login(app)
+    resp = app.get('/manage/pricing/agenda-pricing/%s/' % agenda_pricing.pk)
+    resp = resp.click(
+        href='/manage/pricing/agenda-pricing/%s/billing-date/%s/delete'
+        % (agenda_pricing.pk, billing_date1.pk)
+    )
+    resp = resp.form.submit()
+    assert resp.location.endswith('/manage/pricing/agenda-pricing/%s/#open:billing-dates' % agenda_pricing.pk)
+
+    assert agenda_pricing.billingdates.count() == 1
+
+    agenda_pricing.flat_fee_schedule = False
+    agenda_pricing.save()
+    app.get(
+        '/manage/pricing/agenda-pricing/%s/billing-date/%s/' % (agenda_pricing.pk, billing_date2.pk),
+        status=404,
+    )
+
+    agenda_pricing2 = AgendaPricing.objects.create(
+        pricing=pricing,
+        date_start=datetime.date(year=2021, month=9, day=1),
+        date_end=datetime.date(year=2022, month=9, day=1),
+    )
+    app.get(
+        '/manage/pricing/agenda-pricing/%s/billing-date/%s/' % (agenda_pricing2.pk, billing_date2.pk),
+        status=404,
+    )
+    app.get('/manage/pricing/agenda-pricing/%s/billing-date/%s/' % (0, billing_date2.pk), status=404)
+
+
 def test_detail_agenda_pricing_3_categories(app, admin_user):
     category1 = CriteriaCategory.objects.create(label='Cat 1')
     Criteria.objects.create(label='Crit 1-1', slug='crit-1-1', category=category1, order=1)
-- 
2.35.1

