From 7ee7625f86d7342feadfa9a41062a93e35e26822 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Fri, 3 Jun 2022 14:23:55 +0200
Subject: [PATCH] pricing: empty app (#65976)

---
 .../migrations/0127_remove_pricing_models.py  |   23 +
 chrono/agendas/models.py                      |   27 -
 chrono/manager/forms.py                       |   31 +-
 chrono/manager/static/css/style.scss          |   36 -
 chrono/manager/static/js/chrono.manager.js    |   33 -
 .../manager_events_agenda_settings.html       |   25 -
 .../templates/chrono/manager_home.html        |    3 -
 chrono/manager/utils.py                       |   15 -
 chrono/manager/views.py                       |   63 +-
 chrono/pricing/forms.py                       |  128 --
 .../migrations/0004_remove_pricing_models.py  |   55 +
 chrono/pricing/models.py                      |  592 ------
 .../manager_agenda_pricing_detail.html        |   61 -
 .../pricing/manager_agenda_pricing_form.html  |   35 -
 .../manager_agenda_pricing_matrix_form.html   |   58 -
 .../manager_criteria_category_form.html       |   31 -
 .../chrono/pricing/manager_criteria_form.html |   31 -
 .../chrono/pricing/manager_criteria_list.html |   58 -
 ...anager_pricing_criteria_category_form.html |   31 -
 .../pricing/manager_pricing_detail.html       |   74 -
 .../manager_pricing_duplicate_form.html       |   22 -
 .../chrono/pricing/manager_pricing_form.html  |   31 -
 .../chrono/pricing/manager_pricing_list.html  |   39 -
 .../manager_pricing_variable_form.html        |   44 -
 chrono/pricing/urls.py                        |  149 --
 chrono/pricing/views.py                       |  667 -------
 chrono/settings.py                            |    3 -
 chrono/urls.py                                |    2 -
 tests/manager/test_all.py                     |   51 -
 tests/manager/test_check_type.py              |   74 -
 tests/manager/test_import_export.py           |   15 +-
 tests/pricing/__init__.py                     |    0
 tests/pricing/conftest.py                     |   36 -
 tests/pricing/test_manager.py                 | 1630 -----------------
 tests/pricing/test_models.py                  | 1477 ---------------
 tests/settings.py                             |    1 -
 tests/test_import_export.py                   |  281 ---
 37 files changed, 86 insertions(+), 5846 deletions(-)
 create mode 100644 chrono/agendas/migrations/0127_remove_pricing_models.py
 delete mode 100644 chrono/pricing/forms.py
 create mode 100644 chrono/pricing/migrations/0004_remove_pricing_models.py
 delete mode 100644 chrono/pricing/templates/chrono/pricing/manager_agenda_pricing_detail.html
 delete mode 100644 chrono/pricing/templates/chrono/pricing/manager_agenda_pricing_form.html
 delete mode 100644 chrono/pricing/templates/chrono/pricing/manager_agenda_pricing_matrix_form.html
 delete mode 100644 chrono/pricing/templates/chrono/pricing/manager_criteria_category_form.html
 delete mode 100644 chrono/pricing/templates/chrono/pricing/manager_criteria_form.html
 delete mode 100644 chrono/pricing/templates/chrono/pricing/manager_criteria_list.html
 delete mode 100644 chrono/pricing/templates/chrono/pricing/manager_pricing_criteria_category_form.html
 delete mode 100644 chrono/pricing/templates/chrono/pricing/manager_pricing_detail.html
 delete mode 100644 chrono/pricing/templates/chrono/pricing/manager_pricing_duplicate_form.html
 delete mode 100644 chrono/pricing/templates/chrono/pricing/manager_pricing_form.html
 delete mode 100644 chrono/pricing/templates/chrono/pricing/manager_pricing_list.html
 delete mode 100644 chrono/pricing/templates/chrono/pricing/manager_pricing_variable_form.html
 delete mode 100644 chrono/pricing/urls.py
 delete mode 100644 chrono/pricing/views.py
 delete mode 100644 tests/pricing/__init__.py
 delete mode 100644 tests/pricing/conftest.py
 delete mode 100644 tests/pricing/test_manager.py
 delete mode 100644 tests/pricing/test_models.py

diff --git a/chrono/agendas/migrations/0127_remove_pricing_models.py b/chrono/agendas/migrations/0127_remove_pricing_models.py
new file mode 100644
index 00000000..65164596
--- /dev/null
+++ b/chrono/agendas/migrations/0127_remove_pricing_models.py
@@ -0,0 +1,23 @@
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('agendas', '0126_pricing'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='agenda',
+            name='pricings',
+        ),
+        migrations.RemoveField(
+            model_name='checktype',
+            name='pricing',
+        ),
+        migrations.RemoveField(
+            model_name='checktype',
+            name='pricing_rate',
+        ),
+    ]
diff --git a/chrono/agendas/models.py b/chrono/agendas/models.py
index db39c9d6..53f1b008 100644
--- a/chrono/agendas/models.py
+++ b/chrono/agendas/models.py
@@ -251,11 +251,6 @@ class Agenda(models.Model):
         null=True,
         blank=True,
     )
-    pricings = models.ManyToManyField(
-        'pricing.Pricing',
-        related_name='agendas',
-        through='pricing.AgendaPricing',
-    )
 
     class Meta:
         ordering = ['label']
@@ -404,7 +399,6 @@ class Agenda(models.Model):
             agenda['event_display_template'] = self.event_display_template
             agenda['mark_event_checked_auto'] = self.mark_event_checked_auto
             agenda['events_type'] = self.events_type.slug if self.events_type else None
-            agenda['pricings'] = [x.export_json() for x in self.agendapricing_set.all()]
         elif self.kind == 'meetings':
             agenda['meetingtypes'] = [x.export_json() for x in self.meetingtype_set.filter(deleted=False)]
             agenda['desks'] = [desk.export_json() for desk in self.desk_set.all()]
@@ -423,7 +417,6 @@ class Agenda(models.Model):
             events = data.pop('events')
             notifications_settings = data.pop('notifications_settings', None)
             exceptions_desk = data.pop('exceptions_desk', None)
-            pricings = data.pop('pricings', None) or []
         elif data['kind'] == 'meetings':
             meetingtypes = data.pop('meetingtypes')
             desks = data.pop('desks')
@@ -455,14 +448,6 @@ class Agenda(models.Model):
                 data['events_type'] = EventsType.objects.get(slug=data['events_type'])
             except EventsType.DoesNotExist:
                 raise AgendaImportError(_('Missing "%s" events type') % data['events_type'])
-        if data['kind'] == 'events' and pricings:
-            from chrono.pricing.models import Pricing
-
-            for pricing_data in pricings:
-                try:
-                    pricing_data['pricing'] = Pricing.objects.get(slug=pricing_data['pricing'])
-                except Pricing.DoesNotExist:
-                    raise AgendaImportError(_('Missing "%s" pricing model') % pricing_data['pricing'])
         agenda, created = cls.objects.update_or_create(slug=data['slug'], defaults=data)
         if overwrite:
             AgendaReminderSettings.objects.filter(agenda=agenda).delete()
@@ -473,18 +458,12 @@ class Agenda(models.Model):
             if overwrite:
                 Event.objects.filter(agenda=agenda).delete()
                 AgendaNotificationsSettings.objects.filter(agenda=agenda).delete()
-                agenda.agendapricing_set.all().delete()
             for event_data in events:
                 event_data['agenda'] = agenda
                 Event.import_json(event_data)
             if notifications_settings:
                 notifications_settings['agenda'] = agenda
                 AgendaNotificationsSettings.import_json(notifications_settings)
-            for pricing_data in pricings:
-                from chrono.pricing.models import AgendaPricing
-
-                pricing_data['agenda'] = agenda
-                AgendaPricing.import_json(pricing_data)
             if exceptions_desk:
                 exceptions_desk['agenda'] = agenda
                 Desk.import_json(exceptions_desk)
@@ -3129,12 +3108,6 @@ class CheckType(models.Model):
         choices=[('absence', _('Absence')), ('presence', _('Presence'))],
         default='absence',
     )
-    pricing = models.DecimalField(
-        _('Pricing'), max_digits=5, decimal_places=2, help_text=_('Fixed pricing'), blank=True, null=True
-    )
-    pricing_rate = models.PositiveIntegerField(
-        _('Pricing rate'), help_text=_('Percentage rate'), blank=True, null=True
-    )
     disabled = models.BooleanField(_('Disabled'), default=False)
     objects = CheckTypeManager()
 
diff --git a/chrono/manager/forms.py b/chrono/manager/forms.py
index c1b7669d..25068a8b 100644
--- a/chrono/manager/forms.py
+++ b/chrono/manager/forms.py
@@ -69,27 +69,10 @@ from . import widgets
 from .widgets import SplitDateTimeField, WeekdaysWidget
 
 
-class NewCheckTypeForm(forms.ModelForm):
+class CheckTypeForm(forms.ModelForm):
     class Meta:
         model = CheckType
-        fields = ['label', 'kind', 'pricing', 'pricing_rate']
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        if not settings.CHRONO_ENABLE_PRICING:
-            del self.fields['pricing']
-            del self.fields['pricing_rate']
-
-    def clean(self):
-        super().clean()
-        if self.cleaned_data.get('pricing') is not None and self.cleaned_data.get('pricing_rate') is not None:
-            raise ValidationError(_('Please choose between pricing and pricing rate.'))
-
-
-class CheckTypeForm(NewCheckTypeForm):
-    class Meta:
-        model = CheckType
-        fields = ['label', 'slug', 'pricing', 'pricing_rate', 'disabled']
+        fields = ['label', 'slug', 'disabled']
 
     def clean_slug(self):
         slug = self.cleaned_data['slug']
@@ -1425,16 +1408,6 @@ class AgendasExportForm(forms.Form):
     categories = forms.BooleanField(label=_('Categories'), required=False, initial=True)
     check_type_groups = forms.BooleanField(label=_('Check type groups'), required=False, initial=True)
     events_types = forms.BooleanField(label=_('Events types'), required=False, initial=True)
-    pricing_categories = forms.BooleanField(
-        label=_('Pricing criteria categories'), required=False, initial=True
-    )
-    pricing_models = forms.BooleanField(label=_('Pricing models'), required=False, initial=True)
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        if not settings.CHRONO_ENABLE_PRICING:
-            del self.fields['pricing_categories']
-            del self.fields['pricing_models']
 
 
 class SharedCustodyRuleForm(forms.ModelForm):
diff --git a/chrono/manager/static/css/style.scss b/chrono/manager/static/css/style.scss
index 2151ce29..0624a44c 100644
--- a/chrono/manager/static/css/style.scss
+++ b/chrono/manager/static/css/style.scss
@@ -522,39 +522,3 @@ table.timesheet {
 .page_break {
 	height: 20px;
 }
-
-div.paragraph {
-	background: white;
-	box-sizing: border-box;
-	border: 1px solid #386ede;
-	border-radius: 3px;
-	max-width: 100%;
-	padding: 5px 15px;
-	margin-bottom: 1rem;
-	h4 {
-		margin-top: 5px;
-		border-bottom: none;
-	}
-}
-
-.sortable {
-	span.handle {
-		cursor: move;
-		display: inline-block;
-		padding: 0.5ex;
-		text-align: center;
-		width: 2em;
-		height: 100%;
-		box-sizing: border-box;
-        font-weight: normal;
-	}
-}
-
-ul.objects-list.sortable {
-	li {
-		position: relative;
-		& > a {
-			display: inline-block;
-		}
-	}
-}
diff --git a/chrono/manager/static/js/chrono.manager.js b/chrono/manager/static/js/chrono.manager.js
index 78ddf600..97d87a18 100644
--- a/chrono/manager/static/js/chrono.manager.js
+++ b/chrono/manager/static/js/chrono.manager.js
@@ -48,37 +48,4 @@ $(function() {
       total_form.val(form_num + 1);
     })
   }
-
-  $(document).on('click', '#add-pricing-variable-form', function() {
-    if (typeof property_forms === "undefined") {var property_forms = $('.pricing-variable-form');}
-    if (typeof total_forms === "undefined") {var total_form = $('#id_form-TOTAL_FORMS');}
-    if (typeof form_num === "undefined") {var form_num = property_forms.length - 1;}
-    var new_form = $(property_forms[0]).clone();
-    var form_regex = RegExp(`form-(\\d){1}-`,'g');
-    form_num++;
-    new_form.html(new_form.html().replace(form_regex, `form-${form_num}-`));
-    new_form.appendTo('#pricing-variable-forms tbody');
-    $('#id_form-' + form_num + '-key').val('');
-    $('#id_form-' + form_num + '-value').val('');
-    total_form.val(form_num + 1);
-  })
-
-  $('.sortable').sortable({
-    handle: '.handle',
-    items: '.sortable-item',
-    update : function(event, ui) {
-      var new_order = '';
-      $(this).find('.sortable-item').each(function(i, x) {
-        var item_id = $(x).data('item-id');
-        if (new_order) {
-          new_order += ',';
-        }
-        new_order += item_id;
-      });
-      $.ajax({
-        url: $(this).data('order-url'),
-        data: {'new-order': new_order}
-      });
-    }
-  });
 });
diff --git a/chrono/manager/templates/chrono/manager_events_agenda_settings.html b/chrono/manager/templates/chrono/manager_events_agenda_settings.html
index a1ef50ad..e7a02d6d 100644
--- a/chrono/manager/templates/chrono/manager_events_agenda_settings.html
+++ b/chrono/manager/templates/chrono/manager_events_agenda_settings.html
@@ -4,9 +4,6 @@
 {% block agenda-extra-management-actions %}
   <a rel="popup" href="{% url 'chrono-manager-agenda-import-events' pk=object.id %}">{% trans 'Import Events' %}</a>
   <a rel="popup" href="{% url 'chrono-manager-agenda-add-event' pk=object.id %}">{% trans 'New Event' %}</a>
-  {% if pricing_enabled %}
-  <a rel="popup" href="{% url 'chrono-manager-agenda-pricing-add' pk=object.id %}">{% trans 'New pricing' %}</a>
-  {% endif %}
 {% endblock %}
 
 {% block agenda-settings %}
@@ -93,28 +90,6 @@
 </div>
 </div>
 
-{% if pricing_enabled %}
-<div class="section">
-<h3>{% trans "Pricing" context 'pricing' %}</h3>
-<div>
-  {% if agenda_pricings %}
-  <ul class="objects-list single-links">
-  {% for agenda_pricing in agenda_pricings %}
-    <li><a href="{% url 'chrono-manager-agenda-pricing-detail' agenda.pk agenda_pricing.pk %}">{{ agenda_pricing.pricing }} ({{ agenda_pricing.date_start|date:'d/m/Y' }} - {{ agenda_pricing.date_end|date:'d/m/Y' }})</a></li>
-  {% endfor %}
-  </ul>
-  {% else %}
-  <div class="big-msg-info">
-    {% blocktrans %}
-    This agenda doesn't have any pricing defined yet. Click on the "New pricing" button in
-    the top right of the page to add a first one.
-    {% endblocktrans %}
-  </div>
-  {% endif %}
-</div>
-</div>
-{% endif %}
-
 <div class="section">
 <h3>{% trans "Notifications" %}
 <a rel="popup" class="button" href="{% url 'chrono-manager-agenda-notifications-settings' pk=object.id %}">{% trans 'Configure' %}</a>
diff --git a/chrono/manager/templates/chrono/manager_home.html b/chrono/manager/templates/chrono/manager_home.html
index d5320db2..78ea9796 100644
--- a/chrono/manager/templates/chrono/manager_home.html
+++ b/chrono/manager/templates/chrono/manager_home.html
@@ -12,9 +12,6 @@
     <li><a rel="popup" href="{% url 'chrono-manager-agendas-export' %}" data-autoclose-dialog="true">{% trans 'Export' %}</a></li>
     <li><a href="{% url 'chrono-manager-events-type-list' %}">{% trans 'Events types' %}</a></li>
     <li><a href="{% url 'chrono-manager-check-type-list' %}">{% trans 'Check types' %}</a></li>
-    {% if pricing_enabled %}
-    <li><a href="{% url 'chrono-manager-pricing-list' %}">{% trans 'Pricing' context 'pricing' %}</a></li>
-    {% endif %}
     {% endif %}
     {% if has_access_to_unavailability_calendars %}
     <li><a href="{% url 'chrono-manager-unavailability-calendar-list' %}">{% trans 'Unavailability calendars' %}</a></li>
diff --git a/chrono/manager/utils.py b/chrono/manager/utils.py
index 22c53d1d..0e2952f2 100644
--- a/chrono/manager/utils.py
+++ b/chrono/manager/utils.py
@@ -30,7 +30,6 @@ from chrono.agendas.models import (
     Resource,
     UnavailabilityCalendar,
 )
-from chrono.pricing.models import CriteriaCategory, Pricing
 
 
 def export_site(
@@ -40,15 +39,9 @@ def export_site(
     events_types=True,
     resources=True,
     categories=True,
-    pricing_categories=True,
-    pricing_models=True,
 ):
     '''Dump site objects to JSON-dumpable dictionnary'''
     data = collections.OrderedDict()
-    if pricing_models:
-        data['pricing_models'] = [x.export_json() for x in Pricing.objects.all()]
-    if pricing_categories:
-        data['pricing_categories'] = [x.export_json() for x in CriteriaCategory.objects.all()]
     if categories:
         data['categories'] = [x.export_json() for x in Category.objects.all()]
     if resources:
@@ -75,8 +68,6 @@ def import_site(data, if_empty=False, clean=False, overwrite=False):
         or EventsType.objects.exists()
         or Resource.objects.exists()
         or Category.objects.exists()
-        or CriteriaCategory.objects.exists()
-        or Pricing.objects.exists()
     ):
         return
 
@@ -87,8 +78,6 @@ def import_site(data, if_empty=False, clean=False, overwrite=False):
         EventsType.objects.all().delete()
         Resource.objects.all().delete()
         Category.objects.all().delete()
-        CriteriaCategory.objects.all().delete()
-        Pricing.objects.all().delete()
 
     results = {
         key: collections.defaultdict(list)
@@ -99,8 +88,6 @@ def import_site(data, if_empty=False, clean=False, overwrite=False):
             'events_types',
             'resources',
             'categories',
-            'pricing_categories',
-            'pricing_models',
         ]
     }
 
@@ -124,8 +111,6 @@ def import_site(data, if_empty=False, clean=False, overwrite=False):
             (CheckTypeGroup, 'check_type_groups'),
             (UnavailabilityCalendar, 'unavailability_calendars'),
             (Agenda, 'agendas'),
-            (CriteriaCategory, 'pricing_categories'),
-            (Pricing, 'pricing_models'),
         ):
             objs = data.get(key, [])
             for obj in objs:
diff --git a/chrono/manager/views.py b/chrono/manager/views.py
index ebe61881..e4ef7518 100644
--- a/chrono/manager/views.py
+++ b/chrono/manager/views.py
@@ -26,7 +26,6 @@ from operator import attrgetter
 
 import requests
 from dateutil.relativedelta import MO, relativedelta
-from django.conf import settings
 from django.contrib import messages
 from django.core.exceptions import PermissionDenied
 from django.db import IntegrityError, transaction
@@ -87,7 +86,6 @@ from chrono.agendas.models import (
     UnavailabilityCalendar,
     VirtualMember,
 )
-from chrono.pricing.models import AgendaPricing
 from chrono.utils.date import get_weekday_index
 
 from .forms import (
@@ -116,7 +114,6 @@ from .forms import (
     EventsTimesheetForm,
     ImportEventsForm,
     MeetingTypeForm,
-    NewCheckTypeForm,
     NewDeskForm,
     NewEventForm,
     NewMeetingTypeForm,
@@ -165,7 +162,6 @@ class HomepageView(ListView):
     def get_context_data(self, **kwargs):
         context = super().get_context_data(**kwargs)
         context['has_access_to_unavailability_calendars'] = self.has_access_to_unavailability_calendars()
-        context['pricing_enabled'] = settings.CHRONO_ENABLE_PRICING
         return context
 
     def get(self, request, *args, **kwargs):
@@ -763,7 +759,7 @@ check_type_group_export = CheckTypeGroupExport.as_view()
 class CheckTypeAddView(CreateView):
     template_name = 'chrono/manager_check_type_form.html'
     model = CheckType
-    form_class = NewCheckTypeForm
+    fields = ['label', 'kind']
 
     def dispatch(self, request, *args, **kwargs):
         self.group_pk = kwargs.pop('group_pk')
@@ -1073,34 +1069,6 @@ class AgendasImportView(FormView):
                     x,
                 ),
             },
-            'pricing_categories': {
-                'create_noop': _('No pricing criteria category created.'),
-                'create': lambda x: ungettext(
-                    'A pricing criteria category has been created.',
-                    '%(count)d pricing criteria categories have been created.',
-                    x,
-                ),
-                'update_noop': _('No pricing criteria category updated.'),
-                'update': lambda x: ungettext(
-                    'A pricing criteria category has been updated.',
-                    '%(count)d pricing criteria categories have been updated.',
-                    x,
-                ),
-            },
-            'pricing_models': {
-                'create_noop': _('No pricing model created.'),
-                'create': lambda x: ungettext(
-                    'A pricing model has been created.',
-                    '%(count)d pricing models have been created.',
-                    x,
-                ),
-                'update_noop': _('No pricing model updated.'),
-                'update': lambda x: ungettext(
-                    'A pricing model has been updated.',
-                    '%(count)d pricing models have been updated.',
-                    x,
-                ),
-            },
         }
 
         global_noop = True
@@ -1121,19 +1089,17 @@ class AgendasImportView(FormView):
 
                 obj_results['messages'] = "%s %s" % (message1, message2)
 
-        a_count, uc_count, arg_count, pc_count, pm_count = (
+        a_count, uc_count, arg_count = (
             len(results['agendas']['all']),
             len(results['unavailability_calendars']['all']),
             len(results['check_type_groups']['all']),
-            len(results['pricing_categories']['all']),
-            len(results['pricing_models']['all']),
         )
-        if (a_count, uc_count, arg_count, pc_count, pm_count) == (1, 0, 0, 0, 0):
+        if (a_count, uc_count, arg_count) == (1, 0, 0):
             # only one agenda imported, redirect to settings page
             return HttpResponseRedirect(
                 reverse('chrono-manager-agenda-settings', kwargs={'pk': results['agendas']['all'][0].pk})
             )
-        if (a_count, uc_count, arg_count, pc_count, pm_count) == (0, 1, 0, 0, 0):
+        if (a_count, uc_count, arg_count) == (0, 1, 0):
             # only one unavailability calendar imported, redirect to settings page
             return HttpResponseRedirect(
                 reverse(
@@ -1141,20 +1107,9 @@ class AgendasImportView(FormView):
                     kwargs={'pk': results['unavailability_calendars']['all'][0].pk},
                 )
             )
-        if (a_count, uc_count, arg_count, pc_count, pm_count) == (0, 0, 1, 0, 0):
+        if (a_count, uc_count, arg_count) == (0, 0, 1):
             # only one check type group imported, redirect to check type page
             return HttpResponseRedirect(reverse('chrono-manager-check-type-list'))
-        if (a_count, uc_count, arg_count, pc_count, pm_count) == (0, 0, 0, 1, 0):
-            # only one criteria category imported, redirect to criteria page
-            return HttpResponseRedirect(reverse('chrono-manager-pricing-criteria-list'))
-        if (a_count, uc_count, arg_count, pc_count, pm_count) == (0, 0, 0, 0, 1):
-            # only one pricing imported, redirect to pricing page
-            return HttpResponseRedirect(
-                reverse(
-                    'chrono-manager-pricing-detail',
-                    kwargs={'pk': results['pricing_models']['all'][0].pk},
-                )
-            )
 
         if global_noop:
             messages.info(self.request, _('No data found.'))
@@ -1165,8 +1120,6 @@ class AgendasImportView(FormView):
             messages.info(self.request, results['events_types']['messages'])
             messages.info(self.request, results['resources']['messages'])
             messages.info(self.request, results['categories']['messages'])
-            messages.info(self.request, results['pricing_categories']['messages'])
-            messages.info(self.request, results['pricing_models']['messages'])
 
         return super().form_valid(form)
 
@@ -1925,12 +1878,6 @@ class AgendaSettings(ManagedAgendaMixin, DetailView):
                 end_datetime__gt=now(),
             )
             context['desk'] = desk
-            context['pricing_enabled'] = settings.CHRONO_ENABLE_PRICING
-            context['agenda_pricings'] = (
-                AgendaPricing.objects.filter(agenda=self.agenda)
-                .select_related('pricing')
-                .order_by('date_start', 'date_end')
-            )
         return context
 
     def get_events(self):
diff --git a/chrono/pricing/forms.py b/chrono/pricing/forms.py
deleted file mode 100644
index dd297115..00000000
--- a/chrono/pricing/forms.py
+++ /dev/null
@@ -1,128 +0,0 @@
-# chrono - agendas system
-# Copyright (C) 2022  Entr'ouvert
-#
-# This program is free software: you can redistribute it and/or modify it
-# under the terms of the GNU Affero General Public License as published
-# by the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-from django import forms
-from django.forms import ValidationError
-from django.template import Template, TemplateSyntaxError
-from django.utils.translation import ugettext_lazy as _
-
-from chrono.pricing.models import AgendaPricing, Criteria, CriteriaCategory
-
-
-class NewCriteriaForm(forms.ModelForm):
-    class Meta:
-        model = Criteria
-        fields = ['label', 'condition']
-
-    def clean_condition(self):
-        condition = self.cleaned_data['condition']
-        try:
-            Template('{%% if %s %%}OK{%% endif %%}' % condition)
-        except TemplateSyntaxError:
-            raise ValidationError(_('Invalid syntax.'))
-
-        return condition
-
-
-class CriteriaForm(NewCriteriaForm):
-    class Meta:
-        model = Criteria
-        fields = ['label', 'slug', 'condition']
-
-    def clean_slug(self):
-        slug = self.cleaned_data['slug']
-
-        if self.instance.category.criterias.filter(slug=slug).exclude(pk=self.instance.pk).exists():
-            raise ValidationError(_('Another criteria exists with the same identifier.'))
-
-        return slug
-
-
-class PricingDuplicateForm(forms.Form):
-    label = forms.CharField(label=_('New label'), max_length=150, required=False)
-
-
-class PricingVariableForm(forms.Form):
-    key = forms.CharField(label=_('Variable name'), required=False)
-    value = forms.CharField(
-        label=_('Value template'), widget=forms.TextInput(attrs={'size': 60}), required=False
-    )
-
-
-PricingVariableFormSet = forms.formset_factory(PricingVariableForm)
-
-
-class PricingCriteriaCategoryAddForm(forms.Form):
-    category = forms.ModelChoiceField(
-        label=_('Criteria category to add'), queryset=CriteriaCategory.objects.none(), required=True
-    )
-
-    def __init__(self, *args, **kwargs):
-        self.pricing = kwargs.pop('pricing')
-        super().__init__(*args, **kwargs)
-        self.fields['category'].queryset = CriteriaCategory.objects.exclude(pricings=self.pricing)
-
-
-class PricingCriteriaCategoryEditForm(forms.Form):
-    criterias = forms.ModelMultipleChoiceField(
-        label=_('Criterias'),
-        queryset=Criteria.objects.none(),
-        required=True,
-        widget=forms.CheckboxSelectMultiple(),
-    )
-
-    def __init__(self, *args, **kwargs):
-        self.pricing = kwargs.pop('pricing')
-        self.category = kwargs.pop('category')
-        super().__init__(*args, **kwargs)
-        self.fields['criterias'].queryset = self.category.criterias.all()
-        self.initial['criterias'] = self.pricing.criterias.filter(category=self.category)
-
-
-class AgendaPricingForm(forms.ModelForm):
-    class Meta:
-        model = AgendaPricing
-        fields = ['pricing', 'date_start', 'date_end']
-        widgets = {
-            'date_start': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
-            'date_end': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
-        }
-
-    def clean(self):
-        cleaned_data = super().clean()
-
-        if 'date_start' in cleaned_data and 'date_end' in cleaned_data:
-            if cleaned_data['date_end'] <= cleaned_data['date_start']:
-                self.add_error('date_end', _('End date must be greater than start date.'))
-            else:
-                overlapping_qs = AgendaPricing.objects.filter(agenda=self.instance.agenda,).extra(
-                    where=["(date_start, date_end) OVERLAPS (%s, %s)"],
-                    params=[cleaned_data['date_start'], cleaned_data['date_end']],
-                )
-                if self.instance.pk:
-                    overlapping_qs = overlapping_qs.exclude(pk=self.instance.pk)
-                if overlapping_qs.exists():
-                    raise forms.ValidationError(_('Pricing overlaps existing pricings.'))
-
-        return cleaned_data
-
-
-class PricingMatrixForm(forms.Form):
-    def __init__(self, *args, **kwargs):
-        matrix = kwargs.pop('matrix')
-        super().__init__(*args, **kwargs)
-        for i in range(len(matrix.rows[0].cells)):
-            self.fields['crit_%i' % i] = forms.DecimalField(required=True, max_digits=5, decimal_places=2)
diff --git a/chrono/pricing/migrations/0004_remove_pricing_models.py b/chrono/pricing/migrations/0004_remove_pricing_models.py
new file mode 100644
index 00000000..28f1cf08
--- /dev/null
+++ b/chrono/pricing/migrations/0004_remove_pricing_models.py
@@ -0,0 +1,55 @@
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('agendas', '0127_remove_pricing_models'),
+        ('pricing', '0003_extra_variables'),
+    ]
+
+    operations = [
+        migrations.AlterUniqueTogether(
+            name='criteria',
+            unique_together=None,
+        ),
+        migrations.RemoveField(
+            model_name='criteria',
+            name='category',
+        ),
+        migrations.RemoveField(
+            model_name='pricing',
+            name='categories',
+        ),
+        migrations.RemoveField(
+            model_name='pricing',
+            name='criterias',
+        ),
+        migrations.AlterUniqueTogether(
+            name='pricingcriteriacategory',
+            unique_together=None,
+        ),
+        migrations.RemoveField(
+            model_name='pricingcriteriacategory',
+            name='category',
+        ),
+        migrations.RemoveField(
+            model_name='pricingcriteriacategory',
+            name='pricing',
+        ),
+        migrations.DeleteModel(
+            name='AgendaPricing',
+        ),
+        migrations.DeleteModel(
+            name='Criteria',
+        ),
+        migrations.DeleteModel(
+            name='CriteriaCategory',
+        ),
+        migrations.DeleteModel(
+            name='Pricing',
+        ),
+        migrations.DeleteModel(
+            name='PricingCriteriaCategory',
+        ),
+    ]
diff --git a/chrono/pricing/models.py b/chrono/pricing/models.py
index a826cfeb..e69de29b 100644
--- a/chrono/pricing/models.py
+++ b/chrono/pricing/models.py
@@ -1,592 +0,0 @@
-# chrono - agendas system
-# Copyright (C) 2022  Entr'ouvert
-#
-# This program is free software: you can redistribute it and/or modify it
-# under the terms of the GNU Affero General Public License as published
-# by the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-import copy
-import dataclasses
-import decimal
-from typing import List
-
-from django.contrib.postgres.fields import JSONField
-from django.db import models
-from django.template import Context, RequestContext, Template, TemplateSyntaxError
-from django.utils.text import slugify
-from django.utils.translation import ugettext_lazy as _
-
-from chrono.agendas.models import Agenda, Booking, Subscription
-from chrono.utils.misc import AgendaImportError, clean_import_data, generate_slug
-
-
-class PricingError(Exception):
-    def __init__(self, details=None):
-        self.details = details or {}
-        super().__init__()
-
-
-class AgendaPricingNotFound(PricingError):
-    pass
-
-
-class CriteriaConditionNotFound(PricingError):
-    pass
-
-
-class PricingDataError(PricingError):
-    pass
-
-
-class PricingDataFormatError(PricingError):
-    pass
-
-
-class PricingEventNotCheckedError(PricingError):
-    pass
-
-
-class PricingBookingNotCheckedError(PricingError):
-    pass
-
-
-class PricingSubscriptionError(PricingError):
-    pass
-
-
-class PricingMultipleBookingError(PricingError):
-    pass
-
-
-class PricingBookingCheckTypeError(PricingError):
-    pass
-
-
-class CriteriaCategory(models.Model):
-    label = models.CharField(_('Label'), max_length=150)
-    slug = models.SlugField(_('Identifier'), max_length=160, unique=True)
-
-    class Meta:
-        ordering = ['label']
-
-    def __str__(self):
-        return self.label
-
-    def save(self, *args, **kwargs):
-        if not self.slug:
-            self.slug = generate_slug(self)
-        super().save(*args, **kwargs)
-
-    @property
-    def base_slug(self):
-        return slugify(self.label)
-
-    @classmethod
-    def import_json(cls, data, overwrite=False):
-        criterias = data.pop('criterias', [])
-        data = clean_import_data(cls, data)
-        category, created = cls.objects.update_or_create(slug=data['slug'], defaults=data)
-
-        if overwrite:
-            Criteria.objects.filter(category=category).delete()
-
-        for criteria in criterias:
-            criteria['category'] = category
-            Criteria.import_json(criteria)
-
-        return created, category
-
-    def export_json(self):
-        return {
-            'label': self.label,
-            'slug': self.slug,
-            'criterias': [a.export_json() for a in self.criterias.all()],
-        }
-
-
-class Criteria(models.Model):
-    category = models.ForeignKey(
-        CriteriaCategory, verbose_name=_('Category'), on_delete=models.CASCADE, related_name='criterias'
-    )
-    label = models.CharField(_('Label'), max_length=150)
-    slug = models.SlugField(_('Identifier'), max_length=160)
-    condition = models.CharField(_('Condition'), max_length=1000)
-    order = models.PositiveIntegerField()
-
-    class Meta:
-        ordering = ['order']
-        unique_together = ['category', 'slug']
-
-    def __str__(self):
-        return self.label
-
-    def save(self, *args, **kwargs):
-        if self.order is None:
-            max_order = (
-                Criteria.objects.filter(category=self.category)
-                .aggregate(models.Max('order'))
-                .get('order__max')
-                or 0
-            )
-            self.order = max_order + 1
-        if not self.slug:
-            self.slug = generate_slug(self, category=self.category)
-        super().save(*args, **kwargs)
-
-    @property
-    def base_slug(self):
-        return slugify(self.label)
-
-    @classmethod
-    def import_json(cls, data):
-        data = clean_import_data(cls, data)
-        cls.objects.update_or_create(slug=data['slug'], category=data['category'], defaults=data)
-
-    def export_json(self):
-        return {
-            'label': self.label,
-            'slug': self.slug,
-            'condition': self.condition,
-            'order': self.order,
-        }
-
-    @property
-    def identifier(self):
-        return '%s:%s' % (self.category.slug, self.slug)
-
-    def compute_condition(self, context):
-        try:
-            template = Template('{%% if %s %%}OK{%% endif %%}' % self.condition)
-        except TemplateSyntaxError:
-            return False
-        return template.render(Context(context)) == 'OK'
-
-
-class Pricing(models.Model):
-    label = models.CharField(_('Label'), max_length=150)
-    slug = models.SlugField(_('Identifier'), max_length=160, unique=True)
-    categories = models.ManyToManyField(
-        CriteriaCategory,
-        related_name='pricings',
-        through='PricingCriteriaCategory',
-    )
-    criterias = models.ManyToManyField(Criteria)
-    extra_variables = JSONField(blank=True, default=dict)
-
-    class Meta:
-        ordering = ['label']
-
-    def __str__(self):
-        return self.label
-
-    def save(self, *args, **kwargs):
-        if not self.slug:
-            self.slug = generate_slug(self)
-        super().save(*args, **kwargs)
-
-    @property
-    def base_slug(self):
-        return slugify(self.label)
-
-    def get_extra_variables(self, request, original_context):
-        result = {}
-        context = RequestContext(request)
-        context.push(original_context)
-        for key, tplt in (self.extra_variables or {}).items():
-            try:
-                template = Template(tplt)
-            except TemplateSyntaxError:
-                continue
-            result[key] = template.render(context)
-        return result
-
-    def get_extra_variables_keys(self):
-        return sorted((self.extra_variables or {}).keys())
-
-    @classmethod
-    def import_json(cls, data, overwrite=False):
-        data = data.copy()
-        categories = data.pop('categories', [])
-        categories_by_slug = {c.slug: c for c in CriteriaCategory.objects.all()}
-        criterias_by_categories_and_slug = {
-            (crit.category.slug, crit.slug): crit
-            for crit in Criteria.objects.select_related('category').all()
-        }
-        for category_data in categories:
-            category_slug = category_data['category']
-            if category_data['category'] not in categories_by_slug:
-                raise AgendaImportError(_('Missing "%s" pricing category') % category_data['category'])
-            for criteria_slug in category_data['criterias']:
-                if (category_slug, criteria_slug) not in criterias_by_categories_and_slug:
-                    raise AgendaImportError(
-                        _('Missing "%s" pricing criteria for "%s" category') % (criteria_slug, category_slug)
-                    )
-        data = clean_import_data(cls, data)
-        pricing, created = cls.objects.update_or_create(slug=data['slug'], defaults=data)
-
-        PricingCriteriaCategory.objects.filter(pricing=pricing).delete()
-        criterias = []
-        for category_data in categories:
-            pricing.categories.add(
-                categories_by_slug[category_data['category']],
-                through_defaults={'order': category_data['order']},
-            )
-            for criteria_slug in category_data['criterias']:
-                criterias.append(criterias_by_categories_and_slug[(category_data['category'], criteria_slug)])
-        pricing.criterias.set(criterias)
-
-        return created, pricing
-
-    def export_json(self):
-        return {
-            'label': self.label,
-            'slug': self.slug,
-            'extra_variables': self.extra_variables,
-            'categories': [pcc.export_json() for pcc in PricingCriteriaCategory.objects.filter(pricing=self)],
-        }
-
-    def duplicate(self, label=None):
-        # clone current pricing
-        new_pricing = copy.deepcopy(self)
-        new_pricing.pk = None
-        new_pricing.label = label or _('Copy of %s') % self.label
-        # reset slug
-        new_pricing.slug = None
-        new_pricing.save()
-
-        # set criterias
-        new_pricing.criterias.set(self.criterias.all())
-
-        # set categories
-        for pcc in PricingCriteriaCategory.objects.filter(pricing=self):
-            pcc.duplicate(pricing_target=new_pricing)
-
-        return new_pricing
-
-
-class PricingCriteriaCategory(models.Model):
-    pricing = models.ForeignKey(Pricing, on_delete=models.CASCADE)
-    category = models.ForeignKey(CriteriaCategory, on_delete=models.CASCADE)
-    order = models.PositiveIntegerField()
-
-    class Meta:
-        ordering = ['order']
-        unique_together = ['pricing', 'category']
-
-    def save(self, *args, **kwargs):
-        if self.order is None:
-            max_order = (
-                PricingCriteriaCategory.objects.filter(pricing=self.pricing)
-                .aggregate(models.Max('order'))
-                .get('order__max')
-                or 0
-            )
-            self.order = max_order + 1
-        super().save(*args, **kwargs)
-
-    def export_json(self):
-        return {
-            'category': self.category.slug,
-            'order': self.order,
-            'criterias': [c.slug for c in self.pricing.criterias.all() if c.category == self.category],
-        }
-
-    def duplicate(self, pricing_target):
-        new_pcc = copy.deepcopy(self)
-        new_pcc.pk = None
-        new_pcc.pricing = pricing_target
-        new_pcc.save()
-        return new_pcc
-
-
-@dataclasses.dataclass
-class PricingMatrixCell:
-    criteria: Criteria
-    value: decimal.Decimal
-
-
-@dataclasses.dataclass
-class PricingMatrixRow:
-    criteria: Criteria
-    cells: List[PricingMatrixCell]
-
-
-@dataclasses.dataclass
-class PricingMatrix:
-    criteria: Criteria
-    rows: List[PricingMatrixRow]
-
-
-class AgendaPricing(models.Model):
-    agenda = models.ForeignKey(Agenda, on_delete=models.CASCADE)
-    pricing = models.ForeignKey(Pricing, on_delete=models.CASCADE)
-    date_start = models.DateField()
-    date_end = models.DateField()
-    pricing_data = JSONField(null=True)
-
-    @classmethod
-    def import_json(cls, data):
-        data = clean_import_data(cls, data)
-        cls.objects.update_or_create(
-            agenda=data['agenda'],
-            pricing=data['pricing'],
-            date_start=data['date_start'],
-            date_end=data['date_end'],
-            defaults=data,
-        )
-
-    def export_json(self):
-        return {
-            'pricing': self.pricing.slug,
-            'date_start': self.date_start.strftime('%Y-%m-%d'),
-            'date_end': self.date_end.strftime('%Y-%m-%d'),
-            'pricing_data': self.pricing_data,
-        }
-
-    @staticmethod
-    def get_pricing_data(request, event, user_external_id, adult_external_id):
-        agenda_pricing = AgendaPricing.get_agenda_pricing(event)
-        context = agenda_pricing.get_pricing_context(request, user_external_id, adult_external_id)
-        pricing, criterias = agenda_pricing.compute_pricing(context)
-        modifier = agenda_pricing.get_booking_modifier(event, user_external_id)
-        return agenda_pricing.aggregate_pricing_data(pricing, criterias, context, modifier)
-
-    def aggregate_pricing_data(self, pricing, criterias, context, modifier):
-        if modifier['modifier_type'] == 'fixed':
-            pricing_amount = modifier['modifier_fixed']
-        else:
-            pricing_amount = pricing * modifier['modifier_rate'] / 100
-        return {
-            'pricing': pricing_amount,
-            'calculation_details': {
-                'pricing': pricing,
-                'criterias': criterias,
-                'context': context,
-            },
-            'booking_details': modifier,
-        }
-
-    @staticmethod
-    def get_agenda_pricing(event):
-        agenda = event.agenda
-        try:
-            return agenda.agendapricing_set.get(
-                date_start__lte=event.start_datetime,
-                date_end__gt=event.start_datetime,
-            )
-        except (AgendaPricing.DoesNotExist, AgendaPricing.MultipleObjectsReturned):
-            raise AgendaPricingNotFound
-
-    def get_subscription(self, event, user_external_id):
-        try:
-            return self.agenda.subscriptions.get(
-                user_external_id=user_external_id,
-                date_start__lte=event.start_datetime,
-                date_end__gt=event.start_datetime,
-            )
-        except (Subscription.DoesNotExist, Subscription.MultipleObjectsReturned):
-            raise PricingSubscriptionError
-
-    def get_pricing_context(self, request, user_external_id, adult_external_id):
-        context = {'user_external_id': user_external_id, 'adult_external_id': adult_external_id}
-        if ':' in user_external_id:
-            context['user_external_raw_id'] = user_external_id.split(':')[1]
-        if ':' in adult_external_id:
-            context['adult_external_raw_id'] = adult_external_id.split(':')[1]
-        return self.pricing.get_extra_variables(request, context)
-
-    def compute_pricing(self, context):
-        criterias = {}
-        categories = []
-        # for each category (ordered)
-        for category in self.pricing.categories.all().order_by('pricingcriteriacategory__order'):
-            criterias[category.slug] = None
-            categories.append(category.slug)
-            # find the first matching criteria (criterias are ordered)
-            for criteria in self.pricing.criterias.filter(category=category):
-                condition = criteria.compute_condition(context)
-                if condition:
-                    criterias[category.slug] = criteria.slug
-                    break
-
-        # now search for pricing values matching found criterias
-        pricing_data = self.pricing_data
-        # for each category (ordered)
-        for category in categories:
-            criteria = criterias[category]
-            if criteria is None:
-                raise CriteriaConditionNotFound(details={'category': category})
-            if not isinstance(pricing_data, dict):
-                raise PricingDataFormatError(
-                    details={'category': category, 'pricing': pricing_data, 'wanted': 'dict'}
-                )
-            key = '%s:%s' % (category, criteria)
-            if key not in pricing_data:
-                raise PricingDataError(details={'category': category, 'criteria': criteria})
-            pricing_data = pricing_data[key]
-
-        try:
-            pricing = decimal.Decimal(pricing_data)
-        except (decimal.InvalidOperation, ValueError, TypeError):
-            raise PricingDataFormatError(details={'pricing': pricing_data, 'wanted': 'decimal'})
-
-        return pricing, criterias
-
-    def get_booking_modifier(self, event, user_external_id):
-        # event must be checked
-        if event.checked is False:
-            raise PricingEventNotCheckedError
-
-        # search for an available subscription
-        self.get_subscription(event, user_external_id)
-
-        # search for a booking
-        try:
-            booking = event.booking_set.get(user_external_id=user_external_id)
-        except Booking.DoesNotExist:
-            # no booking
-            return {
-                'status': 'not-booked',
-                'modifier_type': 'rate',
-                'modifier_rate': 0,
-            }
-        except Booking.MultipleObjectsReturned:
-            raise PricingMultipleBookingError
-
-        # booking cancelled
-        if booking.cancellation_datetime is not None:
-            return {
-                'status': 'cancelled',
-                'modifier_type': 'rate',
-                'modifier_rate': 0,
-            }
-
-        # booking not cancelled, is must be checked
-        if booking.user_was_present is None:
-            raise PricingBookingNotCheckedError
-
-        status = 'presence' if booking.user_was_present else 'absence'
-        # no check_type, default rates
-        if booking.user_check_type is None:
-            return {
-                'status': status,
-                'check_type_group': None,
-                'check_type': None,
-                'modifier_type': 'rate',
-                'modifier_rate': 100 if booking.user_was_present else 0,
-            }
-
-        check_type = booking.user_check_type
-        kind_mapping = {'presence': True, 'absence': False}
-        # check_type kind and user_was_present mismatch
-        if kind_mapping[check_type.kind] != booking.user_was_present:
-            raise PricingBookingCheckTypeError(
-                details={
-                    'check_type_group': check_type.group.slug,
-                    'check_type': check_type.slug,
-                    'reason': 'wrong-kind',
-                }
-            )
-
-        # get pricing modifier
-        if check_type.pricing is not None:
-            return {
-                'status': status,
-                'check_type_group': check_type.group.slug,
-                'check_type': check_type.slug,
-                'modifier_type': 'fixed',
-                'modifier_fixed': check_type.pricing,
-            }
-        if check_type.pricing_rate is not None:
-            return {
-                'status': status,
-                'check_type_group': check_type.group.slug,
-                'check_type': check_type.slug,
-                'modifier_type': 'rate',
-                'modifier_rate': check_type.pricing_rate,
-            }
-        # pricing not found
-        raise PricingBookingCheckTypeError(
-            details={
-                'check_type_group': check_type.group.slug,
-                'check_type': check_type.slug,
-                'reason': 'not-configured',
-            }
-        )
-
-    def iter_pricing_matrix(self):
-        categories = self.pricing.categories.all().order_by('pricingcriteriacategory__order')[:3]
-        pricing_data = self.pricing_data or {}
-
-        if not categories:
-            return
-
-        if len(categories) < 3:
-            yield self.get_pricing_matrix(
-                main_criteria=None, categories=categories, pricing_data=pricing_data
-            )
-            return
-
-        # criterias are ordered
-        for criteria in self.pricing.criterias.all():
-            if criteria.category != categories[0]:
-                continue
-            yield self.get_pricing_matrix(
-                main_criteria=criteria,
-                categories=categories[1:],
-                pricing_data=pricing_data.get(criteria.identifier) or {},
-            )
-
-    def get_pricing_matrix(self, main_criteria, categories, pricing_data):
-        matrix = PricingMatrix(
-            criteria=main_criteria,
-            rows=[],
-        )
-
-        def get_pricing_matrix_cell(criteria_2, criteria_3, _pricing_data):
-            try:
-                value = decimal.Decimal(str(_pricing_data.get(criteria_3.identifier)))
-            except (decimal.InvalidOperation, ValueError, TypeError):
-                value = None
-            return PricingMatrixCell(criteria=criteria_2, value=value)
-
-        if len(categories) < 2:
-            rows = [
-                PricingMatrixRow(
-                    criteria=criteria,
-                    cells=[get_pricing_matrix_cell(None, criteria, pricing_data)],
-                )
-                for criteria in self.pricing.criterias.all()
-                if criteria.category == categories[0]
-            ]
-            matrix.rows = rows
-        else:
-            criterias_2 = [c for c in self.pricing.criterias.all() if c.category == categories[0]]
-            criterias_3 = [c for c in self.pricing.criterias.all() if c.category == categories[1]]
-
-            rows = [
-                PricingMatrixRow(
-                    criteria=criteria_3,
-                    cells=[
-                        get_pricing_matrix_cell(
-                            criteria_2,
-                            criteria_3,
-                            pricing_data.get(criteria_2.identifier) or {},
-                        )
-                        for criteria_2 in criterias_2
-                    ],
-                )
-                for criteria_3 in criterias_3
-            ]
-            matrix.rows = rows
-
-        return matrix
diff --git a/chrono/pricing/templates/chrono/pricing/manager_agenda_pricing_detail.html b/chrono/pricing/templates/chrono/pricing/manager_agenda_pricing_detail.html
deleted file mode 100644
index 1d1441b8..00000000
--- a/chrono/pricing/templates/chrono/pricing/manager_agenda_pricing_detail.html
+++ /dev/null
@@ -1,61 +0,0 @@
-{% extends "chrono/manager_agenda_settings.html" %}
-{% load i18n %}
-
-{% block breadcrumb %}
-{{ block.super }}
-<a href="{% url 'chrono-manager-agenda-pricing-detail' agenda.pk object.pk %}">{{ object.pricing }}</a>
-{% endblock %}
-
-{% block appbar %}
-<h2>
-    {{ object.pricing }} ({{ object.date_start|date:'d/m/Y' }} - {{ object.date_end|date:'d/m/Y' }})
-</h2>
-{% if user_can_manage %}
-<span class="actions">
-  <a class="extra-actions-menu-opener"></a>
-  <ul class="extra-actions-menu">
-    <li><a rel="popup" href="{% url 'chrono-manager-agenda-pricing-edit' agenda.pk object.pk %}">{% trans 'Options' %}</a></li>
-    <li><a rel="popup" href="{% url 'chrono-manager-agenda-pricing-delete' agenda.pk object.pk %}">{% trans 'Delete' %}</a></li>
-  </ul>
-</span>
-{% endif %}
-{% endblock %}
-
-{% block content %}
-{% for matrix in object.iter_pricing_matrix %}
-<div class="section">
-  {% if matrix.criteria %}<h3>{{ matrix.criteria.label }}</h3>{% endif %}
-<div>
-  <table class="main pricing-matrix-{{ matrix.criteria.slug }}">
-    {% if matrix.rows.0.cells.0.criteria %}
-    <thead>
-      <tr>
-        <th></th>
-        {% for cell in matrix.rows.0.cells %}<th scope="col">{{ cell.criteria.label }}</th>{% endfor %}
-      </tr>
-    </thead>
-    {% endif %}
-    <tbody>
-      {% for row in matrix.rows %}
-        <tr class="pricing-row-{{ row.criteria.slug }}">
-          <th scope="row">{{ row.criteria.label }}</th>
-          {% for cell in row.cells %}<td class="pricing-cell-{{ cell.criteria.slug }}">{{ cell.value|floatformat:"2"|default_if_none:"" }}</td>{% endfor %}
-        </tr>
-      {% endfor %}
-    </tbody>
-  </table>
-  {% if user_can_manage %}
-  <p>
-  <a class="pk-button" href="{% if matrix.criteria %}{% url 'chrono-manager-agenda-pricing-matrix-slug-edit' agenda.pk object.pk matrix.criteria.slug %}{% else %}{% url 'chrono-manager-agenda-pricing-matrix-edit' agenda.pk object.pk %}{% endif %}">{% trans "Edit pricing" %}</a>
-  </p>
-  {% endif %}
-</div>
-</div>
-{% empty %}
-<div class="big-msg-info">
-  {% blocktrans %}
-  This pricing model is misconfigured.
-  {% endblocktrans %}
-</div>
-{% endfor %}
-{% endblock %}
diff --git a/chrono/pricing/templates/chrono/pricing/manager_agenda_pricing_form.html b/chrono/pricing/templates/chrono/pricing/manager_agenda_pricing_form.html
deleted file mode 100644
index 517482b5..00000000
--- a/chrono/pricing/templates/chrono/pricing/manager_agenda_pricing_form.html
+++ /dev/null
@@ -1,35 +0,0 @@
-{% extends "chrono/manager_agenda_settings.html" %}
-{% load i18n %}
-
-{% block breadcrumb %}
-{{ block.super }}
-{% if form.instance.pk %}
-<a href="{% url 'chrono-manager-agenda-pricing-detail' agenda.pk object.pk %}">{{ object.pricing }}</a>
-<a href="{% url 'chrono-manager-agenda-pricing-edit' agenda.pk object.pk %}">{% trans "Edit" %}</a>
-{% else %}
-<a href="{% url 'chrono-manager-agenda-pricing-add' agenda.pk %}">{% trans "New pricing" %}</a>
-{% endif %}
-{% endblock %}
-
-{% block appbar %}
-{% if object.pk %}
-<h2>{% trans "Edit pricing" %}</h2>
-{% else %}
-<h2>{% trans "New pricing" %}</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>
-    {% if object.pk %}
-    <a class="cancel" href="{% url 'chrono-manager-agenda-pricing-detail' agenda.pk object.pk %}">{% trans 'Cancel' %}</a>
-    {% else %}
-    <a class="cancel" href="{% url 'chrono-manager-agenda-settings' agenda.pk %}">{% trans 'Cancel' %}</a>
-    {% endif %}
-  </div>
-</form>
-{% endblock %}
diff --git a/chrono/pricing/templates/chrono/pricing/manager_agenda_pricing_matrix_form.html b/chrono/pricing/templates/chrono/pricing/manager_agenda_pricing_matrix_form.html
deleted file mode 100644
index 70d4746b..00000000
--- a/chrono/pricing/templates/chrono/pricing/manager_agenda_pricing_matrix_form.html
+++ /dev/null
@@ -1,58 +0,0 @@
-{% extends "chrono/pricing/manager_agenda_pricing_detail.html" %}
-{% load i18n %}
-
-{% block breadcrumb %}
-{{ block.super }}
-{% if matrix.criteria %}
-<a href="{% url 'chrono-manager-agenda-pricing-matrix-slug-edit' agenda.pk object.pk matrix.criteria.slug %}">{% trans "Edit pricing" %}</a>
-{% else %}
-<a href="{% url 'chrono-manager-agenda-pricing-matrix-edit' agenda.pk object.pk %}">{% trans "Edit pricing" %}</a>
-{% endif %}
-{% endblock %}
-
-{% block appbar %}
-<h2>{% trans "Edit pricing" %}</h2>
-{% endblock %}
-
-{% block content %}
-<div class="section">
-  {% if matrix.criteria %}<h3>{{ matrix.criteria.label }}</h3>{% endif %}
-<div>
-<form method="post" enctype="multipart/form-data">
-  {% csrf_token %}
-  {{ form.management_form }}
-  <table class="main">
-    {% if matrix.rows.0.cells.0.criteria %}
-    <thead>
-      <tr>
-        <th></th>
-        {% for cell in matrix.rows.0.cells %}
-        <th>{{ cell.criteria.label }}</th>
-        {% endfor %}
-      </tr>
-    </thead>
-    {% endif %}
-    <tbody>
-    {% for sub_form in form %}
-    {% with row=matrix.rows|get:forloop.counter0 %}
-    <tr>
-      <th>{{ row.criteria.label }}</th>
-      {% for field in sub_form %}
-      <td>
-        {{ field.errors.as_ul }}
-        {{ field }}
-      </td>
-      {% endfor %}
-    </tr>
-    {% endwith %}
-    {% endfor %}
-    </tbody>
-  </table>
-  <div class="buttons">
-    <button class="submit-button">{% trans "Save" %}</button>
-    <a class="cancel" href="{% url 'chrono-manager-agenda-pricing-detail' agenda.pk object.pk %}">{% trans 'Cancel' %}</a>
-  </div>
-</form>
-</div>
-</div>
-{% endblock %}
diff --git a/chrono/pricing/templates/chrono/pricing/manager_criteria_category_form.html b/chrono/pricing/templates/chrono/pricing/manager_criteria_category_form.html
deleted file mode 100644
index a240d9a2..00000000
--- a/chrono/pricing/templates/chrono/pricing/manager_criteria_category_form.html
+++ /dev/null
@@ -1,31 +0,0 @@
-{% extends "chrono/pricing/manager_criteria_list.html" %}
-{% load i18n %}
-
-{% block breadcrumb %}
-{{ block.super }}
-{% if object.pk %}
-<a href="{% url 'chrono-manager-pricing-criteria-category-edit' object.pk %}">{{ object }}</a>
-{% else %}
-<a href="{% url 'chrono-manager-pricing-criteria-category-add' %}">{% trans "New category" %}</a>
-{% endif %}
-{% endblock %}
-
-{% block appbar %}
-{% if object.pk %}
-<h2>{% trans "Edit category" %}</h2>
-{% else %}
-<h2>{% trans "New category" %}</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 'chrono-manager-pricing-criteria-list' %}">{% trans 'Cancel' %}</a>
-  </div>
-</form>
-{% endblock %}
diff --git a/chrono/pricing/templates/chrono/pricing/manager_criteria_form.html b/chrono/pricing/templates/chrono/pricing/manager_criteria_form.html
deleted file mode 100644
index f299c3e9..00000000
--- a/chrono/pricing/templates/chrono/pricing/manager_criteria_form.html
+++ /dev/null
@@ -1,31 +0,0 @@
-{% extends "chrono/pricing/manager_criteria_list.html" %}
-{% load i18n %}
-
-{% block breadcrumb %}
-{{ block.super }}
-{% if form.instance.pk %}
-<a href="{% url 'chrono-manager-pricing-criteria-edit' form.instance.category_id form.instance.pk %}">{{ form.instance }}</a>
-{% else %}
-<a href="{% url 'chrono-manager-pricing-criteria-add' form.instance.category_id %}">{% trans "New criteria" %}</a>
-{% endif %}
-{% endblock %}
-
-{% block appbar %}
-{% if form.instance.pk %}
-<h2>{{ form.instance.category }} - {% trans "Edit criteria" %}</h2>
-{% else %}
-<h2>{{ form.instance.category }} - {% trans "New criteria" %}</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 'chrono-manager-pricing-criteria-list' %}">{% trans 'Cancel' %}</a>
-  </div>
-</form>
-{% endblock %}
diff --git a/chrono/pricing/templates/chrono/pricing/manager_criteria_list.html b/chrono/pricing/templates/chrono/pricing/manager_criteria_list.html
deleted file mode 100644
index c8fedf81..00000000
--- a/chrono/pricing/templates/chrono/pricing/manager_criteria_list.html
+++ /dev/null
@@ -1,58 +0,0 @@
-{% extends "chrono/pricing/manager_pricing_list.html" %}
-{% load i18n %}
-
-{% block breadcrumb %}
-{{ block.super }}
-<a href="{% url 'chrono-manager-pricing-criteria-list' %}">{% trans "Criterias" %}</a>
-{% endblock %}
-
-{% block appbar %}
-<h2>{% trans 'Criterias' %}</h2>
-<span class="actions">
-<a rel="popup" href="{% url 'chrono-manager-pricing-criteria-category-add' %}">{% trans 'New category' %}</a>
-</span>
-{% endblock %}
-
-
-{% block content %}
-<div class="pk-information">
-<p>{% trans "Define here pricing criterias used in pricing models." %}</p>
-</div>
-{% if object_list %}
-<p class="hint">
-{% blocktrans %}
-Use drag and drop with the ⣿ handles to reorder criterias inside a category.
-{% endblocktrans %}
-</p>
-{% endif %}
-{% for object in object_list %}
-<div class="section criteria-category">
-  <h3>
-    <a rel="popup" href="{% url 'chrono-manager-pricing-criteria-category-edit' object.pk %}">{{ object }} [{{ object.slug }}]</a>
-    <span>
-    <a class="button" href="{% url 'chrono-manager-pricing-criteria-category-export' object.pk %}">{% trans "Export"%}</a>
-    <a class="button" rel="popup" href="{% url 'chrono-manager-pricing-criteria-category-delete' object.pk %}">{% trans "Delete"%}</a>
-    </span>
-  </h3>
-  <div>
-  <ul class="objects-list single-links sortable" data-order-url="{% url 'chrono-manager-pricing-criteria-order' object.pk %}">
-    {% for criteria in object.criterias.all %}
-    <li class="sortable-item" data-item-id="{{ criteria.pk }}">
-        <span class="handle">⣿</span>
-        <a rel="popup" href="{% url 'chrono-manager-pricing-criteria-edit' object.pk criteria.pk %}">{{ criteria }}</a>
-        <a class="delete" rel="popup" href="{% url 'chrono-manager-pricing-criteria-delete' object.pk criteria.pk %}">{% trans "delete"%}</a>
-    </li>
-    {% endfor %}
-    <li><a class="add" rel="popup" href="{% url 'chrono-manager-pricing-criteria-add' object.pk %}">{% trans "Add a criteria" %}</a></li>
-  </ul>
-  </div>
-</div>
-{% empty %}
-<div class="big-msg-info">
-  {% blocktrans %}
-  This site doesn't have any pricing category yet. Click on the "New category" button in the top
-  right of the page to add a first one.
-  {% endblocktrans %}
-</div>
-{% endfor %}
-{% endblock %}
diff --git a/chrono/pricing/templates/chrono/pricing/manager_pricing_criteria_category_form.html b/chrono/pricing/templates/chrono/pricing/manager_pricing_criteria_category_form.html
deleted file mode 100644
index 5122296f..00000000
--- a/chrono/pricing/templates/chrono/pricing/manager_pricing_criteria_category_form.html
+++ /dev/null
@@ -1,31 +0,0 @@
-{% extends "chrono/pricing/manager_pricing_list.html" %}
-{% load i18n %}
-
-{% block breadcrumb %}
-{{ block.super }}
-<a href="{% url 'chrono-manager-pricing-detail' object.pk %}">{{ object }}</a>
-{% if category %}
-<a href="{% url 'chrono-manager-pricing-criteria-category-edit' object.pk category.pk %}">{% trans "Select criterias" %}</a>
-{% else %}
-<a href="{% url 'chrono-manager-pricing-criteria-category-add' object.pk %}">{% trans "Add a category" %}</a>
-{% endif %}
-{% endblock %}
-
-{% block appbar %}
-{% if category %}
-<h2>{% trans "Select criterias" %}</h2>
-{% else %}
-<h2>{% trans "Add a category" %}</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 'chrono-manager-pricing-detail' object.pk %}">{% trans 'Cancel' %}</a>
-  </div>
-</form>
-{% endblock %}
diff --git a/chrono/pricing/templates/chrono/pricing/manager_pricing_detail.html b/chrono/pricing/templates/chrono/pricing/manager_pricing_detail.html
deleted file mode 100644
index 00788d55..00000000
--- a/chrono/pricing/templates/chrono/pricing/manager_pricing_detail.html
+++ /dev/null
@@ -1,74 +0,0 @@
-{% extends "chrono/pricing/manager_pricing_list.html" %}
-{% load i18n %}
-
-{% block breadcrumb %}
-{{ block.super }}
-<a href="{% url 'chrono-manager-pricing-detail' object.pk %}">{{ object }}</a>
-{% endblock %}
-
-{% block appbar %}
-<h2>
-    {{ object }}
-    <span class="identifier">[{% trans "identifier:" %} {{ object.slug }}]</span>
-</h2>
-<span class="actions">
-  <a class="extra-actions-menu-opener"></a>
-  <ul class="extra-actions-menu">
-    <li><a rel="popup" href="{% url 'chrono-manager-pricing-edit' pk=object.pk %}">{% trans 'Options' %}</a></li>
-    <li><a rel="popup" class="action-duplicate" href="{% url 'chrono-manager-pricing-duplicate' pk=object.pk %}">{% trans 'Duplicate' %}</a></li>
-    <li><a href="{% url 'chrono-manager-pricing-export' pk=object.pk %}">{% trans 'Export' %}</a></li>
-    <li><a rel="popup" href="{% url 'chrono-manager-pricing-delete' pk=object.pk %}">{% trans 'Delete' %}</a></li>
-  </ul>
-</span>
-{% endblock %}
-
-{% block content %}
-<div class="section">
-  <h3>{% trans "Variables" %}</h3>
-
-  <div>
-    {% if object.extra_variables %}
-    <p>
-    <label>{% trans 'Extra variables:' %}</label>
-    {% for key in object.get_extra_variables_keys %}<i>{{ key }}</i>{% if not forloop.last %}, {% endif %}{% endfor %}
-    </p>
-    {% endif %}
-    <a class="pk-button" rel="popup" href="{% url 'chrono-manager-pricing-variable-edit' pk=object.pk %}">{% trans 'Define variables' %}</a>
-  </div>
-</div>
-
-<div class="section">
-  <h3>{% trans "Criterias" %}</h3>
-  {% with criterias=object.criterias.all categories=object.categories.all %}
-  {% if categories %}
-  <div>
-  {% blocktrans %}Use drag and drop with the ⣿ handles to reorder categories.{% endblocktrans %}
-  </div>
-  {% endif %}
-  <div class="sortable" data-order-url="{% url 'chrono-manager-pricing-criteria-category-order' object.pk %}">
-    {% for category in categories %}
-    <div class="paragraph sortable-item" data-item-id="{{ category.pk }}">
-      <h4><span class="handle">⣿</span>{% trans "Category:" %} {{ category }}</h4>
-      <p>{% trans "Selected criterias:" %}</p>
-      <ul>
-        {% for criteria in criterias %}
-        {% if criteria.category == category %}
-        <li>{{ criteria }}</li>
-        {% endif %}
-        {% endfor %}
-      </ul>
-      <p>
-        <a rel="popup" class="pk-button" href="{% url 'chrono-manager-pricing-criteria-category-edit' pk=object.pk category_pk=category.pk %}">{% trans "Change criterias selection" %}</a>
-        <a rel="popup" class="pk-button" href="{% url 'chrono-manager-pricing-criteria-category-delete' pk=object.pk category_pk=category.pk %}">{% trans "Remove this category" %}</a>
-      </p>
-    </div>
-    {% endfor %}
-    {% if object.categories.count < 3 %}
-    <p>
-      <a rel="popup" class="pk-button" href="{% url 'chrono-manager-pricing-criteria-category-add' pk=object.pk %}">{% trans "Add a category" %} <span class="extra-info">({% trans "max 3 categories" %})</span></a>
-    </p>
-    {% endif %}
-  {% endwith %}
-  </div>
-</div>
-{% endblock %}
diff --git a/chrono/pricing/templates/chrono/pricing/manager_pricing_duplicate_form.html b/chrono/pricing/templates/chrono/pricing/manager_pricing_duplicate_form.html
deleted file mode 100644
index 5035eb95..00000000
--- a/chrono/pricing/templates/chrono/pricing/manager_pricing_duplicate_form.html
+++ /dev/null
@@ -1,22 +0,0 @@
-{% extends "chrono/pricing/manager_pricing_detail.html" %}
-{% load i18n %}
-
-{% block breadcrumb %}
-{{ block.super }}
-<a href="{% url 'chrono-manager-pricing-duplicate' object.pk %}">{% trans "Duplicate pricing model" %}</a>
-{% endblock %}
-
-{% block appbar %}
-<h2>{% trans "Duplicate pricing model" %}</h2>
-{% endblock %}
-
-{% block content %}
-<form method="post" enctype="multipart/form-data">
-  {% csrf_token %}
-  {{ form.as_p }}
-  <div class="buttons">
-    <button class="submit-button">{% trans "Duplicate" %}</button>
-    <a class="cancel" href="{% url 'chrono-manager-pricing-detail' object.pk %}">{% trans 'Cancel' %}</a>
-  </div>
-</form>
-{% endblock %}
diff --git a/chrono/pricing/templates/chrono/pricing/manager_pricing_form.html b/chrono/pricing/templates/chrono/pricing/manager_pricing_form.html
deleted file mode 100644
index 7025f45b..00000000
--- a/chrono/pricing/templates/chrono/pricing/manager_pricing_form.html
+++ /dev/null
@@ -1,31 +0,0 @@
-{% extends "chrono/pricing/manager_pricing_list.html" %}
-{% load i18n %}
-
-{% block breadcrumb %}
-{{ block.super }}
-{% if object.pk %}
-<a href="{% url 'chrono-manager-pricing-detail' object.pk %}">{{ object }}</a>
-<a href="{% url 'chrono-manager-pricing-edit' object.pk %}">{% trans "Edit" %}</a>
-{% else %}
-<a href="{% url 'chrono-manager-pricing-add' %}">{% trans "New pricing model" %}</a>
-{% endif %}
-{% endblock %}
-
-{% block appbar %}
-{% if object.pk %}
-<h2>{% trans "Edit pricing model" %}</h2>
-{% else %}
-<h2>{% trans "New pricing model" %}</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 'chrono-manager-pricing-list' %}">{% trans 'Cancel' %}</a>
-  </div>
-</form>
-{% endblock %}
diff --git a/chrono/pricing/templates/chrono/pricing/manager_pricing_list.html b/chrono/pricing/templates/chrono/pricing/manager_pricing_list.html
deleted file mode 100644
index c5233985..00000000
--- a/chrono/pricing/templates/chrono/pricing/manager_pricing_list.html
+++ /dev/null
@@ -1,39 +0,0 @@
-{% extends "chrono/manager_base.html" %}
-{% load i18n %}
-
-{% block breadcrumb %}
-{{ block.super }}
-<a href="{% url 'chrono-manager-pricing-list' %}">{% trans "Pricing" context 'pricing' %}</a>
-{% endblock %}
-
-{% block appbar %}
-<h2>{% trans 'Pricing' context 'pricing' %}</h2>
-<span class="actions">
-<a href="{% url 'chrono-manager-pricing-criteria-list' %}">{% trans 'Criterias' %}</a>
-<a rel="popup" href="{% url 'chrono-manager-pricing-add' %}">{% trans 'New pricing model' %}</a>
-</span>
-{% endblock %}
-
-{% block content %}
-<div class="pk-information">
-<p>{% trans "Define here pricing models used in events agendas." %}</p>
-</div>
-{% if object_list %}
-<div>
-  <ul class="objects-list single-links">
-    {% for object in object_list %}
-    <li>
-        <a href="{% url 'chrono-manager-pricing-detail' pk=object.pk %}">{{ object.label }} ({{ object.slug }})</a>
-    </li>
-    {% endfor %}
-  </ul>
-</div>
-{% else %}
-<div class="big-msg-info">
-  {% blocktrans %}
-  This site doesn't have any pricing model yet. Click on the "New" button in the top
-  right of the page to add a first one.
-  {% endblocktrans %}
-</div>
-{% endif %}
-{% endblock %}
diff --git a/chrono/pricing/templates/chrono/pricing/manager_pricing_variable_form.html b/chrono/pricing/templates/chrono/pricing/manager_pricing_variable_form.html
deleted file mode 100644
index bd2570c9..00000000
--- a/chrono/pricing/templates/chrono/pricing/manager_pricing_variable_form.html
+++ /dev/null
@@ -1,44 +0,0 @@
-{% extends "chrono/pricing/manager_pricing_detail.html" %}
-{% load i18n %}
-
-{% block breadcrumb %}
-{{ block.super }}
-<a href="{% url 'chrono-manager-pricing-variable-edit' object.pk %}">{% trans "Variable definition" %}</a>
-{% endblock %}
-
-{% block appbar %}
-<h2>{% trans "Variable definition" %}</h2>
-{% endblock %}
-
-{% block content %}
-<form method="post" enctype="multipart/form-data">
-  {% csrf_token %}
-  {{ form.management_form }}
-  <table id="pricing-variable-forms">
-    <thead>
-      <tr>
-        {% for field in form.0 %}
-        <th class="column-{{ field.name }}{% if field.required %} required{% endif %}">{{ field.label }}</th>
-        {% endfor %}
-      </tr>
-    </thead>
-    <tbody>
-    {% for sub_form in form %}
-    <tr class='pricing-variable-form'>
-      {% for field in sub_form %}
-      <td class="field-{{ field.name }}">
-        {{ field.errors.as_ul }}
-        {{ field }}
-      </td>
-      {% endfor %}
-    </tr>
-    {% endfor %}
-    </tbody>
-  </table>
-  <button id="add-pricing-variable-form" type="button">{% trans "Add another variable" %}</button>
-  <div class="buttons">
-    <button class="submit-button">{% trans "Save" %}</button>
-    <a class="cancel" href="{% url 'chrono-manager-pricing-detail' object.pk %}">{% trans 'Cancel' %}</a>
-  </div>
-</form>
-{% endblock %}
diff --git a/chrono/pricing/urls.py b/chrono/pricing/urls.py
deleted file mode 100644
index 09fac10b..00000000
--- a/chrono/pricing/urls.py
+++ /dev/null
@@ -1,149 +0,0 @@
-# chrono - agendas system
-# Copyright (C) 2022  Entr'ouvert
-#
-# This program is free software: you can redistribute it and/or modify it
-# under the terms of the GNU Affero General Public License as published
-# by the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-from django.conf.urls import url
-
-from . import views
-
-urlpatterns = [
-    url(r'^$', views.pricing_list, name='chrono-manager-pricing-list'),
-    url(
-        r'^add/$',
-        views.pricing_add,
-        name='chrono-manager-pricing-add',
-    ),
-    url(
-        r'^(?P<pk>\d+)/$',
-        views.pricing_detail,
-        name='chrono-manager-pricing-detail',
-    ),
-    url(
-        r'^(?P<pk>\d+)/edit/$',
-        views.pricing_edit,
-        name='chrono-manager-pricing-edit',
-    ),
-    url(
-        r'^(?P<pk>\d+)/delete/$',
-        views.pricing_delete,
-        name='chrono-manager-pricing-delete',
-    ),
-    url(
-        r'^(?P<pk>\d+)/duplicate/$',
-        views.pricing_duplicate,
-        name='chrono-manager-pricing-duplicate',
-    ),
-    url(
-        r'^(?P<pk>\d+)/export/$',
-        views.pricing_export,
-        name='chrono-manager-pricing-export',
-    ),
-    url(
-        r'^(?P<pk>\d+)/variable/$',
-        views.pricing_variable_edit,
-        name='chrono-manager-pricing-variable-edit',
-    ),
-    url(
-        r'^(?P<pk>\d+)/category/add/$',
-        views.pricing_criteria_category_add,
-        name='chrono-manager-pricing-criteria-category-add',
-    ),
-    url(
-        r'^(?P<pk>\d+)/category/(?P<category_pk>\d+)/edit/$',
-        views.pricing_criteria_category_edit,
-        name='chrono-manager-pricing-criteria-category-edit',
-    ),
-    url(
-        r'^(?P<pk>\d+)/category/(?P<category_pk>\d+)/delete/$',
-        views.pricing_criteria_category_delete,
-        name='chrono-manager-pricing-criteria-category-delete',
-    ),
-    url(
-        r'^(?P<pk>\d+)/order/$',
-        views.pricing_criteria_category_order,
-        name='chrono-manager-pricing-criteria-category-order',
-    ),
-    url(r'^criterias/$', views.criteria_list, name='chrono-manager-pricing-criteria-list'),
-    url(
-        r'^criteria/category/add/$',
-        views.criteria_category_add,
-        name='chrono-manager-pricing-criteria-category-add',
-    ),
-    url(
-        r'^criteria/category/(?P<pk>\d+)/edit/$',
-        views.criteria_category_edit,
-        name='chrono-manager-pricing-criteria-category-edit',
-    ),
-    url(
-        r'^criteria/category/(?P<pk>\d+)/delete/$',
-        views.criteria_category_delete,
-        name='chrono-manager-pricing-criteria-category-delete',
-    ),
-    url(
-        r'^criteria/category/(?P<pk>\d+)/export/$',
-        views.criteria_category_export,
-        name='chrono-manager-pricing-criteria-category-export',
-    ),
-    url(
-        r'^criteria/category/(?P<pk>\d+)/order/$',
-        views.criteria_order,
-        name='chrono-manager-pricing-criteria-order',
-    ),
-    url(
-        r'^criteria/category/(?P<category_pk>\d+)/add/$',
-        views.criteria_add,
-        name='chrono-manager-pricing-criteria-add',
-    ),
-    url(
-        r'^criteria/category/(?P<category_pk>\d+)/(?P<pk>\d+)/edit/$',
-        views.criteria_edit,
-        name='chrono-manager-pricing-criteria-edit',
-    ),
-    url(
-        r'^criteria/category/(?P<category_pk>\d+)/(?P<pk>\d+)/delete/$',
-        views.criteria_delete,
-        name='chrono-manager-pricing-criteria-delete',
-    ),
-    url(
-        r'^agenda/(?P<pk>\d+)/pricing/add/$',
-        views.agenda_pricing_add,
-        name='chrono-manager-agenda-pricing-add',
-    ),
-    url(
-        r'^agenda/(?P<pk>\d+)/pricing/(?P<pricing_pk>\d+)/$',
-        views.agenda_pricing_detail,
-        name='chrono-manager-agenda-pricing-detail',
-    ),
-    url(
-        r'^agenda/(?P<pk>\d+)/pricing/(?P<pricing_pk>\d+)/edit/$',
-        views.agenda_pricing_edit,
-        name='chrono-manager-agenda-pricing-edit',
-    ),
-    url(
-        r'^agenda/(?P<pk>\d+)/pricing/(?P<pricing_pk>\d+)/delete/$',
-        views.agenda_pricing_delete,
-        name='chrono-manager-agenda-pricing-delete',
-    ),
-    url(
-        r'^agenda/(?P<pk>\d+)/pricing/(?P<pricing_pk>\d+)/matrix/edit/$',
-        views.agenda_pricing_matrix_edit,
-        name='chrono-manager-agenda-pricing-matrix-edit',
-    ),
-    url(
-        r'^agenda/(?P<pk>\d+)/pricing/(?P<pricing_pk>\d+)/matrix/(?P<slug>[-_a-zA-Z0-9]+)/edit/$',
-        views.agenda_pricing_matrix_edit,
-        name='chrono-manager-agenda-pricing-matrix-slug-edit',
-    ),
-]
diff --git a/chrono/pricing/views.py b/chrono/pricing/views.py
deleted file mode 100644
index 2cc66334..00000000
--- a/chrono/pricing/views.py
+++ /dev/null
@@ -1,667 +0,0 @@
-# chrono - agendas system
-# Copyright (C) 2022  Entr'ouvert
-#
-# This program is free software: you can redistribute it and/or modify it
-# under the terms of the GNU Affero General Public License as published
-# by the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-import datetime
-import json
-from collections import defaultdict
-from operator import itemgetter
-
-from django import forms
-from django.core.exceptions import PermissionDenied
-from django.db.models import Prefetch
-from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect
-from django.shortcuts import get_object_or_404
-from django.urls import reverse
-from django.views.generic import CreateView, DeleteView, DetailView, FormView, ListView, UpdateView
-from django.views.generic.detail import SingleObjectMixin
-
-from chrono.agendas.models import Agenda
-from chrono.manager.views import ManagedAgendaMixin, ViewableAgendaMixin
-from chrono.pricing.forms import (
-    AgendaPricingForm,
-    CriteriaForm,
-    NewCriteriaForm,
-    PricingCriteriaCategoryAddForm,
-    PricingCriteriaCategoryEditForm,
-    PricingDuplicateForm,
-    PricingMatrixForm,
-    PricingVariableFormSet,
-)
-from chrono.pricing.models import AgendaPricing, Criteria, CriteriaCategory, Pricing, PricingCriteriaCategory
-
-
-class PricingListView(ListView):
-    template_name = 'chrono/pricing/manager_pricing_list.html'
-    model = Pricing
-
-    def dispatch(self, request, *args, **kwargs):
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-
-pricing_list = PricingListView.as_view()
-
-
-class CriteriaListView(ListView):
-    template_name = 'chrono/pricing/manager_criteria_list.html'
-    model = CriteriaCategory
-
-    def dispatch(self, request, *args, **kwargs):
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get_queryset(self):
-        return CriteriaCategory.objects.prefetch_related('criterias')
-
-
-criteria_list = CriteriaListView.as_view()
-
-
-class PricingAddView(CreateView):
-    template_name = 'chrono/pricing/manager_pricing_form.html'
-    model = Pricing
-    fields = ['label']
-
-    def dispatch(self, request, *args, **kwargs):
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get_success_url(self):
-        return reverse('chrono-manager-pricing-detail', args=[self.object.pk])
-
-
-pricing_add = PricingAddView.as_view()
-
-
-class PricingDetailView(DetailView):
-    template_name = 'chrono/pricing/manager_pricing_detail.html'
-    model = Pricing
-
-    def dispatch(self, request, *args, **kwargs):
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get_queryset(self):
-        return (
-            super()
-            .get_queryset()
-            .prefetch_related(
-                Prefetch(
-                    'categories', queryset=CriteriaCategory.objects.order_by('pricingcriteriacategory__order')
-                )
-            )
-        )
-
-
-pricing_detail = PricingDetailView.as_view()
-
-
-class PricingEditView(UpdateView):
-    template_name = 'chrono/pricing/manager_pricing_form.html'
-    model = Pricing
-    fields = ['label', 'slug']
-
-    def dispatch(self, request, *args, **kwargs):
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get_success_url(self):
-        return reverse('chrono-manager-pricing-detail', args=[self.object.pk])
-
-
-pricing_edit = PricingEditView.as_view()
-
-
-class PricingDeleteView(DeleteView):
-    template_name = 'chrono/manager_confirm_delete.html'
-    model = Pricing
-
-    def dispatch(self, request, *args, **kwargs):
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get_success_url(self):
-        return reverse('chrono-manager-pricing-list')
-
-
-pricing_delete = PricingDeleteView.as_view()
-
-
-class PricingDuplicate(SingleObjectMixin, FormView):
-    template_name = 'chrono/pricing/manager_pricing_duplicate_form.html'
-    model = Pricing
-    form_class = PricingDuplicateForm
-
-    def dispatch(self, request, *args, **kwargs):
-        self.object = self.get_object()
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get_success_url(self):
-        return reverse('chrono-manager-pricing-detail', kwargs={'pk': self.new_pricing.pk})
-
-    def form_valid(self, form):
-        self.new_pricing = self.object.duplicate(label=form.cleaned_data['label'])
-        return super().form_valid(form)
-
-
-pricing_duplicate = PricingDuplicate.as_view()
-
-
-class PricingExport(DetailView):
-    model = Pricing
-
-    def dispatch(self, request, *args, **kwargs):
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get(self, request, *args, **kwargs):
-        response = HttpResponse(content_type='application/json')
-        today = datetime.date.today()
-        attachment = 'attachment; filename="export_pricing_{}_{}.json"'.format(
-            self.get_object().slug, today.strftime('%Y%m%d')
-        )
-        response['Content-Disposition'] = attachment
-        json.dump({'pricing_models': [self.get_object().export_json()]}, response, indent=2)
-        return response
-
-
-pricing_export = PricingExport.as_view()
-
-
-class PricingVariableEdit(FormView):
-    template_name = 'chrono/pricing/manager_pricing_variable_form.html'
-    model = Pricing
-    form_class = PricingVariableFormSet
-
-    def dispatch(self, request, *args, **kwargs):
-        self.object = get_object_or_404(Pricing, pk=kwargs['pk'])
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get_context_data(self, **kwargs):
-        kwargs['object'] = self.object
-        return super().get_context_data(**kwargs)
-
-    def get_initial(self):
-        return sorted(
-            ({'key': k, 'value': v} for k, v in self.object.extra_variables.items()),
-            key=itemgetter('key'),
-        )
-
-    def form_valid(self, form):
-        self.object.extra_variables = {}
-        for sub_data in form.cleaned_data:
-            if not sub_data.get('key'):
-                continue
-            self.object.extra_variables[sub_data['key']] = sub_data['value']
-        self.object.save()
-        return HttpResponseRedirect(self.get_success_url())
-
-    def get_success_url(self):
-        return reverse('chrono-manager-pricing-detail', args=[self.object.pk])
-
-
-pricing_variable_edit = PricingVariableEdit.as_view()
-
-
-class PricingCriteriaCategoryAddView(FormView):
-    template_name = 'chrono/pricing/manager_pricing_criteria_category_form.html'
-    model = Pricing
-    form_class = PricingCriteriaCategoryAddForm
-
-    def dispatch(self, request, *args, **kwargs):
-        self.object = get_object_or_404(Pricing, pk=kwargs['pk'])
-        if self.object.categories.count() >= 3:
-            raise Http404
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get_form_kwargs(self):
-        kwargs = super().get_form_kwargs()
-        kwargs['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):
-        PricingCriteriaCategory.objects.create(pricing=self.object, category=form.cleaned_data['category'])
-        return super().form_valid(form)
-
-    def get_success_url(self):
-        return reverse('chrono-manager-pricing-detail', args=[self.object.pk])
-
-
-pricing_criteria_category_add = PricingCriteriaCategoryAddView.as_view()
-
-
-class PricingCriteriaCategoryEditView(FormView):
-    template_name = 'chrono/pricing/manager_pricing_criteria_category_form.html'
-    model = Pricing
-    form_class = PricingCriteriaCategoryEditForm
-
-    def dispatch(self, request, *args, **kwargs):
-        self.object = get_object_or_404(Pricing, pk=kwargs['pk'])
-        self.category = get_object_or_404(self.object.categories, pk=kwargs['category_pk'])
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get_form_kwargs(self):
-        kwargs = super().get_form_kwargs()
-        kwargs['pricing'] = self.object
-        kwargs['category'] = self.category
-        return kwargs
-
-    def get_context_data(self, **kwargs):
-        kwargs['object'] = self.object
-        kwargs['category'] = self.category
-        return super().get_context_data(**kwargs)
-
-    def form_valid(self, form):
-        old_criterias = self.object.criterias.filter(category=self.category)
-        new_criterias = form.cleaned_data['criterias']
-        removed_criterias = set(old_criterias) - set(new_criterias)
-        self.object.criterias.remove(*removed_criterias)
-        self.object.criterias.add(*new_criterias)
-        return super().form_valid(form)
-
-    def get_success_url(self):
-        return reverse('chrono-manager-pricing-detail', args=[self.object.pk])
-
-
-pricing_criteria_category_edit = PricingCriteriaCategoryEditView.as_view()
-
-
-class PricingCriteriaCategoryDeleteView(DeleteView):
-    template_name = 'chrono/manager_confirm_delete.html'
-    model = CriteriaCategory
-    pk_url_kwarg = 'category_pk'
-
-    def dispatch(self, request, *args, **kwargs):
-        self.pricing = get_object_or_404(Pricing, pk=kwargs['pk'])
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get_queryset(self):
-        return self.pricing.categories.all()
-
-    def delete(self, request, *args, **kwargs):
-        self.object = self.get_object()
-        self.pricing.categories.remove(self.object)
-        self.pricing.criterias.remove(*self.pricing.criterias.filter(category=self.object))
-        return HttpResponseRedirect(self.get_success_url())
-
-    def get_success_url(self):
-        return reverse('chrono-manager-pricing-detail', args=[self.pricing.pk])
-
-
-pricing_criteria_category_delete = PricingCriteriaCategoryDeleteView.as_view()
-
-
-class PricingCriteriaCategoryOrder(DetailView):
-    model = Pricing
-
-    def dispatch(self, request, *args, **kwargs):
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get(self, request, *args, **kwargs):
-        if 'new-order' not in request.GET:
-            return HttpResponseBadRequest('missing new-order parameter')
-        pricing = self.get_object()
-        try:
-            new_order = [int(x) for x in request.GET['new-order'].split(',')]
-        except ValueError:
-            return HttpResponseBadRequest('incorrect new-order parameter')
-        categories = pricing.categories.all()
-        if set(new_order) != {x.pk for x in categories} or len(new_order) != len(categories):
-            return HttpResponseBadRequest('incorrect new-order parameter')
-        for i, c_id in enumerate(new_order):
-            PricingCriteriaCategory.objects.filter(pricing=pricing, category=c_id).update(order=i + 1)
-        return HttpResponse(status=204)
-
-
-pricing_criteria_category_order = PricingCriteriaCategoryOrder.as_view()
-
-
-class CriteriaCategoryAddView(CreateView):
-    template_name = 'chrono/pricing/manager_criteria_category_form.html'
-    model = CriteriaCategory
-    fields = ['label']
-
-    def dispatch(self, request, *args, **kwargs):
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get_success_url(self):
-        return reverse('chrono-manager-pricing-criteria-list')
-
-
-criteria_category_add = CriteriaCategoryAddView.as_view()
-
-
-class CriteriaCategoryEditView(UpdateView):
-    template_name = 'chrono/pricing/manager_criteria_category_form.html'
-    model = CriteriaCategory
-    fields = ['label', 'slug']
-
-    def dispatch(self, request, *args, **kwargs):
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get_success_url(self):
-        return reverse('chrono-manager-pricing-criteria-list')
-
-
-criteria_category_edit = CriteriaCategoryEditView.as_view()
-
-
-class CriteriaCategoryDeleteView(DeleteView):
-    template_name = 'chrono/manager_confirm_delete.html'
-    model = CriteriaCategory
-
-    def dispatch(self, request, *args, **kwargs):
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get_success_url(self):
-        return reverse('chrono-manager-pricing-criteria-list')
-
-
-criteria_category_delete = CriteriaCategoryDeleteView.as_view()
-
-
-class CriteriaCategoryExport(DetailView):
-    model = CriteriaCategory
-
-    def dispatch(self, request, *args, **kwargs):
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get(self, request, *args, **kwargs):
-        response = HttpResponse(content_type='application/json')
-        today = datetime.date.today()
-        attachment = 'attachment; filename="export_pricing_category_{}_{}.json"'.format(
-            self.get_object().slug, today.strftime('%Y%m%d')
-        )
-        response['Content-Disposition'] = attachment
-        json.dump({'pricing_categories': [self.get_object().export_json()]}, response, indent=2)
-        return response
-
-
-criteria_category_export = CriteriaCategoryExport.as_view()
-
-
-class CriteriaOrder(DetailView):
-    model = CriteriaCategory
-
-    def dispatch(self, request, *args, **kwargs):
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get(self, request, *args, **kwargs):
-        if 'new-order' not in request.GET:
-            return HttpResponseBadRequest('missing new-order parameter')
-        category = self.get_object()
-        try:
-            new_order = [int(x) for x in request.GET['new-order'].split(',')]
-        except ValueError:
-            return HttpResponseBadRequest('incorrect new-order parameter')
-        criterias = category.criterias.all()
-        if set(new_order) != {x.pk for x in criterias} or len(new_order) != len(criterias):
-            return HttpResponseBadRequest('incorrect new-order parameter')
-        criterias_by_id = {c.pk: c for c in criterias}
-        for i, c_id in enumerate(new_order):
-            criterias_by_id[c_id].order = i + 1
-            criterias_by_id[c_id].save()
-        return HttpResponse(status=204)
-
-
-criteria_order = CriteriaOrder.as_view()
-
-
-class CriteriaAddView(CreateView):
-    template_name = 'chrono/pricing/manager_criteria_form.html'
-    model = Criteria
-    form_class = NewCriteriaForm
-
-    def dispatch(self, request, *args, **kwargs):
-        self.category_pk = kwargs.pop('category_pk')
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get_form_kwargs(self):
-        kwargs = super().get_form_kwargs()
-        if not kwargs.get('instance'):
-            kwargs['instance'] = self.model()
-        kwargs['instance'].category_id = self.category_pk
-        return kwargs
-
-    def get_success_url(self):
-        return reverse('chrono-manager-pricing-criteria-list')
-
-
-criteria_add = CriteriaAddView.as_view()
-
-
-class CriteriaEditView(UpdateView):
-    template_name = 'chrono/pricing/manager_criteria_form.html'
-    model = Criteria
-    form_class = CriteriaForm
-
-    def dispatch(self, request, *args, **kwargs):
-        self.category_pk = kwargs.pop('category_pk')
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get_queryset(self):
-        return Criteria.objects.filter(category=self.category_pk)
-
-    def get_success_url(self):
-        return reverse('chrono-manager-pricing-criteria-list')
-
-
-criteria_edit = CriteriaEditView.as_view()
-
-
-class CriteriaDeleteView(DeleteView):
-    template_name = 'chrono/manager_confirm_delete.html'
-    model = Criteria
-
-    def dispatch(self, request, *args, **kwargs):
-        self.category_pk = kwargs.pop('category_pk')
-        if not request.user.is_staff:
-            raise PermissionDenied()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get_queryset(self):
-        return Criteria.objects.filter(category=self.category_pk)
-
-    def get_success_url(self):
-        return reverse('chrono-manager-pricing-criteria-list')
-
-
-criteria_delete = CriteriaDeleteView.as_view()
-
-
-class AgendaPricingAddView(ManagedAgendaMixin, CreateView):
-    template_name = 'chrono/pricing/manager_agenda_pricing_form.html'
-    model = AgendaPricing
-    form_class = AgendaPricingForm
-
-    def get_success_url(self):
-        return reverse('chrono-manager-agenda-pricing-detail', args=[self.agenda.pk, self.object.pk])
-
-
-agenda_pricing_add = AgendaPricingAddView.as_view()
-
-
-class AgendaPricingDetailView(ViewableAgendaMixin, DetailView):
-    model = AgendaPricing
-    pk_url_kwarg = 'pricing_pk'
-    template_name = 'chrono/pricing/manager_agenda_pricing_detail.html'
-
-    def set_agenda(self, **kwargs):
-        self.agenda = get_object_or_404(Agenda, pk=kwargs.get('pk'), kind='events')
-
-    def get_queryset(self):
-        return AgendaPricing.objects.filter(agenda=self.agenda).prefetch_related(
-            'pricing__criterias__category'
-        )
-
-    def get_context_data(self, **kwargs):
-        kwargs['user_can_manage'] = self.agenda.can_be_managed(self.request.user)
-        return super().get_context_data(**kwargs)
-
-
-agenda_pricing_detail = AgendaPricingDetailView.as_view()
-
-
-class AgendaPricingEditView(ManagedAgendaMixin, UpdateView):
-    template_name = 'chrono/pricing/manager_agenda_pricing_form.html'
-    model = AgendaPricing
-    pk_url_kwarg = 'pricing_pk'
-    form_class = AgendaPricingForm
-
-    def set_agenda(self, **kwargs):
-        self.agenda = get_object_or_404(Agenda, pk=kwargs.get('pk'), kind='events')
-
-    def get_queryset(self):
-        return AgendaPricing.objects.filter(agenda=self.agenda)
-
-    def get_success_url(self):
-        return reverse('chrono-manager-agenda-pricing-detail', args=[self.agenda.pk, self.object.pk])
-
-
-agenda_pricing_edit = AgendaPricingEditView.as_view()
-
-
-class AgendaPricingDeleteView(ManagedAgendaMixin, DeleteView):
-    template_name = 'chrono/manager_confirm_delete.html'
-    model = AgendaPricing
-    pk_url_kwarg = 'pricing_pk'
-
-    def set_agenda(self, **kwargs):
-        self.agenda = get_object_or_404(Agenda, pk=kwargs.get('pk'), kind='events')
-
-    def get_queryset(self):
-        return AgendaPricing.objects.filter(agenda=self.agenda)
-
-
-agenda_pricing_delete = AgendaPricingDeleteView.as_view()
-
-
-class AgendaPricingMatrixEdit(ManagedAgendaMixin, FormView):
-    template_name = 'chrono/pricing/manager_agenda_pricing_matrix_form.html'
-
-    def set_agenda(self, **kwargs):
-        self.agenda = get_object_or_404(Agenda, pk=kwargs.get('pk'), kind='events')
-        self.object = get_object_or_404(
-            AgendaPricing.objects.filter(agenda=self.agenda), pk=kwargs['pricing_pk']
-        )
-        matrix_list = list(self.object.iter_pricing_matrix())
-        if not matrix_list:
-            raise Http404
-        self.matrix = None
-        if kwargs.get('slug'):
-            for matrix in matrix_list:
-                if matrix.criteria is None:
-                    continue
-                if matrix.criteria.slug == kwargs['slug']:
-                    self.matrix = matrix
-                    break
-        else:
-            if matrix_list[0].criteria is None:
-                self.matrix = matrix_list[0]
-        if self.matrix is None:
-            raise Http404
-
-    def get_context_data(self, **kwargs):
-        kwargs['object'] = self.object
-        kwargs['matrix'] = self.matrix
-        return super().get_context_data(**kwargs)
-
-    def get_form(self):
-        count = len(self.matrix.rows)
-        PricingMatrixFormSet = forms.formset_factory(
-            PricingMatrixForm, min_num=count, max_num=count, extra=0, can_delete=False
-        )
-        kwargs = {
-            'initial': [
-                {'crit_%i' % i: cell.value for i, cell in enumerate(row.cells)} for row in self.matrix.rows
-            ]
-        }
-        if self.request.method == 'POST':
-            kwargs.update(
-                {
-                    'data': self.request.POST,
-                }
-            )
-        return PricingMatrixFormSet(form_kwargs={'matrix': self.matrix}, **kwargs)
-
-    def post(self, *args, **kwargs):
-        form = self.get_form()
-        if form.is_valid():
-            # build prixing_data for this matrix
-            matrix_pricing_data = defaultdict(dict)
-            for i, sub_data in enumerate(form.cleaned_data):
-                row = self.matrix.rows[i]
-                for j, cell in enumerate(row.cells):
-                    value = sub_data['crit_%s' % j]
-                    key = cell.criteria.identifier if cell.criteria else None
-                    matrix_pricing_data[key][row.criteria.identifier] = float(value)
-            if self.matrix.criteria:
-                # full pricing model with 3 categories
-                self.object.pricing_data = self.object.pricing_data or {}
-                self.object.pricing_data[self.matrix.criteria.identifier] = matrix_pricing_data
-            elif list(matrix_pricing_data.keys()) == [None]:
-                # only one category
-                self.object.pricing_data = matrix_pricing_data[None]
-            else:
-                # 2 categories
-                self.object.pricing_data = matrix_pricing_data
-            self.object.save()
-            return self.form_valid(form)
-        else:
-            return self.form_invalid(form)
-
-    def get_success_url(self):
-        return reverse('chrono-manager-agenda-pricing-detail', args=[self.agenda.pk, self.object.pk])
-
-
-agenda_pricing_matrix_edit = AgendaPricingMatrixEdit.as_view()
diff --git a/chrono/settings.py b/chrono/settings.py
index ee5ea957..54e7190f 100644
--- a/chrono/settings.py
+++ b/chrono/settings.py
@@ -190,9 +190,6 @@ except ImportError:
     WORKING_DAY_CALENDAR = None
     EXCEPTIONS_SOURCES = {}
 
-# feature flag for publik-famille & pricing developements
-CHRONO_ENABLE_PRICING = False
-
 TEMPLATE_VARS = {}
 SMS_URL = ''
 SMS_SENDER = ''
diff --git a/chrono/urls.py b/chrono/urls.py
index 5f15df95..d130965d 100644
--- a/chrono/urls.py
+++ b/chrono/urls.py
@@ -22,14 +22,12 @@ from django.contrib.staticfiles.urls import staticfiles_urlpatterns
 
 from .api.urls import urlpatterns as chrono_api_urls
 from .manager.urls import urlpatterns as chrono_manager_urls
-from .pricing.urls import urlpatterns as chrono_pricing_urls
 from .urls_utils import decorated_includes
 from .views import LoginView, LogoutView, homepage
 
 urlpatterns = [
     url(r'^$', homepage, name='home'),
     url(r'^manage/', decorated_includes(login_required, include(chrono_manager_urls))),
-    url(r'^manage/pricing/', decorated_includes(login_required, include(chrono_pricing_urls))),
     url(r'^api/', include(chrono_api_urls)),
     url(r'^logout/$', LogoutView.as_view(), name='auth_logout'),
     url(r'^login/$', LoginView.as_view(), name='auth_login'),
diff --git a/tests/manager/test_all.py b/tests/manager/test_all.py
index ad1cacda..96736450 100644
--- a/tests/manager/test_all.py
+++ b/tests/manager/test_all.py
@@ -25,7 +25,6 @@ from chrono.agendas.models import (
     UnavailabilityCalendar,
     VirtualMember,
 )
-from chrono.pricing.models import AgendaPricing, Pricing
 from chrono.utils.signature import check_query
 from tests.utils import login
 
@@ -445,56 +444,6 @@ def test_options_events_agenda_events_type(app, admin_user):
     assert 'events_type' not in resp.context['form'].fields
 
 
-def test_options_events_agenda_pricing(settings, app, admin_user):
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    pricing1 = Pricing.objects.create(label='Model 1')
-    pricing2 = Pricing.objects.create(label='Model 2')
-
-    app = login(app)
-    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
-    assert 'Pricing' in resp
-    assert 'Model 1' not in resp
-    assert 'Model 2' not in resp
-    AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing1,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2022, month=9, day=1),
-    )
-    AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing1,
-        date_start=datetime.date(year=2022, month=9, day=1),
-        date_end=datetime.date(year=2023, month=9, day=1),
-    )
-    AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing2,
-        date_start=datetime.date(year=2022, month=9, day=1),
-        date_end=datetime.date(year=2023, month=9, day=1),
-    )
-
-    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
-    assert 'Model 1 (01/09/2021 - 01/09/2022)' in resp
-    assert 'Model 1 (01/09/2022 - 01/09/2023)' in resp
-    assert 'Model 2 (01/09/2022 - 01/09/2023)' in resp
-
-    settings.CHRONO_ENABLE_PRICING = False
-    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
-    assert 'Pricing' not in resp
-    assert 'Model 1' not in resp
-    assert 'Model 2' not in resp
-    settings.CHRONO_ENABLE_PRICING = True
-
-    # check kind
-    agenda.kind = 'meetings'
-    agenda.save()
-    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
-    assert 'Pricing' not in resp
-    assert 'Model 1' not in resp
-    assert 'Model 2' not in resp
-
-
 def test_options_events_agenda_delays(settings, app, admin_user):
     settings.WORKING_DAY_CALENDAR = None
     agenda = Agenda.objects.create(label='Foo bar')
diff --git a/tests/manager/test_check_type.py b/tests/manager/test_check_type.py
index 2e7e2c7d..5bb0b34c 100644
--- a/tests/manager/test_check_type.py
+++ b/tests/manager/test_check_type.py
@@ -119,8 +119,6 @@ def test_add_check_type(app, admin_user):
     assert check_type.group == group
     assert check_type.slug == 'foo-reason'
     assert check_type.kind == 'absence'
-    assert check_type.pricing is None
-    assert check_type.pricing_rate is None
 
     resp = app.get('/manage/check-type/group/%s/add/' % group.pk)
     resp.form['label'] = 'Foo reason'
@@ -133,43 +131,6 @@ def test_add_check_type(app, admin_user):
     assert check_type.kind == 'presence'
 
 
-def test_add_check_type_pricing(settings, app, admin_user):
-    group = CheckTypeGroup.objects.create(label='Foo bar')
-
-    app = login(app)
-    resp = app.get('/manage/check-type/group/%s/add/' % group.pk)
-    assert 'pricing' in resp.context['form'].fields
-    assert 'pricing_rate' in resp.context['form'].fields
-    resp.form['label'] = 'Foo reason'
-    resp.form['pricing'] = 42
-    resp.form['pricing_rate'] = 150
-    resp = resp.form.submit()
-    assert resp.context['form'].errors['__all__'] == ['Please choose between pricing and pricing rate.']
-    resp.form['pricing'] = 0
-    resp.form['pricing_rate'] = 0
-    resp = resp.form.submit()
-    assert resp.context['form'].errors['__all__'] == ['Please choose between pricing and pricing rate.']
-    resp.form['pricing'] = 42
-    resp.form['pricing_rate'] = None
-    resp = resp.form.submit()
-    check_type = CheckType.objects.latest('pk')
-    assert check_type.pricing == 42
-    assert check_type.pricing_rate is None
-
-    resp = app.get('/manage/check-type/group/%s/add/' % group.pk)
-    resp.form['label'] = 'Foo reason'
-    resp.form['pricing_rate'] = 150
-    resp = resp.form.submit()
-    check_type = CheckType.objects.latest('pk')
-    assert check_type.pricing is None
-    assert check_type.pricing_rate == 150
-
-    settings.CHRONO_ENABLE_PRICING = False
-    resp = app.get('/manage/check-type/group/%s/add/' % group.pk)
-    assert 'pricing' not in resp.context['form'].fields
-    assert 'pricing_rate' not in resp.context['form'].fields
-
-
 def test_add_check_type_as_manager(app, manager_user, agenda_with_restrictions):
     group = CheckTypeGroup.objects.create(label='Foo bar')
 
@@ -205,8 +166,6 @@ def test_edit_check_type(app, admin_user):
     assert check_type.label == 'Foo bar reason'
     assert check_type.slug == 'foo-bar-reason'
     assert check_type.kind == 'presence'
-    assert check_type.pricing is None
-    assert check_type.pricing_rate is None
     assert check_type.disabled is True
 
     # check_type is used
@@ -225,39 +184,6 @@ def test_edit_check_type_as_manager(app, manager_user, agenda_with_restrictions)
     app.get('/manage/check-type/group/%s/%s/edit/' % (group.pk, check_type.pk), status=403)
 
 
-def test_edit_check_type_pricing(settings, app, admin_user):
-    group = CheckTypeGroup.objects.create(label='Foo bar')
-    check_type = CheckType.objects.create(label='Foo reason', group=group)
-
-    app = login(app)
-    resp = app.get('/manage/check-type/group/%s/%s/edit/' % (group.pk, check_type.pk))
-    assert 'pricing' in resp.context['form'].fields
-    assert 'pricing_rate' in resp.context['form'].fields
-    resp.form['pricing'] = 42
-    resp.form['pricing_rate'] = 150
-    resp = resp.form.submit()
-    assert resp.context['form'].errors['__all__'] == ['Please choose between pricing and pricing rate.']
-    resp.form['pricing'] = 42
-    resp.form['pricing_rate'] = None
-    resp = resp.form.submit()
-    check_type.refresh_from_db()
-    assert check_type.pricing == 42
-    assert check_type.pricing_rate is None
-
-    resp = app.get('/manage/check-type/group/%s/%s/edit/' % (group.pk, check_type.pk))
-    resp.form['pricing'] = None
-    resp.form['pricing_rate'] = 150
-    resp = resp.form.submit()
-    check_type.refresh_from_db()
-    assert check_type.pricing is None
-    assert check_type.pricing_rate == 150
-
-    settings.CHRONO_ENABLE_PRICING = False
-    resp = app.get('/manage/check-type/group/%s/%s/edit/' % (group.pk, check_type.pk))
-    assert 'pricing' not in resp.context['form'].fields
-    assert 'pricing_rate' not in resp.context['form'].fields
-
-
 def test_delete_check_type(app, admin_user):
     group = CheckTypeGroup.objects.create(label='Foo bar')
     check_type = CheckType.objects.create(label='Foo reason', group=group)
diff --git a/tests/manager/test_import_export.py b/tests/manager/test_import_export.py
index bcfa9604..efd161e2 100644
--- a/tests/manager/test_import_export.py
+++ b/tests/manager/test_import_export.py
@@ -22,7 +22,7 @@ from tests.utils import login
 pytestmark = pytest.mark.django_db
 
 
-def test_export_site(settings, app, admin_user):
+def test_export_site(app, admin_user):
     login(app)
     resp = app.get('/manage/')
     resp = resp.click('Export')
@@ -40,8 +40,6 @@ def test_export_site(settings, app, admin_user):
         'events_types': [],
         'resources': [],
         'categories': [],
-        'pricing_categories': [],
-        'pricing_models': [],
     }
 
     agenda = Agenda.objects.create(label='Foo Bar', kind='events')
@@ -57,8 +55,6 @@ def test_export_site(settings, app, admin_user):
     assert len(site_json['events_types']) == 0
     assert len(site_json['resources']) == 0
     assert len(site_json['categories']) == 0
-    assert len(site_json['pricing_categories']) == 0
-    assert len(site_json['pricing_models']) == 0
 
     resp = app.get('/manage/agendas/export/')
     resp.form['agendas'] = False
@@ -66,8 +62,6 @@ def test_export_site(settings, app, admin_user):
     resp.form['events_types'] = False
     resp.form['resources'] = False
     resp.form['categories'] = False
-    resp.form['pricing_categories'] = False
-    resp.form['pricing_models'] = False
     resp = resp.form.submit()
 
     site_json = json.loads(resp.text)
@@ -77,13 +71,6 @@ def test_export_site(settings, app, admin_user):
     assert 'events_types' not in site_json
     assert 'resources' not in site_json
     assert 'categories' not in site_json
-    assert 'pricing_categories' not in site_json
-    assert 'pricing_models' not in site_json
-
-    settings.CHRONO_ENABLE_PRICING = False
-    resp = app.get('/manage/agendas/export/')
-    assert 'pricing_categories' not in resp.context['form'].fields
-    assert 'pricing_models' not in resp.context['form'].fields
 
 
 def test_import_agenda_as_manager(app, manager_user):
diff --git a/tests/pricing/__init__.py b/tests/pricing/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/tests/pricing/conftest.py b/tests/pricing/conftest.py
deleted file mode 100644
index 2f25b082..00000000
--- a/tests/pricing/conftest.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import pytest
-from django.contrib.auth.models import Group, User
-
-
-@pytest.fixture
-def simple_user():
-    try:
-        user = User.objects.get(username='user')
-    except User.DoesNotExist:
-        user = User.objects.create_user('user', password='user')
-    return user
-
-
-@pytest.fixture
-def managers_group():
-    group, _ = Group.objects.get_or_create(name='Managers')
-    return group
-
-
-@pytest.fixture
-def manager_user(managers_group):
-    try:
-        user = User.objects.get(username='manager')
-    except User.DoesNotExist:
-        user = User.objects.create_user('manager', password='manager')
-    user.groups.set([managers_group])
-    return user
-
-
-@pytest.fixture
-def admin_user():
-    try:
-        user = User.objects.get(username='admin')
-    except User.DoesNotExist:
-        user = User.objects.create_superuser('admin', email=None, password='admin')
-    return user
diff --git a/tests/pricing/test_manager.py b/tests/pricing/test_manager.py
deleted file mode 100644
index 509c0a01..00000000
--- a/tests/pricing/test_manager.py
+++ /dev/null
@@ -1,1630 +0,0 @@
-import copy
-import datetime
-import json
-
-import pytest
-from webtest import Upload
-
-from chrono.agendas.models import Agenda
-from chrono.pricing.models import AgendaPricing, Criteria, CriteriaCategory, Pricing, PricingCriteriaCategory
-from tests.utils import login
-
-pytestmark = pytest.mark.django_db
-
-
-@pytest.fixture
-def agenda_with_restrictions(manager_user):
-    agenda = Agenda(label='Foo Bar')
-    agenda.view_role = manager_user.groups.all()[0]
-    agenda.save()
-    return agenda
-
-
-def test_list_pricings_as_manager(app, manager_user, agenda_with_restrictions):
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/', status=403)
-
-    resp = app.get('/manage/')
-    assert 'Pricing' not in resp.text
-
-
-def test_add_pricing(settings, app, admin_user):
-    app = login(app)
-    resp = app.get('/manage/')
-    resp = resp.click('Pricing')
-    resp = resp.click('New pricing model')
-    resp.form['label'] = 'Pricing model for lunch'
-    resp = resp.form.submit()
-    pricing = Pricing.objects.latest('pk')
-    assert resp.location.endswith('/manage/pricing/%s/' % pricing.pk)
-    assert pricing.label == 'Pricing model for lunch'
-    assert pricing.slug == 'pricing-model-for-lunch'
-
-    settings.CHRONO_ENABLE_PRICING = False
-    resp = app.get('/manage/')
-    assert 'Pricing' not in resp.text
-
-
-def test_add_pricing_as_manager(app, manager_user):
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/add/', status=403)
-
-
-def test_detail_pricing(app, admin_user):
-    pricing = Pricing.objects.create(label='Model')
-
-    app = login(app)
-    resp = app.get('/manage/pricing/')
-    resp = resp.click(href='/manage/pricing/%s/' % pricing.pk)
-    assert '/manage/pricing/%s/edit/' % pricing.pk in resp
-    assert '/manage/pricing/%s/delete/' % pricing.pk in resp
-
-
-def test_detail_pricing_as_manager(app, manager_user):
-    pricing = Pricing.objects.create(label='Model')
-
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/%s/' % pricing.pk, status=403)
-
-
-def test_edit_pricing(app, admin_user):
-    pricing = Pricing.objects.create(label='Model 1')
-    pricing2 = Pricing.objects.create(label='Model 2')
-
-    app = login(app)
-    resp = app.get('/manage/pricing/%s/' % pricing.pk)
-    resp = resp.click(href='/manage/pricing/%s/edit/' % pricing.pk)
-    resp.form['label'] = 'Model Foo'
-    resp.form['slug'] = pricing2.slug
-    resp = resp.form.submit()
-    assert resp.context['form'].errors['slug'] == ['Pricing with this Identifier already exists.']
-
-    resp.form['slug'] = 'foo-bar'
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/pricing/%s/' % pricing.pk)
-    pricing.refresh_from_db()
-    assert pricing.label == 'Model Foo'
-    assert pricing.slug == 'foo-bar'
-
-
-def test_edit_pricing_as_manager(app, manager_user):
-    pricing = Pricing.objects.create(label='Model')
-
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/%s/edit/' % pricing.pk, status=403)
-
-
-def test_delete_pricing(app, admin_user):
-    pricing = Pricing.objects.create(label='Model')
-
-    app = login(app)
-    resp = app.get('/manage/pricing/%s/' % pricing.pk)
-    resp = resp.click(href='/manage/pricing/%s/delete/' % pricing.pk)
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/pricing/')
-    assert Pricing.objects.exists() is False
-
-
-def test_delete_pricing_as_manager(app, manager_user):
-    pricing = Pricing.objects.create(label='Model')
-
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/%s/delete/' % pricing.pk, status=403)
-
-
-def test_duplicate_pricing(app, admin_user):
-    pricing = Pricing.objects.create(label='Model')
-    assert Pricing.objects.count() == 1
-
-    app = login(app)
-    resp = app.get('/manage/pricing/%s/' % pricing.pk)
-    resp = resp.click(href='/manage/pricing/%s/duplicate/' % pricing.pk)
-    resp = resp.form.submit()
-    assert Pricing.objects.count() == 2
-
-    new_pricing = Pricing.objects.latest('pk')
-    assert resp.location == '/manage/pricing/%s/' % new_pricing.pk
-    assert new_pricing.pk != pricing.pk
-
-    resp = resp.follow()
-    assert 'copy-of-model' in resp.text
-
-    resp = resp.click(href='/manage/pricing/%s/duplicate/' % new_pricing.pk)
-    resp.form['label'] = 'hop'
-    resp = resp.form.submit().follow()
-    assert 'hop' in resp.text
-
-
-def test_duplicate_pricing_as_manager(app, manager_user):
-    pricing = Pricing.objects.create(label='Model')
-
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/%s/duplicate/' % pricing.pk, status=403)
-
-
-@pytest.mark.freeze_time('2021-07-08')
-def test_import_pricing(app, admin_user):
-    pricing = Pricing.objects.create(label='Model')
-
-    app = login(app)
-    resp = app.get('/manage/pricing/%s/export/' % pricing.id)
-    assert resp.headers['content-type'] == 'application/json'
-    assert resp.headers['content-disposition'] == 'attachment; filename="export_pricing_model_20210708.json"'
-    pricing_export = resp.text
-
-    # existing pricing
-    resp = app.get('/manage/', status=200)
-    resp = resp.click('Import')
-    resp.form['agendas_json'] = Upload('export.json', pricing_export.encode('utf-8'), 'application/json')
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/pricing/%s/' % pricing.pk)
-    resp = resp.follow()
-    assert 'No pricing model created. A pricing model has been updated.' not in resp.text
-    assert Pricing.objects.count() == 1
-
-    # new pricing
-    Pricing.objects.all().delete()
-    resp = app.get('/manage/', status=200)
-    resp = resp.click('Import')
-    resp.form['agendas_json'] = Upload('export.json', pricing_export.encode('utf-8'), 'application/json')
-    resp = resp.form.submit()
-    pricing = Pricing.objects.latest('pk')
-    assert resp.location.endswith('/manage/pricing/%s/' % pricing.pk)
-    resp = resp.follow()
-    assert 'A pricing model has been created. No pricing model updated.' not in resp.text
-    assert Pricing.objects.count() == 1
-
-    # multiple pricing
-    pricings = json.loads(pricing_export)
-    pricings['pricing_models'].append(copy.copy(pricings['pricing_models'][0]))
-    pricings['pricing_models'].append(copy.copy(pricings['pricing_models'][0]))
-    pricings['pricing_models'][1]['label'] = 'Foo bar 2'
-    pricings['pricing_models'][1]['slug'] = 'foo-bar-2'
-    pricings['pricing_models'][2]['label'] = 'Foo bar 3'
-    pricings['pricing_models'][2]['slug'] = 'foo-bar-3'
-
-    resp = app.get('/manage/', status=200)
-    resp = resp.click('Import')
-    resp.form['agendas_json'] = Upload(
-        'export.json', json.dumps(pricings).encode('utf-8'), 'application/json'
-    )
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/')
-    resp = resp.follow()
-    assert '2 pricing models have been created. A pricing model has been updated.' in resp.text
-    assert Pricing.objects.count() == 3
-
-    Pricing.objects.all().delete()
-    resp = app.get('/manage/', status=200)
-    resp = resp.click('Import')
-    resp.form['agendas_json'] = Upload(
-        'export.json', json.dumps(pricings).encode('utf-8'), 'application/json'
-    )
-    resp = resp.form.submit().follow()
-    assert '3 pricing models have been created. No pricing model updated.' in resp.text
-    assert Pricing.objects.count() == 3
-
-
-def test_pricing_edit_extra_variables(app, admin_user):
-    pricing = Pricing.objects.create(label='Model')
-    assert pricing.extra_variables == {}
-
-    app = login(app)
-    resp = app.get('/manage/pricing/%s/' % pricing.id)
-    assert '<label>Extra variables:</label>' not in resp.text
-    resp = resp.click(href='/manage/pricing/%s/variable/' % pricing.id)
-    resp.form['form-0-key'] = 'foo'
-    resp.form['form-0-value'] = 'bar'
-    resp = resp.form.submit().follow()
-    pricing.refresh_from_db()
-    assert pricing.extra_variables == {'foo': 'bar'}
-    assert '<label>Extra variables:</label>' in resp.text
-    assert '<i>foo</i>' in resp
-
-    resp = resp.click(href='/manage/pricing/%s/variable/' % pricing.id)
-    assert resp.form['form-TOTAL_FORMS'].value == '2'
-    assert resp.form['form-0-key'].value == 'foo'
-    assert resp.form['form-0-value'].value == 'bar'
-    assert resp.form['form-1-key'].value == ''
-    assert resp.form['form-1-value'].value == ''
-    resp.form['form-0-value'] = 'bar-bis'
-    resp.form['form-1-key'] = 'blah'
-    resp.form['form-1-value'] = 'baz'
-    resp = resp.form.submit().follow()
-    pricing.refresh_from_db()
-    assert pricing.extra_variables == {
-        'foo': 'bar-bis',
-        'blah': 'baz',
-    }
-    assert '<i>blah</i>, <i>foo</i>' in resp
-
-    resp = resp.click(href='/manage/pricing/%s/variable/' % pricing.id)
-    assert resp.form['form-TOTAL_FORMS'].value == '3'
-    assert resp.form['form-0-key'].value == 'blah'
-    assert resp.form['form-0-value'].value == 'baz'
-    assert resp.form['form-1-key'].value == 'foo'
-    assert resp.form['form-1-value'].value == 'bar-bis'
-    assert resp.form['form-2-key'].value == ''
-    assert resp.form['form-2-value'].value == ''
-    resp.form['form-1-key'] = 'foo'
-    resp.form['form-1-value'] = 'bar'
-    resp.form['form-0-key'] = ''
-    resp = resp.form.submit().follow()
-    pricing.refresh_from_db()
-    assert pricing.extra_variables == {
-        'foo': 'bar',
-    }
-    assert '<i>foo</i>' in resp
-
-
-def test_pricing_edit_extra_variables_as_manager(app, manager_user):
-    pricing = Pricing.objects.create(label='Model')
-
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/%s/variable/' % pricing.pk, status=403)
-
-
-def test_pricing_add_category(app, admin_user):
-    pricing = Pricing.objects.create(label='Model')
-    category1 = CriteriaCategory.objects.create(label='Cat 1')
-    category2 = CriteriaCategory.objects.create(label='Cat 2')
-    category3 = CriteriaCategory.objects.create(label='Cat 3')
-    category4 = CriteriaCategory.objects.create(label='Cat 4')
-
-    app = login(app)
-    resp = app.get('/manage/pricing/%s/' % pricing.pk)
-    resp = resp.click(href='/manage/pricing/%s/category/add/' % pricing.pk)
-    assert list(resp.context['form'].fields['category'].queryset) == [
-        category1,
-        category2,
-        category3,
-        category4,
-    ]
-    resp.form['category'] = category1.pk
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/pricing/%s/' % pricing.pk)
-    resp = resp.follow()
-    assert '/manage/pricing/%s/category/add/' % pricing.pk in resp
-    assert list(
-        PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('category', flat=True)
-    ) == [category1.pk]
-    assert list(PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('order', flat=True)) == [
-        1
-    ]
-
-    resp = app.get('/manage/pricing/%s/category/add/' % pricing.pk)
-    assert list(resp.context['form'].fields['category'].queryset) == [category2, category3, category4]
-    resp.form['category'] = category4.pk
-    resp = resp.form.submit().follow()
-    assert list(
-        PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('category', flat=True)
-    ) == [category1.pk, category4.pk]
-    assert list(PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('order', flat=True)) == [
-        1,
-        2,
-    ]
-
-    resp = app.get('/manage/pricing/%s/category/add/' % pricing.pk)
-    assert list(resp.context['form'].fields['category'].queryset) == [category2, category3]
-    resp.form['category'] = category2.pk
-    resp = resp.form.submit().follow()
-    assert '/manage/pricing/%s/category/add/' % pricing.pk not in resp
-    assert list(
-        PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('category', flat=True)
-    ) == [category1.pk, category4.pk, category2.pk]
-    assert list(PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('order', flat=True)) == [
-        1,
-        2,
-        3,
-    ]
-
-    app.get('/manage/pricing/%s/category/add/' % pricing.pk, status=404)
-
-
-def test_pricing_add_category_as_manager(app, manager_user):
-    pricing = Pricing.objects.create(label='Model')
-
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/%s/category/add/' % pricing.pk, status=403)
-
-
-def test_pricing_edit_category(app, admin_user):
-    category1 = CriteriaCategory.objects.create(label='Cat 1')
-    criteria1 = Criteria.objects.create(label='Crit 1', category=category1)
-    criteria2 = Criteria.objects.create(label='Crit 2', category=category1)
-    criteria3 = Criteria.objects.create(label='Crit 3', category=category1)
-    criteria4 = Criteria.objects.create(label='Crit 4', category=category1)
-    category2 = CriteriaCategory.objects.create(label='cat 2')
-    criteria5 = Criteria.objects.create(label='Crit 5', category=category2)
-    pricing = Pricing.objects.create(label='Model')
-    pricing.categories.add(category1, through_defaults={'order': 1})
-    pricing.categories.add(category2, through_defaults={'order': 2})
-
-    app = login(app)
-    resp = app.get('/manage/pricing/%s/' % pricing.pk)
-    resp = resp.click(href='/manage/pricing/%s/category/%s/edit/' % (pricing.pk, category1.pk))
-    assert list(resp.context['form'].fields['criterias'].queryset) == [
-        criteria1,
-        criteria2,
-        criteria3,
-        criteria4,
-    ]
-    assert list(resp.context['form'].initial['criterias']) == []
-    resp.form['criterias'] = [criteria1.pk, criteria3.pk]
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/pricing/%s/' % pricing.pk)
-    resp = resp.follow()
-    assert list(pricing.criterias.order_by('pk')) == [criteria1, criteria3]
-
-    resp = app.get('/manage/pricing/%s/category/%s/edit/' % (pricing.pk, category1.pk))
-    assert list(resp.context['form'].initial['criterias']) == [criteria1, criteria3]
-    resp.form['criterias'] = [criteria1.pk, criteria4.pk]
-    resp = resp.form.submit().follow()
-    assert list(pricing.criterias.order_by('pk')) == [criteria1, criteria4]
-
-    resp = app.get('/manage/pricing/%s/category/%s/edit/' % (pricing.pk, category2.pk))
-    assert list(resp.context['form'].fields['criterias'].queryset) == [criteria5]
-    assert list(resp.context['form'].initial['criterias']) == []
-    resp.form['criterias'] = [criteria5.pk]
-    resp = resp.form.submit().follow()
-    assert list(pricing.criterias.order_by('pk')) == [criteria1, criteria4, criteria5]
-
-
-def test_pricing_edit_category_as_manager(app, manager_user):
-    pricing = Pricing.objects.create(label='Model')
-    category = CriteriaCategory.objects.create(label='Cat')
-    pricing.categories.add(category, through_defaults={'order': 1})
-
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/%s/category/%s/edit/' % (pricing.pk, category.pk), status=403)
-
-
-def test_pricing_delete_category(app, admin_user):
-    category1 = CriteriaCategory.objects.create(label='Cat 1')
-    criteria1 = Criteria.objects.create(label='Crit 1', category=category1)
-    category2 = CriteriaCategory.objects.create(label='Cat 2')
-    criteria2 = Criteria.objects.create(label='Crit 2', category=category2)
-    pricing = Pricing.objects.create(label='Model')
-    pricing.categories.add(category1, through_defaults={'order': 1})
-    pricing.categories.add(category2, through_defaults={'order': 2})
-    pricing.criterias.add(criteria1, criteria2)
-
-    app = login(app)
-    resp = app.get('/manage/pricing/%s/' % pricing.pk)
-    resp = resp.click(href='/manage/pricing/%s/category/%s/delete/' % (pricing.pk, category1.pk))
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/pricing/%s/' % pricing.pk)
-    resp = resp.follow()
-    assert list(pricing.categories.all()) == [category2]
-    assert list(pricing.criterias.all()) == [criteria2]
-
-    # not linked
-    app.get('/manage/pricing/%s/category/%s/delete/' % (pricing.pk, category1.pk), status=404)
-    # unknown
-    app.get('/manage/pricing/%s/category/%s/delete/' % (pricing.pk, 0), status=404)
-
-
-def test_pricing_delete_category_as_manager(app, manager_user):
-    pricing = Pricing.objects.create(label='Model')
-    category = CriteriaCategory.objects.create(label='Cat')
-
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/%s/category/%s/delete/' % (pricing.pk, category.pk), status=403)
-
-
-def test_pricing_reorder_categories(app, admin_user):
-    category1 = CriteriaCategory.objects.create(label='Cat 1')
-    category2 = CriteriaCategory.objects.create(label='Cat 2')
-    category3 = CriteriaCategory.objects.create(label='Cat 3')
-    category4 = CriteriaCategory.objects.create(label='Cat 4')
-    pricing = Pricing.objects.create(label='Model')
-    pricing.categories.add(category1, through_defaults={'order': 1})
-    pricing.categories.add(category2, through_defaults={'order': 2})
-    pricing.categories.add(category3, through_defaults={'order': 3})
-    assert list(
-        PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('category', flat=True)
-    ) == [category1.pk, category2.pk, category3.pk]
-    assert list(PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('order', flat=True)) == [
-        1,
-        2,
-        3,
-    ]
-
-    app = login(app)
-    # missing get params
-    app.get('/manage/pricing/%s/order/' % (pricing.pk), status=400)
-
-    # bad new-order param
-    bad_params = [
-        # missing category3 in order
-        ','.join(str(x) for x in [category1.pk, category2.pk]),
-        # category1 mentionned twice
-        ','.join(str(x) for x in [category1.pk, category2.pk, category3.pk, category1.pk]),
-        # category4 not in pricing categories
-        ','.join(str(x) for x in [category1.pk, category2.pk, category3.pk, category4.pk]),
-        # not an id
-        'foo,1,2,3',
-        ' 1 ,2,3',
-    ]
-    for bad_param in bad_params:
-        app.get(
-            '/manage/pricing/%s/order/' % (pricing.pk),
-            params={'new-order': bad_param},
-            status=400,
-        )
-    # not changed
-    assert list(
-        PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('category', flat=True)
-    ) == [category1.pk, category2.pk, category3.pk]
-    assert list(PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('order', flat=True)) == [
-        1,
-        2,
-        3,
-    ]
-
-    # change order
-    app.get(
-        '/manage/pricing/%s/order/' % (pricing.pk),
-        params={'new-order': ','.join(str(x) for x in [category3.pk, category1.pk, category2.pk])},
-    )
-    assert list(
-        PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('category', flat=True)
-    ) == [category3.pk, category1.pk, category2.pk]
-    assert list(PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('order', flat=True)) == [
-        1,
-        2,
-        3,
-    ]
-
-
-def test_pricing_reorder_categories_as_manager(app, manager_user):
-    pricing = Pricing.objects.create(label='Model')
-
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/%s/order/' % (pricing.pk), status=403)
-
-
-def test_list_criterias_as_manager(app, manager_user):
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/criterias/', status=403)
-
-
-def test_add_category(settings, app, admin_user):
-    app = login(app)
-    resp = app.get('/manage/')
-    resp = resp.click('Pricing')
-    resp = resp.click('Criterias')
-    resp = resp.click('New category')
-    resp.form['label'] = 'QF'
-    resp = resp.form.submit()
-    category = CriteriaCategory.objects.latest('pk')
-    assert resp.location.endswith('/manage/pricing/criterias/')
-    assert category.label == 'QF'
-    assert category.slug == 'qf'
-
-
-def test_add_category_as_manager(app, manager_user):
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/criteria/category/add/', status=403)
-
-
-def test_edit_category(app, admin_user):
-    category = CriteriaCategory.objects.create(label='QF')
-    category2 = CriteriaCategory.objects.create(label='Domicile')
-
-    app = login(app)
-    resp = app.get('/manage/pricing/criterias/')
-    resp = resp.click(href='/manage/pricing/criteria/category/%s/edit/' % category.pk)
-    resp.form['label'] = 'QF Foo'
-    resp.form['slug'] = category2.slug
-    resp = resp.form.submit()
-    assert resp.context['form'].errors['slug'] == ['Criteria category with this Identifier already exists.']
-
-    resp.form['slug'] = 'baz2'
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/pricing/criterias/')
-    category.refresh_from_db()
-    assert category.label == 'QF Foo'
-    assert category.slug == 'baz2'
-
-
-def test_edit_category_as_manager(app, manager_user):
-    category = CriteriaCategory.objects.create(label='Foo bar')
-
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/criteria/category/%s/edit/' % category.pk, status=403)
-
-
-def test_delete_category(app, admin_user):
-    category = CriteriaCategory.objects.create(label='QF')
-    Criteria.objects.create(label='QF 1', category=category)
-
-    app = login(app)
-    resp = app.get('/manage/pricing/criterias/')
-    resp = resp.click(href='/manage/pricing/criteria/category/%s/delete/' % category.pk)
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/pricing/criterias/')
-    assert CriteriaCategory.objects.exists() is False
-    assert Criteria.objects.exists() is False
-
-
-def test_delete_category_as_manager(app, manager_user):
-    category = CriteriaCategory.objects.create(label='Foo bar')
-
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/criteria/category/%s/delete/' % category.pk, status=403)
-
-
-def test_add_criteria(app, admin_user):
-    category = CriteriaCategory.objects.create(label='QF')
-
-    app = login(app)
-    resp = app.get('/manage/pricing/criterias/')
-    resp = resp.click('Add a criteria')
-    resp.form['label'] = 'QF < 1'
-    resp.form['condition'] = 'qf < 1 #'
-    assert 'slug' not in resp.context['form'].fields
-    resp = resp.form.submit()
-    assert resp.context['form'].errors['condition'] == ['Invalid syntax.']
-    resp.form['condition'] = 'qf < 1'
-    resp = resp.form.submit()
-    criteria = Criteria.objects.latest('pk')
-    assert resp.location.endswith('/manage/pricing/criterias/')
-    assert criteria.label == 'QF < 1'
-    assert criteria.category == category
-    assert criteria.slug == 'qf-1'
-    assert criteria.condition == 'qf < 1'
-    assert criteria.order == 1
-
-    resp = app.get('/manage/pricing/criteria/category/%s/add/' % category.pk)
-    resp.form['label'] = 'QF < 1'
-    resp.form['condition'] = 'qf < 1'
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/pricing/criterias/')
-    criteria = Criteria.objects.latest('pk')
-    assert criteria.label == 'QF < 1'
-    assert criteria.category == category
-    assert criteria.slug == 'qf-1-1'
-    assert criteria.condition == 'qf < 1'
-    assert criteria.order == 2
-
-
-def test_add_criteria_as_manager(app, manager_user):
-    category = CriteriaCategory.objects.create(label='Foo bar')
-
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/criteria/category/%s/add/' % category.pk, status=403)
-
-
-def test_edit_criteria(app, admin_user):
-    category = CriteriaCategory.objects.create(label='QF')
-    criteria = Criteria.objects.create(label='QF 1', category=category)
-    criteria2 = Criteria.objects.create(label='QF 2', category=category)
-    category2 = CriteriaCategory.objects.create(label='Foo')
-    criteria3 = Criteria.objects.create(label='foo-bar', category=category2)
-
-    app = login(app)
-    resp = app.get('/manage/pricing/criterias/')
-    resp = resp.click(href='/manage/pricing/criteria/category/%s/%s/edit/' % (category.pk, criteria.pk))
-    resp.form['label'] = 'QF 1 bis'
-    resp.form['slug'] = criteria2.slug
-    resp.form['condition'] = 'qf <= 1 #'
-    resp = resp.form.submit()
-    assert resp.context['form'].errors['slug'] == ['Another criteria exists with the same identifier.']
-    assert resp.context['form'].errors['condition'] == ['Invalid syntax.']
-
-    resp.form['condition'] = 'qf <= 1'
-    resp.form['slug'] = criteria3.slug
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/pricing/criterias/')
-    criteria.refresh_from_db()
-    assert criteria.label == 'QF 1 bis'
-    assert criteria.slug == 'foo-bar'
-    assert criteria.condition == 'qf <= 1'
-
-
-def test_edit_criteria_as_manager(app, manager_user):
-    category = CriteriaCategory.objects.create(label='QF')
-    criteria = Criteria.objects.create(label='QF 1', category=category)
-
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/criteria/category/%s/%s/edit/' % (category.pk, criteria.pk), status=403)
-
-
-def test_delete_criteria(app, admin_user):
-    category = CriteriaCategory.objects.create(label='QF')
-    criteria = Criteria.objects.create(label='QF 1', category=category)
-
-    app = login(app)
-    resp = app.get('/manage/pricing/criterias/')
-    resp = resp.click(href='/manage/pricing/criteria/category/%s/%s/delete/' % (category.pk, criteria.pk))
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/pricing/criterias/')
-    assert CriteriaCategory.objects.exists() is True
-    assert Criteria.objects.exists() is False
-
-
-def test_delete_criteria_as_manager(app, manager_user):
-    category = CriteriaCategory.objects.create(label='QF')
-    criteria = Criteria.objects.create(label='QF 1', category=category)
-
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/criteria/category/%s/%s/delete/' % (category.pk, criteria.pk), status=403)
-
-
-def test_reorder_criterias(app, admin_user):
-    category = CriteriaCategory.objects.create(label='QF')
-    criteria1 = Criteria.objects.create(label='QF 1', category=category)
-    criteria2 = Criteria.objects.create(label='QF 2', category=category)
-    criteria3 = Criteria.objects.create(label='QF 3', category=category)
-    criteria4 = Criteria.objects.create(label='QF 4', category=category)
-    assert list(category.criterias.values_list('pk', flat=True).order_by('order')) == [
-        criteria1.pk,
-        criteria2.pk,
-        criteria3.pk,
-        criteria4.pk,
-    ]
-    assert list(category.criterias.values_list('order', flat=True).order_by('order')) == [1, 2, 3, 4]
-
-    app = login(app)
-    # missing get params
-    app.get('/manage/pricing/criteria/category/%s/order/' % (category.pk), status=400)
-
-    # bad new-order param
-    bad_params = [
-        # missing criteria3 in order
-        ','.join(str(x) for x in [criteria1.pk, criteria2.pk, criteria4.pk]),
-        # criteria1 mentionned twice
-        ','.join(str(x) for x in [criteria1.pk, criteria2.pk, criteria3.pk, criteria4.pk, criteria1.pk]),
-        # not an id
-        'foo,1,2,3,4',
-        ' 1 ,2,3,4',
-    ]
-    for bad_param in bad_params:
-        app.get(
-            '/manage/pricing/criteria/category/%s/order/' % (category.pk),
-            params={'new-order': bad_param},
-            status=400,
-        )
-    # not changed
-    assert list(category.criterias.values_list('pk', flat=True).order_by('order')) == [
-        criteria1.pk,
-        criteria2.pk,
-        criteria3.pk,
-        criteria4.pk,
-    ]
-    assert list(category.criterias.values_list('order', flat=True).order_by('order')) == [1, 2, 3, 4]
-
-    # change order
-    app.get(
-        '/manage/pricing/criteria/category/%s/order/' % (category.pk),
-        params={
-            'new-order': ','.join(str(x) for x in [criteria3.pk, criteria1.pk, criteria4.pk, criteria2.pk])
-        },
-    )
-    assert list(category.criterias.values_list('pk', flat=True).order_by('order')) == [
-        criteria3.pk,
-        criteria1.pk,
-        criteria4.pk,
-        criteria2.pk,
-    ]
-    assert list(category.criterias.values_list('order', flat=True).order_by('order')) == [1, 2, 3, 4]
-
-
-def test_reorder_criterias_as_manager(app, manager_user):
-    category = CriteriaCategory.objects.create(label='QF')
-
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/criteria/category/%s/order/' % (category.pk), status=403)
-
-
-@pytest.mark.freeze_time('2021-07-08')
-def test_import_criteria_category(app, admin_user):
-    category = CriteriaCategory.objects.create(label='Foo bar')
-    Criteria.objects.create(label='Foo', category=category)
-    Criteria.objects.create(label='Baz', category=category)
-
-    app = login(app)
-    resp = app.get('/manage/pricing/criteria/category/%s/export/' % category.id)
-    assert resp.headers['content-type'] == 'application/json'
-    assert (
-        resp.headers['content-disposition']
-        == 'attachment; filename="export_pricing_category_foo-bar_20210708.json"'
-    )
-    category_export = resp.text
-
-    # existing category
-    resp = app.get('/manage/', status=200)
-    resp = resp.click('Import')
-    resp.form['agendas_json'] = Upload('export.json', category_export.encode('utf-8'), 'application/json')
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/pricing/criterias/')
-    resp = resp.follow()
-    assert (
-        'No pricing criteria category created. A pricing criteria category has been updated.' not in resp.text
-    )
-    assert CriteriaCategory.objects.count() == 1
-    assert Criteria.objects.count() == 2
-
-    # new category
-    CriteriaCategory.objects.all().delete()
-    resp = app.get('/manage/', status=200)
-    resp = resp.click('Import')
-    resp.form['agendas_json'] = Upload('export.json', category_export.encode('utf-8'), 'application/json')
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/pricing/criterias/')
-    resp = resp.follow()
-    assert (
-        'A pricing criteria category has been created. No pricing criteria category updated.' not in resp.text
-    )
-    assert CriteriaCategory.objects.count() == 1
-    assert Criteria.objects.count() == 2
-
-    # multiple categories
-    categories = json.loads(category_export)
-    categories['pricing_categories'].append(copy.copy(categories['pricing_categories'][0]))
-    categories['pricing_categories'].append(copy.copy(categories['pricing_categories'][0]))
-    categories['pricing_categories'][1]['label'] = 'Foo bar 2'
-    categories['pricing_categories'][1]['slug'] = 'foo-bar-2'
-    categories['pricing_categories'][2]['label'] = 'Foo bar 3'
-    categories['pricing_categories'][2]['slug'] = 'foo-bar-3'
-
-    resp = app.get('/manage/', status=200)
-    resp = resp.click('Import')
-    resp.form['agendas_json'] = Upload(
-        'export.json', json.dumps(categories).encode('utf-8'), 'application/json'
-    )
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/')
-    resp = resp.follow()
-    assert (
-        '2 pricing criteria categories have been created. A pricing criteria category has been updated.'
-        in resp.text
-    )
-    assert CriteriaCategory.objects.count() == 3
-    assert Criteria.objects.count() == 6
-
-    CriteriaCategory.objects.all().delete()
-    resp = app.get('/manage/', status=200)
-    resp = resp.click('Import')
-    resp.form['agendas_json'] = Upload(
-        'export.json', json.dumps(categories).encode('utf-8'), 'application/json'
-    )
-    resp = resp.form.submit().follow()
-    assert (
-        '3 pricing criteria categories have been created. No pricing criteria category updated.' in resp.text
-    )
-    assert CriteriaCategory.objects.count() == 3
-    assert Criteria.objects.count() == 6
-
-
-def test_add_agenda_pricing(settings, app, admin_user):
-    agenda = Agenda.objects.create(label='Foo Bar')
-    pricing = Pricing.objects.create(label='Model')
-
-    app = login(app)
-    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
-    resp = resp.click('New pricing')
-    resp.form['pricing'] = pricing.pk
-    resp.form['date_start'] = '2021-09-01'
-    resp.form['date_end'] = '2021-09-01'
-    resp = resp.form.submit()
-    assert resp.context['form'].errors['date_end'] == ['End date must be greater than start date.']
-    resp.form['date_end'] = '2022-09-01'
-    resp = resp.form.submit()
-    agenda_pricing = AgendaPricing.objects.latest('pk')
-    assert resp.location.endswith('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
-    assert agenda_pricing.pricing == pricing
-    assert agenda_pricing.agenda == agenda
-    assert agenda_pricing.date_start == datetime.date(2021, 9, 1)
-    assert agenda_pricing.date_end == datetime.date(2022, 9, 1)
-
-    resp = app.get('/manage/pricing/agenda/%s/pricing/add/' % agenda.pk)
-    resp.form['pricing'] = pricing.pk
-    resp.form['date_start'] = '2021-11-01'
-    resp.form['date_end'] = '2022-11-01'
-    resp = resp.form.submit()
-    assert resp.context['form'].errors['__all__'] == ['Pricing overlaps existing pricings.']
-    resp.form['date_start'] = '2022-09-01'
-    resp.form['date_end'] = '2023-09-01'
-    resp = resp.form.submit()
-    agenda_pricing = AgendaPricing.objects.latest('pk')
-    assert agenda_pricing.pricing == pricing
-    assert agenda_pricing.agenda == agenda
-    assert agenda_pricing.date_start == datetime.date(2022, 9, 1)
-    assert agenda_pricing.date_end == datetime.date(2023, 9, 1)
-
-    settings.CHRONO_ENABLE_PRICING = False
-    resp = app.get('/manage/')
-    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
-    assert 'New pricing' not in resp
-
-
-def test_add_agenda_pricing_as_manager(app, manager_user, agenda_with_restrictions):
-    app = login(app, username='manager', password='manager')
-    app.get('/manage/pricing/agenda/%s/pricing/add/' % agenda_with_restrictions.pk, status=403)
-
-
-def test_edit_agenda_pricing(app, admin_user):
-    agenda = Agenda.objects.create(label='Foo Bar')
-    pricing = Pricing.objects.create(label='Model')
-    pricing2 = Pricing.objects.create(label='Model 2')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2022, month=9, day=1),
-    )
-    agenda2 = Agenda.objects.create(label='Foo Bar')
-    agenda_pricing2 = AgendaPricing.objects.create(
-        agenda=agenda2,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2022, month=9, day=1),
-    )
-    AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2022, month=9, day=1),
-        date_end=datetime.date(year=2023, month=9, day=1),
-    )
-
-    app = login(app)
-    resp = app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
-    resp = resp.click(href='/manage/pricing/agenda/%s/pricing/%s/edit/' % (agenda.pk, agenda_pricing.pk))
-    resp.form['pricing'] = pricing2.pk
-    resp.form['date_start'] = '2021-09-01'
-    resp.form['date_end'] = '2021-09-01'
-    resp = resp.form.submit()
-    assert resp.context['form'].errors['date_end'] == ['End date must be greater than start date.']
-    resp.form['date_start'] = '2021-11-01'
-    resp.form['date_end'] = '2022-11-01'
-    resp = resp.form.submit()
-    assert resp.context['form'].errors['__all__'] == ['Pricing overlaps existing pricings.']
-    resp.form['date_start'] = '2021-08-01'
-    resp.form['date_end'] = '2022-09-01'
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
-    agenda_pricing.refresh_from_db()
-    assert agenda_pricing.pricing == pricing2
-    assert agenda_pricing.agenda == agenda
-    assert agenda_pricing.date_start == datetime.date(2021, 8, 1)
-    assert agenda_pricing.date_end == datetime.date(2022, 9, 1)
-
-    app.get('/manage/pricing/agenda/%s/pricing/%s/edit/' % (agenda.pk, agenda_pricing2.pk), status=404)
-    app.get('/manage/pricing/agenda/%s/pricing/%s/edit/' % (0, agenda_pricing.pk), status=404)
-    app.get('/manage/pricing/agenda/%s/pricing/%s/edit/' % (agenda.pk, 0), status=404)
-    # wrong kind
-    for kind in ['meetings', 'virtual']:
-        agenda.kind = kind
-        agenda.save()
-        app.get('/manage/pricing/agenda/%s/pricing/%s/edit/' % (agenda.pk, agenda_pricing.pk), status=404)
-
-
-def test_edit_agenda_pricing_as_manager(app, manager_user, agenda_with_restrictions):
-    pricing = Pricing.objects.create(label='Model')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda_with_restrictions,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    app = login(app, username='manager', password='manager')
-    app.get(
-        '/manage/pricing/agenda/%s/pricing/%s/edit/' % (agenda_with_restrictions.pk, agenda_pricing.pk),
-        status=403,
-    )
-
-    resp = app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda_with_restrictions.pk, agenda_pricing.pk))
-    assert (
-        '/manage/pricing/agenda/%s/pricing/%s/edit/' % (agenda_with_restrictions.pk, agenda_pricing.pk)
-        not in resp
-    )
-
-
-def test_delete_agenda_pricing_as_manager(app, manager_user, agenda_with_restrictions):
-    pricing = Pricing.objects.create(label='Model')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda_with_restrictions,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    app = login(app, username='manager', password='manager')
-    app.get(
-        '/manage/pricing/agenda/%s/pricing/%s/delete/' % (agenda_with_restrictions.pk, agenda_pricing.pk),
-        status=403,
-    )
-
-    resp = app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda_with_restrictions.pk, agenda_pricing.pk))
-    assert (
-        '/manage/pricing/agenda/%s/pricing/%s/delete/' % (agenda_with_restrictions.pk, agenda_pricing.pk)
-        not in resp
-    )
-
-
-def test_delete_agenda_pricing(app, admin_user):
-    agenda = Agenda.objects.create(label='Foo Bar')
-    pricing = Pricing.objects.create(label='Model')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2022, month=9, day=1),
-    )
-    agenda2 = Agenda.objects.create(label='Foo Bar')
-    agenda_pricing2 = AgendaPricing.objects.create(
-        agenda=agenda2,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2022, month=9, day=1),
-    )
-
-    app = login(app)
-    app.get('/manage/pricing/agenda/%s/pricing/%s/delete/' % (agenda.pk, agenda_pricing2.pk), status=404)
-    app.get('/manage/pricing/agenda/%s/pricing/%s/delete/' % (0, agenda_pricing.pk), status=404)
-    app.get('/manage/pricing/agenda/%s/pricing/%s/delete/' % (agenda.pk, 0), status=404)
-    # wrong kind
-    for kind in ['meetings', 'virtual']:
-        agenda.kind = kind
-        agenda.save()
-        app.get('/manage/pricing/agenda/%s/pricing/%s/delete/' % (agenda.pk, agenda_pricing.pk), status=404)
-
-    agenda.kind = 'events'
-    agenda.save()
-    resp = app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
-    resp = resp.click(href='/manage/pricing/agenda/%s/pricing/%s/delete/' % (agenda.pk, agenda_pricing.pk))
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.pk)
-    assert AgendaPricing.objects.filter(pk=agenda_pricing.pk).exists() is False
-
-
-def test_detail_agenda_pricing(app, admin_user):
-    agenda = Agenda.objects.create(label='Foo Bar')
-    pricing = Pricing.objects.create(label='Model')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    agenda2 = Agenda.objects.create(label='Foo Bar')
-    agenda_pricing2 = AgendaPricing.objects.create(
-        agenda=agenda2,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-
-    app = login(app)
-    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
-    resp = resp.click(href='/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
-
-    app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing2.pk), status=404)
-    app.get('/manage/pricing/agenda/%s/pricing/%s/' % (0, agenda_pricing.pk), status=404)
-    app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, 0), status=404)
-    # wrong kind
-    for kind in ['meetings', 'virtual']:
-        agenda.kind = kind
-        agenda.save()
-        app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.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)
-    Criteria.objects.create(label='Crit 1-2', slug='crit-1-2', category=category1, order=2)
-    category2 = CriteriaCategory.objects.create(label='Cat 2')
-    Criteria.objects.create(label='Crit 2-1', slug='crit-2-1', category=category2, order=1)
-    Criteria.objects.create(label='Crit 2-2', slug='crit-2-2', category=category2, order=2)
-    Criteria.objects.create(label='Crit 2-3', slug='crit-2-3', category=category2, order=3)
-    category3 = CriteriaCategory.objects.create(label='Cat 3')
-    Criteria.objects.create(label='Crit 3-1', slug='crit-3-1', category=category3, order=1)
-    Criteria.objects.create(label='Crit 3-3', slug='crit-3-3', category=category3, order=3)
-    Criteria.objects.create(label='Crit 3-4', slug='crit-3-4', category=category3, order=4)
-    Criteria.objects.create(label='Crit 3-2', slug='crit-3-2', category=category3, order=2)
-
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    pricing = Pricing.objects.create(label='Foo bar')
-    pricing.categories.add(category1, through_defaults={'order': 1})
-    pricing.categories.add(category2, through_defaults={'order': 2})
-    pricing.categories.add(category3, through_defaults={'order': 3})
-    pricing.criterias.set(Criteria.objects.all())
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-        pricing_data={
-            'cat-1:crit-1-1': {
-                'cat-2:crit-2-1': {
-                    'cat-3:crit-3-1': 111,
-                    'cat-3:crit-3-3': 'not-a-decimal',
-                    'cat-3:crit-3-4': 114,
-                },
-                'cat-2:crit-2-3': {
-                    'cat-3:crit-3-2': 132,
-                },
-            },
-            'cat-1:crit-1-2': {
-                'cat-2:crit-2-2': {
-                    'cat-3:crit-3-3': 223,
-                },
-            },
-        },
-    )
-
-    app = login(app)
-    resp = app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
-    assert '<h3>Crit 1-1</h3>' in resp
-    ths = resp.pyquery.find('table.pricing-matrix-crit-1-1 thead th')
-    assert len(ths) == 4
-    assert ths[0].text is None
-    assert ths[1].text == 'Crit 2-1'
-    assert ths[2].text == 'Crit 2-2'
-    assert ths[3].text == 'Crit 2-3'
-    assert resp.pyquery.find('table.pricing-matrix-crit-1-1 tr.pricing-row-crit-3-1 th')[0].text == 'Crit 3-1'
-    assert resp.pyquery.find('table.pricing-matrix-crit-1-1 tr.pricing-row-crit-3-2 th')[0].text == 'Crit 3-2'
-    assert resp.pyquery.find('table.pricing-matrix-crit-1-1 tr.pricing-row-crit-3-3 th')[0].text == 'Crit 3-3'
-    assert resp.pyquery.find('table.pricing-matrix-crit-1-1 tr.pricing-row-crit-3-4 th')[0].text == 'Crit 3-4'
-    assert (
-        resp.pyquery.find('table.pricing-matrix-crit-1-1 tr.pricing-row-crit-3-1 td.pricing-cell-crit-2-1')[
-            0
-        ].text
-        == '111.00'
-    )
-    assert (
-        resp.pyquery.find('table.pricing-matrix-crit-1-1 tr.pricing-row-crit-3-2 td.pricing-cell-crit-2-1')[
-            0
-        ].text
-        is None
-    )  # not defined
-    assert (
-        resp.pyquery.find('table.pricing-matrix-crit-1-1 tr.pricing-row-crit-3-3 td.pricing-cell-crit-2-1')[
-            0
-        ].text
-        is None
-    )  # wrong value
-    assert (
-        resp.pyquery.find('table.pricing-matrix-crit-1-1 tr.pricing-row-crit-3-4 td.pricing-cell-crit-2-1')[
-            0
-        ].text
-        == '114.00'
-    )
-    assert (
-        resp.pyquery.find('table.pricing-matrix-crit-1-1 tr.pricing-row-crit-3-2 td.pricing-cell-crit-2-3')[
-            0
-        ].text
-        == '132.00'
-    )
-    assert '<h3>Crit 1-2</h3>' in resp
-    ths = resp.pyquery.find('table.pricing-matrix-crit-1-2 thead th')
-    assert len(ths) == 4
-    assert ths[0].text is None
-    assert ths[1].text == 'Crit 2-1'
-    assert ths[2].text == 'Crit 2-2'
-    assert ths[3].text == 'Crit 2-3'
-    assert resp.pyquery.find('table.pricing-matrix-crit-1-2 tr.pricing-row-crit-3-1 th')[0].text == 'Crit 3-1'
-    assert resp.pyquery.find('table.pricing-matrix-crit-1-2 tr.pricing-row-crit-3-2 th')[0].text == 'Crit 3-2'
-    assert resp.pyquery.find('table.pricing-matrix-crit-1-2 tr.pricing-row-crit-3-3 th')[0].text == 'Crit 3-3'
-    assert resp.pyquery.find('table.pricing-matrix-crit-1-2 tr.pricing-row-crit-3-4 th')[0].text == 'Crit 3-4'
-    assert (
-        resp.pyquery.find('table.pricing-matrix-crit-1-2 tr.pricing-row-crit-3-2 td.pricing-cell-crit-2-2')[
-            0
-        ].text
-        is None
-    )  # not defined
-    assert (
-        resp.pyquery.find('table.pricing-matrix-crit-1-2 tr.pricing-row-crit-3-3 td.pricing-cell-crit-2-2')[
-            0
-        ].text
-        == '223.00'
-    )
-
-
-def test_detail_agenda_pricing_2_categories(app, admin_user):
-    category2 = CriteriaCategory.objects.create(label='Cat 2')
-    Criteria.objects.create(label='Crit 2-1', slug='crit-2-1', category=category2, order=1)
-    Criteria.objects.create(label='Crit 2-2', slug='crit-2-2', category=category2, order=2)
-    Criteria.objects.create(label='Crit 2-3', slug='crit-2-3', category=category2, order=3)
-    category3 = CriteriaCategory.objects.create(label='Cat 3')
-    Criteria.objects.create(label='Crit 3-1', slug='crit-3-1', category=category3, order=1)
-    Criteria.objects.create(label='Crit 3-3', slug='crit-3-3', category=category3, order=3)
-    Criteria.objects.create(label='Crit 3-4', slug='crit-3-4', category=category3, order=4)
-    Criteria.objects.create(label='Crit 3-2', slug='crit-3-2', category=category3, order=2)
-
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    pricing = Pricing.objects.create(label='Foo bar')
-    pricing.categories.add(category2, through_defaults={'order': 2})
-    pricing.categories.add(category3, through_defaults={'order': 3})
-    pricing.criterias.set(Criteria.objects.all())
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-        pricing_data={
-            'cat-2:crit-2-1': {
-                'cat-3:crit-3-1': 111,
-                'cat-3:crit-3-3': 'not-a-decimal',
-                'cat-3:crit-3-4': 114,
-            },
-            'cat-2:crit-2-3': {
-                'cat-3:crit-3-2': 132,
-            },
-        },
-    )
-
-    app = login(app)
-    resp = app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
-    assert '<h3>' not in resp
-    ths = resp.pyquery.find('table thead th')
-    assert len(ths) == 4
-    assert ths[0].text is None
-    assert ths[1].text == 'Crit 2-1'
-    assert ths[2].text == 'Crit 2-2'
-    assert ths[3].text == 'Crit 2-3'
-    assert resp.pyquery.find('table tr.pricing-row-crit-3-1 th')[0].text == 'Crit 3-1'
-    assert resp.pyquery.find('table tr.pricing-row-crit-3-2 th')[0].text == 'Crit 3-2'
-    assert resp.pyquery.find('table tr.pricing-row-crit-3-3 th')[0].text == 'Crit 3-3'
-    assert resp.pyquery.find('table tr.pricing-row-crit-3-4 th')[0].text == 'Crit 3-4'
-    assert resp.pyquery.find('table tr.pricing-row-crit-3-1 td.pricing-cell-crit-2-1')[0].text == '111.00'
-    assert (
-        resp.pyquery.find('table tr.pricing-row-crit-3-2 td.pricing-cell-crit-2-1')[0].text is None
-    )  # not defined
-    assert (
-        resp.pyquery.find('table tr.pricing-row-crit-3-3 td.pricing-cell-crit-2-1')[0].text is None
-    )  # wrong value
-    assert resp.pyquery.find('table tr.pricing-row-crit-3-4 td.pricing-cell-crit-2-1')[0].text == '114.00'
-    assert resp.pyquery.find('table tr.pricing-row-crit-3-2 td.pricing-cell-crit-2-3')[0].text == '132.00'
-
-
-def test_detail_agenda_pricing_1_category(app, admin_user):
-    category3 = CriteriaCategory.objects.create(label='Cat 3')
-    Criteria.objects.create(label='Crit 3-1', slug='crit-3-1', category=category3, order=1)
-    Criteria.objects.create(label='Crit 3-3', slug='crit-3-3', category=category3, order=3)
-    Criteria.objects.create(label='Crit 3-4', slug='crit-3-4', category=category3, order=4)
-    Criteria.objects.create(label='Crit 3-2', slug='crit-3-2', category=category3, order=2)
-
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    pricing = Pricing.objects.create(label='Foo bar')
-    pricing.categories.add(category3, through_defaults={'order': 3})
-    pricing.criterias.set(Criteria.objects.all())
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-        pricing_data={
-            'cat-3:crit-3-1': 111,
-            'cat-3:crit-3-3': 'not-a-decimal',
-            'cat-3:crit-3-4': 114,
-        },
-    )
-
-    app = login(app)
-    resp = app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
-    assert '<h3>' not in resp
-    ths = resp.pyquery.find('table thead')
-    assert len(ths) == 0
-    assert resp.pyquery.find('table tr.pricing-row-crit-3-1 th')[0].text == 'Crit 3-1'
-    assert resp.pyquery.find('table tr.pricing-row-crit-3-2 th')[0].text == 'Crit 3-2'
-    assert resp.pyquery.find('table tr.pricing-row-crit-3-3 th')[0].text == 'Crit 3-3'
-    assert resp.pyquery.find('table tr.pricing-row-crit-3-4 th')[0].text == 'Crit 3-4'
-    assert resp.pyquery.find('table tr.pricing-row-crit-3-1 td')[0].text == '111.00'
-    assert resp.pyquery.find('table tr.pricing-row-crit-3-2 td')[0].text is None  # not defined
-    assert resp.pyquery.find('table tr.pricing-row-crit-3-3 td')[0].text is None  # wrong value
-    assert resp.pyquery.find('table tr.pricing-row-crit-3-4 td')[0].text == '114.00'
-
-
-def test_edit_agenda_pricing_matrix_3_categories(app, admin_user):
-    category1 = CriteriaCategory.objects.create(label='Cat 1')
-    criteria11 = Criteria.objects.create(label='Crit 1-1', slug='crit-1-1', category=category1, order=1)
-    criteria12 = Criteria.objects.create(label='Crit 1-2', slug='crit-1-2', category=category1, order=2)
-    category2 = CriteriaCategory.objects.create(label='Cat 2')
-    criteria21 = Criteria.objects.create(label='Crit 2-1', slug='crit-2-1', category=category2, order=1)
-    Criteria.objects.create(label='Crit 2-2', slug='crit-2-2', category=category2, order=2)
-    Criteria.objects.create(label='Crit 2-3', slug='crit-2-3', category=category2, order=3)
-    category3 = CriteriaCategory.objects.create(label='Cat 3')
-    criteria31 = Criteria.objects.create(label='Crit 3-1', slug='crit-3-1', category=category3, order=1)
-    Criteria.objects.create(label='Crit 3-3', slug='crit-3-3', category=category3, order=3)
-    Criteria.objects.create(label='Crit 3-4', slug='crit-3-4', category=category3, order=4)
-    Criteria.objects.create(label='Crit 3-2', slug='crit-3-2', category=category3, order=2)
-
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    pricing = Pricing.objects.create(label='Foo bar')
-    pricing.categories.add(category1, through_defaults={'order': 1})
-    pricing.categories.add(category2, through_defaults={'order': 2})
-    pricing.categories.add(category3, through_defaults={'order': 3})
-    pricing.criterias.set(Criteria.objects.all())
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-        pricing_data={
-            'cat-1:crit-1-1': {
-                'cat-2:crit-2-1': {
-                    'cat-3:crit-3-1': 111,
-                    'cat-3:crit-3-3': 'not-a-decimal',
-                    'cat-3:crit-3-4': 114,
-                },
-                'cat-2:crit-2-3': {
-                    'cat-3:crit-3-2': 132,
-                },
-            },
-            'cat-1:crit-1-2': {
-                'cat-2:crit-2-2': {
-                    'cat-3:crit-3-3': 223,
-                },
-            },
-        },
-    )
-
-    app = login(app)
-    resp = app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
-    resp = resp.click(
-        href='/manage/pricing/agenda/%s/pricing/%s/matrix/%s/edit/'
-        % (agenda.pk, agenda_pricing.pk, criteria11.slug)
-    )
-    assert resp.form['form-0-crit_0'].value == '111'
-    assert resp.form['form-0-crit_1'].value == ''
-    assert resp.form['form-0-crit_2'].value == ''
-    assert resp.form['form-1-crit_0'].value == ''
-    assert resp.form['form-1-crit_1'].value == ''
-    assert resp.form['form-1-crit_2'].value == '132'
-    assert resp.form['form-2-crit_0'].value == ''
-    assert resp.form['form-2-crit_1'].value == ''
-    assert resp.form['form-2-crit_2'].value == ''
-    assert resp.form['form-3-crit_0'].value == '114'
-    assert resp.form['form-3-crit_1'].value == ''
-    assert resp.form['form-3-crit_2'].value == ''
-    resp.form['form-0-crit_1'] = '121'
-    resp.form['form-0-crit_2'] = '131'
-    resp.form['form-1-crit_0'] = '112'
-    resp.form['form-1-crit_1'] = '122'
-    resp.form['form-1-crit_2'] = '132.5'
-    resp.form['form-2-crit_0'] = '113'
-    resp.form['form-2-crit_1'] = '123'
-    resp.form['form-2-crit_2'] = '133'
-    resp.form['form-3-crit_0'] = '914'
-    resp.form['form-3-crit_1'] = '124'
-    resp.form['form-3-crit_2'] = '134'
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
-    agenda_pricing.refresh_from_db()
-    assert agenda_pricing.pricing_data == {
-        'cat-1:crit-1-1': {
-            'cat-2:crit-2-1': {
-                'cat-3:crit-3-1': 111,
-                'cat-3:crit-3-2': 112,
-                'cat-3:crit-3-3': 113,
-                'cat-3:crit-3-4': 914,
-            },
-            'cat-2:crit-2-2': {
-                'cat-3:crit-3-1': 121,
-                'cat-3:crit-3-2': 122,
-                'cat-3:crit-3-3': 123,
-                'cat-3:crit-3-4': 124,
-            },
-            'cat-2:crit-2-3': {
-                'cat-3:crit-3-1': 131,
-                'cat-3:crit-3-2': 132.5,
-                'cat-3:crit-3-3': 133,
-                'cat-3:crit-3-4': 134,
-            },
-        },
-        'cat-1:crit-1-2': {
-            'cat-2:crit-2-2': {
-                'cat-3:crit-3-3': 223,
-            },
-        },
-    }
-    app.get(
-        '/manage/pricing/agenda/%s/pricing/%s/matrix/%s/edit/'
-        % (agenda.pk, agenda_pricing.pk, criteria12.slug),
-        status=200,
-    )
-
-    agenda2 = Agenda.objects.create(label='Foo Bar')
-    agenda_pricing2 = AgendaPricing.objects.create(
-        agenda=agenda2,
-        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/%s/pricing/%s/matrix/%s/edit/'
-        % (agenda.pk, agenda_pricing2.pk, criteria11.slug),
-        status=404,
-    )
-    app.get(
-        '/manage/pricing/agenda/%s/pricing/%s/matrix/%s/edit/' % (0, agenda_pricing.pk, criteria11.slug),
-        status=404,
-    )
-    app.get(
-        '/manage/pricing/agenda/%s/pricing/%s/matrix/%s/edit/' % (agenda.pk, 0, criteria11.slug), status=404
-    )
-    app.get(
-        '/manage/pricing/agenda/%s/pricing/%s/matrix/%s/edit/' % (agenda.pk, agenda_pricing.pk, 'unknown'),
-        status=404,
-    )
-    app.get(
-        '/manage/pricing/agenda/%s/pricing/%s/matrix/%s/edit/'
-        % (agenda.pk, agenda_pricing.pk, criteria21.slug),
-        status=404,
-    )
-    app.get(
-        '/manage/pricing/agenda/%s/pricing/%s/matrix/%s/edit/'
-        % (agenda.pk, agenda_pricing.pk, criteria31.slug),
-        status=404,
-    )
-    app.get('/manage/pricing/agenda/%s/pricing/%s/matrix/edit/' % (agenda.pk, agenda_pricing.pk), status=404)
-    # wrong kind
-    for kind in ['meetings', 'virtual']:
-        agenda.kind = kind
-        agenda.save()
-        app.get(
-            '/manage/pricing/agenda/%s/pricing/%s/matrix/%s/edit/'
-            % (agenda.pk, agenda_pricing.pk, criteria11.slug),
-            status=404,
-        )
-
-
-def test_edit_agenda_pricing_matrix_2_categories(app, admin_user):
-    category2 = CriteriaCategory.objects.create(label='Cat 2')
-    criteria21 = Criteria.objects.create(label='Crit 2-1', slug='crit-2-1', category=category2, order=1)
-    Criteria.objects.create(label='Crit 2-2', slug='crit-2-2', category=category2, order=2)
-    Criteria.objects.create(label='Crit 2-3', slug='crit-2-3', category=category2, order=3)
-    category3 = CriteriaCategory.objects.create(label='Cat 3')
-    criteria31 = Criteria.objects.create(label='Crit 3-1', slug='crit-3-1', category=category3, order=1)
-    Criteria.objects.create(label='Crit 3-3', slug='crit-3-3', category=category3, order=3)
-    Criteria.objects.create(label='Crit 3-4', slug='crit-3-4', category=category3, order=4)
-    Criteria.objects.create(label='Crit 3-2', slug='crit-3-2', category=category3, order=2)
-
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    pricing = Pricing.objects.create(label='Foo bar')
-    pricing.categories.add(category2, through_defaults={'order': 2})
-    pricing.categories.add(category3, through_defaults={'order': 3})
-    pricing.criterias.set(Criteria.objects.all())
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-        pricing_data={
-            'cat-2:crit-2-1': {
-                'cat-3:crit-3-1': 111,
-                'cat-3:crit-3-3': 'not-a-decimal',
-                'cat-3:crit-3-4': 114,
-            },
-            'cat-2:crit-2-3': {
-                'cat-3:crit-3-2': 132,
-            },
-        },
-    )
-
-    app = login(app)
-    resp = app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
-    resp = resp.click(
-        href='/manage/pricing/agenda/%s/pricing/%s/matrix/edit/' % (agenda.pk, agenda_pricing.pk)
-    )
-    assert resp.form['form-0-crit_0'].value == '111'
-    assert resp.form['form-0-crit_1'].value == ''
-    assert resp.form['form-0-crit_2'].value == ''
-    assert resp.form['form-1-crit_0'].value == ''
-    assert resp.form['form-1-crit_1'].value == ''
-    assert resp.form['form-1-crit_2'].value == '132'
-    assert resp.form['form-2-crit_0'].value == ''
-    assert resp.form['form-2-crit_1'].value == ''
-    assert resp.form['form-2-crit_2'].value == ''
-    assert resp.form['form-3-crit_0'].value == '114'
-    assert resp.form['form-3-crit_1'].value == ''
-    assert resp.form['form-3-crit_2'].value == ''
-    resp.form['form-0-crit_1'] = '121'
-    resp.form['form-0-crit_2'] = '131'
-    resp.form['form-1-crit_0'] = '112'
-    resp.form['form-1-crit_1'] = '122'
-    resp.form['form-1-crit_2'] = '132.5'
-    resp.form['form-2-crit_0'] = '113'
-    resp.form['form-2-crit_1'] = '123'
-    resp.form['form-2-crit_2'] = '133'
-    resp.form['form-3-crit_0'] = '914'
-    resp.form['form-3-crit_1'] = '124'
-    resp.form['form-3-crit_2'] = '134'
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
-    agenda_pricing.refresh_from_db()
-    assert agenda_pricing.pricing_data == {
-        'cat-2:crit-2-1': {
-            'cat-3:crit-3-1': 111,
-            'cat-3:crit-3-2': 112,
-            'cat-3:crit-3-3': 113,
-            'cat-3:crit-3-4': 914,
-        },
-        'cat-2:crit-2-2': {
-            'cat-3:crit-3-1': 121,
-            'cat-3:crit-3-2': 122,
-            'cat-3:crit-3-3': 123,
-            'cat-3:crit-3-4': 124,
-        },
-        'cat-2:crit-2-3': {
-            'cat-3:crit-3-1': 131,
-            'cat-3:crit-3-2': 132.5,
-            'cat-3:crit-3-3': 133,
-            'cat-3:crit-3-4': 134,
-        },
-    }
-
-    agenda2 = Agenda.objects.create(label='Foo Bar')
-    agenda_pricing2 = AgendaPricing.objects.create(
-        agenda=agenda2,
-        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/%s/pricing/%s/matrix/edit/' % (agenda.pk, agenda_pricing2.pk), status=404)
-    app.get('/manage/pricing/agenda/%s/pricing/%s/matrix/edit/' % (0, agenda_pricing.pk), status=404)
-    app.get('/manage/pricing/agenda/%s/pricing/%s/matrix/edit/' % (agenda.pk, 0), status=404)
-    app.get(
-        '/manage/pricing/agenda/%s/pricing/%s/matrix/%s/edit/'
-        % (agenda.pk, agenda_pricing.pk, criteria21.slug),
-        status=404,
-    )
-    app.get(
-        '/manage/pricing/agenda/%s/pricing/%s/matrix/%s/edit/'
-        % (agenda.pk, agenda_pricing.pk, criteria31.slug),
-        status=404,
-    )
-    # wrong kind
-    for kind in ['meetings', 'virtual']:
-        agenda.kind = kind
-        agenda.save()
-        app.get(
-            '/manage/pricing/agenda/%s/pricing/%s/matrix/edit/' % (agenda.pk, agenda_pricing.pk), status=404
-        )
-
-
-def test_edit_agenda_pricing_matrix_1_category(app, admin_user):
-    category3 = CriteriaCategory.objects.create(label='Cat 3')
-    criteria31 = Criteria.objects.create(label='Crit 3-1', slug='crit-3-1', category=category3, order=1)
-    Criteria.objects.create(label='Crit 3-3', slug='crit-3-3', category=category3, order=3)
-    Criteria.objects.create(label='Crit 3-4', slug='crit-3-4', category=category3, order=4)
-    Criteria.objects.create(label='Crit 3-2', slug='crit-3-2', category=category3, order=2)
-
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    pricing = Pricing.objects.create(label='Foo bar')
-    pricing.categories.add(category3, through_defaults={'order': 3})
-    pricing.criterias.set(Criteria.objects.all())
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-        pricing_data={
-            'cat-3:crit-3-1': 111,
-            'cat-3:crit-3-3': 'not-a-decimal',
-            'cat-3:crit-3-4': 114,
-        },
-    )
-
-    app = login(app)
-    resp = app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
-    resp = resp.click(
-        href='/manage/pricing/agenda/%s/pricing/%s/matrix/edit/' % (agenda.pk, agenda_pricing.pk)
-    )
-    assert resp.form['form-0-crit_0'].value == '111'
-    assert resp.form['form-1-crit_0'].value == ''
-    assert resp.form['form-2-crit_0'].value == ''
-    assert resp.form['form-3-crit_0'].value == '114'
-    resp.form['form-1-crit_0'] = '112.5'
-    resp.form['form-2-crit_0'] = '113'
-    resp.form['form-3-crit_0'] = '914'
-    resp = resp.form.submit()
-    assert resp.location.endswith('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
-    agenda_pricing.refresh_from_db()
-    assert agenda_pricing.pricing_data == {
-        'cat-3:crit-3-1': 111,
-        'cat-3:crit-3-2': 112.5,
-        'cat-3:crit-3-3': 113,
-        'cat-3:crit-3-4': 914,
-    }
-
-    agenda2 = Agenda.objects.create(label='Foo Bar')
-    agenda_pricing2 = AgendaPricing.objects.create(
-        agenda=agenda2,
-        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/%s/pricing/%s/matrix/edit/' % (agenda.pk, agenda_pricing2.pk), status=404)
-    app.get('/manage/pricing/agenda/%s/pricing/%s/matrix/edit/' % (0, agenda_pricing.pk), status=404)
-    app.get('/manage/pricing/agenda/%s/pricing/%s/matrix/edit/' % (agenda.pk, 0), status=404)
-    app.get(
-        '/manage/pricing/agenda/%s/pricing/%s/matrix/%s/edit/'
-        % (agenda.pk, agenda_pricing.pk, criteria31.slug),
-        status=404,
-    )
-    # wrong kind
-    for kind in ['meetings', 'virtual']:
-        agenda.kind = kind
-        agenda.save()
-        app.get(
-            '/manage/pricing/agenda/%s/pricing/%s/matrix/edit/' % (agenda.pk, agenda_pricing.pk), status=404
-        )
-
-
-def test_edit_agenda_pricing_matrix_empty(app, admin_user):
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    pricing = Pricing.objects.create(label='Foo bar')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-
-    app = login(app)
-    app.get('/manage/pricing/agenda/%s/pricing/%s/matrix/edit/' % (agenda.pk, agenda_pricing.pk), status=404)
-
-
-def test_edit_agenda_pricing_matrix_as_manager(app, manager_user, agenda_with_restrictions):
-    category1 = CriteriaCategory.objects.create(label='Cat 1')
-    Criteria.objects.create(label='Crit 1-1', slug='crit-1-1', category=category1, order=1)
-    Criteria.objects.create(label='Crit 1-2', slug='crit-1-2', category=category1, order=2)
-    category2 = CriteriaCategory.objects.create(label='Cat 2')
-    category3 = CriteriaCategory.objects.create(label='Cat 3')
-    pricing = Pricing.objects.create(label='Model')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda_with_restrictions,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    pricing.categories.add(category1, through_defaults={'order': 1})
-    pricing.criterias.set(Criteria.objects.all())
-
-    def check():
-        resp = app.get(
-            '/manage/pricing/agenda/%s/pricing/%s/' % (agenda_with_restrictions.pk, agenda_pricing.pk)
-        )
-        assert (
-            '/manage/pricing/agenda/%s/pricing/%s/matrix/edit/'
-            % (agenda_with_restrictions.pk, agenda_pricing.pk)
-            not in resp
-        )
-        for slug in ['crit-1-1', 'crit-1-2']:
-            assert (
-                '/manage/pricing/agenda/%s/pricing/%s/matrix/%s/edit/'
-                % (agenda_with_restrictions.pk, agenda_pricing.pk, slug)
-                not in resp
-            )
-
-    app = login(app, username='manager', password='manager')
-    app.get(
-        '/manage/pricing/agenda/%s/pricing/%s/matrix/edit/'
-        % (agenda_with_restrictions.pk, agenda_pricing.pk),
-        status=403,
-    )
-    check()
-
-    pricing.categories.add(category2, through_defaults={'order': 2})
-    app.get(
-        '/manage/pricing/agenda/%s/pricing/%s/matrix/edit/'
-        % (agenda_with_restrictions.pk, agenda_pricing.pk),
-        status=403,
-    )
-    check()
-
-    pricing.categories.add(category3, through_defaults={'order': 3})
-    app.get(
-        '/manage/pricing/agenda/%s/pricing/%s/matrix/crit-1-1/edit/'
-        % (agenda_with_restrictions.pk, agenda_pricing.pk),
-        status=403,
-    )
-    app.get(
-        '/manage/pricing/agenda/%s/pricing/%s/matrix/crit-1-2/edit/'
-        % (agenda_with_restrictions.pk, agenda_pricing.pk),
-        status=403,
-    )
-    check()
diff --git a/tests/pricing/test_models.py b/tests/pricing/test_models.py
deleted file mode 100644
index 72b36c2e..00000000
--- a/tests/pricing/test_models.py
+++ /dev/null
@@ -1,1477 +0,0 @@
-import datetime
-import json
-from unittest import mock
-
-import pytest
-from django.template import Context
-from django.test.client import RequestFactory
-from django.utils.timezone import make_aware, now
-from publik_django_templatetags.wcs.context_processors import Cards
-
-from chrono.agendas.models import Agenda, Booking, CheckType, CheckTypeGroup, Event, Subscription
-from chrono.pricing.models import (
-    AgendaPricing,
-    AgendaPricingNotFound,
-    Criteria,
-    CriteriaCategory,
-    CriteriaConditionNotFound,
-    Pricing,
-    PricingBookingCheckTypeError,
-    PricingBookingNotCheckedError,
-    PricingCriteriaCategory,
-    PricingDataError,
-    PricingDataFormatError,
-    PricingEventNotCheckedError,
-    PricingMatrix,
-    PricingMatrixCell,
-    PricingMatrixRow,
-    PricingMultipleBookingError,
-    PricingSubscriptionError,
-)
-
-pytestmark = pytest.mark.django_db
-
-
-@pytest.fixture
-def context():
-    return Context(
-        {
-            'cards': Cards(),
-            'request': RequestFactory().get('/'),
-        }
-    )
-
-
-class MockedRequestResponse(mock.Mock):
-    status_code = 200
-
-    def json(self):
-        return json.loads(self.content)
-
-
-def mocked_requests_send(request, **kwargs):
-    data = [{'id': 1, 'fields': {'foo': 'bar'}}, {'id': 2, 'fields': {'foo': 'baz'}}]  # fake result
-    return MockedRequestResponse(content=json.dumps({'data': data}))
-
-
-def test_criteria_category_slug():
-    category = CriteriaCategory.objects.create(label='Foo bar')
-    assert category.slug == 'foo-bar'
-
-
-def test_criteria_category_existing_slug():
-    category = CriteriaCategory.objects.create(label='Foo bar', slug='bar')
-    assert category.slug == 'bar'
-
-
-def test_criteria_category_duplicate_slugs():
-    category = CriteriaCategory.objects.create(label='Foo baz')
-    assert category.slug == 'foo-baz'
-    category = CriteriaCategory.objects.create(label='Foo baz')
-    assert category.slug == 'foo-baz-1'
-    category = CriteriaCategory.objects.create(label='Foo baz')
-    assert category.slug == 'foo-baz-2'
-
-
-def test_criteria_slug():
-    category = CriteriaCategory.objects.create(label='Foo')
-    criteria = Criteria.objects.create(label='Foo bar', category=category)
-    assert criteria.slug == 'foo-bar'
-
-
-def test_criteria_existing_slug():
-    category = CriteriaCategory.objects.create(label='Foo')
-    criteria = Criteria.objects.create(label='Foo bar', slug='bar', category=category)
-    assert criteria.slug == 'bar'
-
-
-def test_criteria_duplicate_slugs():
-    category = CriteriaCategory.objects.create(label='Foo')
-    category2 = CriteriaCategory.objects.create(label='Bar')
-    Criteria.objects.create(label='Foo baz', slug='foo-baz', category=category2)
-    criteria = Criteria.objects.create(label='Foo baz', category=category)
-    assert criteria.slug == 'foo-baz'
-    criteria = Criteria.objects.create(label='Foo baz', category=category)
-    assert criteria.slug == 'foo-baz-1'
-    criteria = Criteria.objects.create(label='Foo baz', category=category)
-    assert criteria.slug == 'foo-baz-2'
-
-
-def test_criteria_order():
-    category = CriteriaCategory.objects.create(label='Foo')
-    criteria = Criteria.objects.create(label='Foo bar', category=category)
-    assert criteria.order == 1
-
-
-def test_criteria_existing_order():
-    category = CriteriaCategory.objects.create(label='Foo')
-    criteria = Criteria.objects.create(label='Foo bar', order=42, category=category)
-    assert criteria.order == 42
-
-
-def test_criteria_duplicate_orders():
-    category = CriteriaCategory.objects.create(label='Foo')
-    category2 = CriteriaCategory.objects.create(label='Bar')
-    Criteria.objects.create(label='Foo baz', order=1, category=category2)
-    criteria = Criteria.objects.create(label='Foo baz', category=category)
-    assert criteria.order == 1
-    criteria = Criteria.objects.create(label='Foo baz', category=category)
-    assert criteria.order == 2
-    criteria = Criteria.objects.create(label='Foo baz', category=category)
-    assert criteria.order == 3
-
-
-def test_pricing_slug():
-    pricing = Pricing.objects.create(label='Foo bar')
-    assert pricing.slug == 'foo-bar'
-
-
-def test_pricing_existing_slug():
-    pricing = Pricing.objects.create(label='Foo bar', slug='bar')
-    assert pricing.slug == 'bar'
-
-
-def test_pricing_duplicate_slugs():
-    pricing = Pricing.objects.create(label='Foo baz')
-    assert pricing.slug == 'foo-baz'
-    pricing = Pricing.objects.create(label='Foo baz')
-    assert pricing.slug == 'foo-baz-1'
-    pricing = Pricing.objects.create(label='Foo baz')
-    assert pricing.slug == 'foo-baz-2'
-
-
-def test_pricing_category_criteria_order():
-    category = CriteriaCategory.objects.create(label='Foo')
-    pricing = Pricing.objects.create(label='Foo bar')
-    pcc = PricingCriteriaCategory.objects.create(pricing=pricing, category=category)
-    assert pcc.order == 1
-
-
-def test_pricing_category_criteria_existing_order():
-    category = CriteriaCategory.objects.create(label='Foo')
-    pricing = Pricing.objects.create(label='Foo bar')
-    pcc = PricingCriteriaCategory.objects.create(order=42, pricing=pricing, category=category)
-    assert pcc.order == 42
-
-
-def test_pricing_category_criteria_duplicate_orders():
-    category1 = CriteriaCategory.objects.create(label='Foo')
-    category2 = CriteriaCategory.objects.create(label='Bar')
-    category3 = CriteriaCategory.objects.create(label='Baz')
-    pricing = Pricing.objects.create(label='Foo bar')
-    pricing2 = Pricing.objects.create(label='Foo baz')
-    PricingCriteriaCategory.objects.create(order=1, pricing=pricing2, category=category1)
-    PricingCriteriaCategory.objects.create(order=2, pricing=pricing2, category=category2)
-    PricingCriteriaCategory.objects.create(order=3, pricing=pricing2, category=category3)
-    pcc = PricingCriteriaCategory.objects.create(pricing=pricing, category=category1)
-    assert pcc.order == 1
-    pcc = PricingCriteriaCategory.objects.create(pricing=pricing, category=category2)
-    assert pcc.order == 2
-    pcc = PricingCriteriaCategory.objects.create(pricing=pricing, category=category3)
-    assert pcc.order == 3
-
-
-def test_pricing_duplicate():
-    category1 = CriteriaCategory.objects.create(label='Cat 1')
-    Criteria.objects.create(label='Crit 1-1', slug='crit-1-1', category=category1, order=1)
-    Criteria.objects.create(label='Crit 1-2', slug='crit-1-2', category=category1, order=2)
-    category2 = CriteriaCategory.objects.create(label='Cat 2')
-    Criteria.objects.create(label='Crit 2-1', slug='crit-2-1', category=category2, order=1)
-    Criteria.objects.create(label='Crit 2-2', slug='crit-2-2', category=category2, order=2)
-    Criteria.objects.create(label='Crit 2-3', slug='crit-2-3', category=category2, order=3)
-    category3 = CriteriaCategory.objects.create(label='Cat 3')
-    Criteria.objects.create(label='Crit 3-1', slug='crit-3-1', category=category3, order=1)
-    Criteria.objects.create(label='Crit 3-3', slug='crit-3-3', category=category3, order=3)
-    Criteria.objects.create(label='Crit 3-4', slug='crit-3-4', category=category3, order=4)
-    Criteria.objects.create(label='Crit 3-2', slug='crit-3-2', category=category3, order=2)
-    not_used = Criteria.objects.create(label='Not used', slug='crit-3-notused', category=category3, order=5)
-
-    pricing = Pricing.objects.create(
-        label='Foo',
-        extra_variables={
-            'foo': 'bar',
-        },
-    )
-    pricing.categories.add(category1, through_defaults={'order': 1})
-    pricing.categories.add(category2, through_defaults={'order': 2})
-    pricing.categories.add(category3, through_defaults={'order': 3})
-    pricing.criterias.set(Criteria.objects.exclude(pk=not_used.pk))
-
-    new_pricing = pricing.duplicate()
-    assert new_pricing.label == 'Copy of Foo'
-    assert new_pricing.slug == 'copy-of-foo'
-    assert new_pricing.extra_variables == pricing.extra_variables
-    assert list(new_pricing.criterias.all()) == list(pricing.criterias.all())
-    original_pcc_categories = list(
-        PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('category', flat=True)
-    )
-    new_pcc_categories = list(
-        PricingCriteriaCategory.objects.filter(pricing=new_pricing).values_list('category', flat=True)
-    )
-    assert new_pcc_categories == original_pcc_categories
-    original_pcc_orders = list(
-        PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('order', flat=True)
-    )
-    new_pcc_orders = list(
-        PricingCriteriaCategory.objects.filter(pricing=new_pricing).values_list('order', flat=True)
-    )
-    assert new_pcc_orders == original_pcc_orders
-
-    new_pricing = pricing.duplicate(label='Bar')
-    assert new_pricing.label == 'Bar'
-    assert new_pricing.slug == 'bar'
-
-
-def test_get_agenda_pricing():
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    pricing = Pricing.objects.create(label='Foo bar')
-    event = Event.objects.create(
-        agenda=agenda, start_datetime=make_aware(datetime.datetime(2021, 9, 15, 12, 00)), places=10
-    )
-
-    # not found
-    with pytest.raises(AgendaPricingNotFound):
-        AgendaPricing.get_agenda_pricing(event)
-
-    # ok
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    assert AgendaPricing.get_agenda_pricing(event) == agenda_pricing
-
-    # more than one matching
-    AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=14),
-        date_end=datetime.date(year=2021, month=9, day=16),
-    )
-    with pytest.raises(AgendaPricingNotFound):
-        AgendaPricing.get_agenda_pricing(event)
-
-
-@pytest.mark.parametrize(
-    'event_date, found',
-    [
-        # just before first day
-        ((2021, 8, 31, 12, 00), False),
-        # first day
-        ((2021, 9, 1, 12, 00), True),
-        # last day
-        ((2021, 9, 30, 12, 00), True),
-        # just after last day
-        ((2021, 10, 1, 12, 00), False),
-    ],
-)
-def test_get_agenda_pricing_event_date(event_date, found):
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    pricing = Pricing.objects.create(label='Foo bar')
-    event = Event.objects.create(
-        agenda=agenda, start_datetime=make_aware(datetime.datetime(*event_date)), places=10
-    )
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    if found:
-        assert AgendaPricing.get_agenda_pricing(event) == agenda_pricing
-    else:
-        with pytest.raises(AgendaPricingNotFound):
-            AgendaPricing.get_agenda_pricing(event)
-
-
-@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
-def test_get_pricing_context(mock_send, context, nocache):
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    event = Event.objects.create(
-        agenda=agenda, start_datetime=make_aware(datetime.datetime(2021, 9, 15, 12, 00)), places=10
-    )
-    pricing = Pricing.objects.create(label='Foo bar')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    assert agenda_pricing.get_pricing_context(event, 'child:42', 'parent:35') == {}
-    pricing.extra_variables = {
-        'foo': 'bar',
-        'qf': '{{ 40|add:2 }}',
-        'domicile': 'commune',
-        'ids': '{{ cards|objects:"foo"|getlist:"id"|join:"," }}',
-        'bad': '{% if foo %}',
-    }
-    pricing.save()
-    assert agenda_pricing.get_pricing_context(event, 'child:42', 'parent:35') == {
-        'foo': 'bar',
-        'qf': '42',
-        'domicile': 'commune',
-        'ids': '1,2',
-    }
-
-    # user_external_id and adult_external_id can be used in variables
-    pricing.extra_variables = {
-        'qf': '{{ cards|objects:"qf"|filter_by:"foo"|filter_value:user_external_id|filter_by:"bar"|filter_value:adult_external_id|list }}',
-    }
-    pricing.save()
-    mock_send.reset_mock()
-    agenda_pricing.get_pricing_context(event, 'child:42', 'parent:35')
-    assert 'filter-foo=child%3A42&' in mock_send.call_args_list[0][0][0].url
-    assert 'filter-bar=parent%3A35&' in mock_send.call_args_list[0][0][0].url
-    pricing.extra_variables = {
-        'qf': '{{ cards|objects:"qf"|filter_by:"foo"|filter_value:user_external_raw_id|filter_by:"bar"|filter_value:adult_external_raw_id|list }}',
-    }
-    pricing.save()
-    mock_send.reset_mock()
-    agenda_pricing.get_pricing_context(event, 'child:42', 'parent:35')
-    assert 'filter-foo=42&' in mock_send.call_args_list[0][0][0].url
-    assert 'filter-bar=35&' in mock_send.call_args_list[0][0][0].url
-
-
-@pytest.mark.parametrize(
-    'condition, context, result',
-    [
-        ('qf < 1', {}, False),
-        ('qf < 1', {'qf': 'foo'}, False),
-        ('qf < 1', {'qf': 1}, False),
-        ('qf < 1', {'qf': 0.9}, True),
-        ('1 <= qf and qf < 2', {'qf': 0}, False),
-        ('1 <= qf and qf < 2', {'qf': 2}, False),
-        ('1 <= qf and qf < 2', {'qf': 10}, False),
-        ('1 <= qf and qf < 2', {'qf': 1}, True),
-        ('1 <= qf and qf < 2', {'qf': 1.5}, True),
-    ],
-)
-def test_compute_condition(condition, context, result):
-    category = CriteriaCategory.objects.create(label='QF', slug='qf')
-    criteria = Criteria.objects.create(label='FOO', condition=condition, category=category)
-    assert criteria.compute_condition(context) == result
-
-
-def test_compute_pricing():
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    category = CriteriaCategory.objects.create(label='QF', slug='qf')
-    pricing = Pricing.objects.create(label='Foo bar')
-    pricing.categories.add(category, through_defaults={'order': 1})
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    # no criteria defined on agenda_pricing
-    with pytest.raises(CriteriaConditionNotFound) as e:
-        agenda_pricing.compute_pricing(context={'qf': 2})
-    assert e.value.details == {'category': 'qf'}
-
-    # conditions are not set
-    criteria1 = Criteria.objects.create(label='QF < 1', slug='qf-0', category=category)
-    criteria2 = Criteria.objects.create(label='QF >= 1', slug='qf-1', category=category)
-    pricing.criterias.add(criteria1)
-    pricing.criterias.add(criteria2)
-    with pytest.raises(CriteriaConditionNotFound) as e:
-        agenda_pricing.compute_pricing(context={'qf': 2})
-    assert e.value.details == {'category': 'qf'}
-
-    # conditions set, but no match
-    criteria1.condition = 'qf < 1'
-    criteria1.save()
-    criteria2.condition = 'False'
-    criteria2.save()
-    with pytest.raises(CriteriaConditionNotFound) as e:
-        agenda_pricing.compute_pricing(context={'qf': 2})
-    assert e.value.details == {'category': 'qf'}
-
-    # criteria found, but agenda_pricing.pricing_data is not defined
-    criteria1.condition = 'qf < 1'
-    criteria1.save()
-    criteria2.condition = 'qf >= 1'
-    criteria2.save()
-    with pytest.raises(PricingDataFormatError) as e:
-        agenda_pricing.compute_pricing(context={'qf': 2})
-    assert e.value.details == {'category': 'qf', 'pricing': None, 'wanted': 'dict'}
-
-    # criteria not found in pricing_data
-    agenda_pricing.pricing_data = {
-        'qf:qf-0': 42,
-    }
-    agenda_pricing.save()
-    with pytest.raises(PricingDataError) as e:
-        agenda_pricing.compute_pricing(context={'qf': 2})
-    assert e.value.details == {'category': 'qf', 'criteria': 'qf-1'}
-
-    # criteria found, but value is wrong
-    for value in ['foo', [], {}]:
-        agenda_pricing.pricing_data = {
-            'qf:qf-0': 42,
-            'qf:qf-1': value,
-        }
-        agenda_pricing.save()
-        with pytest.raises(PricingDataFormatError) as e:
-            agenda_pricing.compute_pricing(context={'qf': 2})
-        assert e.value.details == {'pricing': value, 'wanted': 'decimal'}
-
-    # correct value (decimal)
-    agenda_pricing.pricing_data = {
-        'qf:qf-0': 42,
-        'qf:qf-1': 52,
-    }
-    agenda_pricing.save()
-    assert agenda_pricing.compute_pricing(context={'qf': 2}) == (52, {'qf': 'qf-1'})
-
-    # more complexe pricing model
-    category2 = CriteriaCategory.objects.create(label='Domicile', slug='domicile')
-    criteria1 = Criteria.objects.create(
-        label='Commune', slug='dom-0', condition='domicile == "commune"', category=category2
-    )
-    criteria2 = Criteria.objects.create(
-        label='Hors commune', slug='dom-1', condition='domicile != "commune"', category=category2
-    )
-    pricing.categories.add(category2, through_defaults={'order': 2})
-    pricing.criterias.add(criteria1)
-    pricing.criterias.add(criteria2)
-
-    # wrong definition
-    agenda_pricing.pricing_data = {
-        'domicile:dom-0': {
-            'qf:qf-0': 3,
-            'qf:qf-1': 5,
-        },
-        'domicile:dom-1': {
-            'qf:qf-0': 7,
-            'qf:qf-1': 10,
-        },
-    }
-    agenda_pricing.save()
-    with pytest.raises(PricingDataError) as e:
-        agenda_pricing.compute_pricing(context={'qf': 2, 'domicile': 'commune'})
-
-    # reorder categories, so the definition is correct
-    PricingCriteriaCategory.objects.filter(pricing=pricing, category=category).update(order=2)
-    PricingCriteriaCategory.objects.filter(pricing=pricing, category=category2).update(order=1)
-    assert agenda_pricing.compute_pricing(context={'qf': 2, 'domicile': 'commune'}) == (
-        5,
-        {'domicile': 'dom-0', 'qf': 'qf-1'},
-    )
-    assert agenda_pricing.compute_pricing(context={'qf': 0, 'domicile': 'commune'}) == (
-        3,
-        {'domicile': 'dom-0', 'qf': 'qf-0'},
-    )
-    assert agenda_pricing.compute_pricing(context={'qf': 2, 'domicile': 'ext'}) == (
-        10,
-        {'domicile': 'dom-1', 'qf': 'qf-1'},
-    )
-    assert agenda_pricing.compute_pricing(context={'qf': 0, 'domicile': 'ext'}) == (
-        7,
-        {'domicile': 'dom-1', 'qf': 'qf-0'},
-    )
-
-
-def test_get_booking_modifier_event_not_checked():
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    event = Event.objects.create(
-        agenda=agenda, start_datetime=make_aware(datetime.datetime(2021, 9, 15, 12, 00)), places=10
-    )
-    pricing = Pricing.objects.create(label='Foo bar')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    with pytest.raises(PricingEventNotCheckedError):
-        agenda_pricing.get_booking_modifier(event, 'child:42')
-
-
-def test_get_booking_modifier_no_subscription():
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    event = Event.objects.create(
-        agenda=agenda,
-        start_datetime=make_aware(datetime.datetime(2021, 9, 15, 12, 00)),
-        places=10,
-        checked=True,
-    )
-    Subscription.objects.create(
-        agenda=agenda,
-        user_external_id='child:35',  # another user
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    pricing = Pricing.objects.create(label='Foo bar')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    with pytest.raises(PricingSubscriptionError):
-        agenda_pricing.get_booking_modifier(event, 'child:42')
-
-    # more than one subscription found !
-    Subscription.objects.create(
-        agenda=agenda,
-        user_external_id='child:42',
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    Subscription.objects.create(
-        agenda=agenda,
-        user_external_id='child:42',
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    with pytest.raises(PricingSubscriptionError):
-        agenda_pricing.get_booking_modifier(event, 'child:42')
-
-
-@pytest.mark.parametrize(
-    'event_date, success',
-    [
-        # just before first day
-        ((2021, 8, 31, 12, 00), False),
-        # first day
-        ((2021, 9, 1, 12, 00), True),
-        # last day
-        ((2021, 9, 30, 12, 00), True),
-        # just after last day
-        ((2021, 10, 1, 12, 00), False),
-    ],
-)
-def test_get_booking_modifier_subscription_date(event_date, success):
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    Subscription.objects.create(
-        agenda=agenda,
-        user_external_id='child:42',
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    event = Event.objects.create(
-        agenda=agenda, start_datetime=make_aware(datetime.datetime(*event_date)), places=10, checked=True
-    )
-    pricing = Pricing.objects.create(label='Foo bar')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    if success:
-        assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
-            'status': 'not-booked',
-            'modifier_type': 'rate',
-            'modifier_rate': 0,
-        }
-    else:
-        with pytest.raises(PricingSubscriptionError):
-            agenda_pricing.get_booking_modifier(event, 'child:42')
-
-
-def test_get_booking_modifier_no_booking():
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    Subscription.objects.create(
-        agenda=agenda,
-        user_external_id='child:42',
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    event = Event.objects.create(
-        agenda=agenda,
-        start_datetime=make_aware(datetime.datetime(2021, 9, 15, 12, 00)),
-        places=10,
-        checked=True,
-    )
-    pricing = Pricing.objects.create(label='Foo bar')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
-        'status': 'not-booked',
-        'modifier_type': 'rate',
-        'modifier_rate': 0,
-    }
-
-    # more than one booking found !
-    Booking.objects.create(event=event, user_external_id='child:42')
-    Booking.objects.create(event=event, user_external_id='child:42')
-    with pytest.raises(PricingMultipleBookingError):
-        agenda_pricing.get_booking_modifier(event, 'child:42')
-
-
-def test_get_booking_modifier_booking_cancelled():
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    Subscription.objects.create(
-        agenda=agenda,
-        user_external_id='child:42',
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    event = Event.objects.create(
-        agenda=agenda,
-        start_datetime=make_aware(datetime.datetime(2021, 9, 15, 12, 00)),
-        places=10,
-        checked=True,
-    )
-    Booking.objects.create(event=event, user_external_id='child:42', cancellation_datetime=now())
-    pricing = Pricing.objects.create(label='Foo bar')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
-        'status': 'cancelled',
-        'modifier_type': 'rate',
-        'modifier_rate': 0,
-    }
-
-
-def test_get_booking_modifier_booking_not_checked():
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    Subscription.objects.create(
-        agenda=agenda,
-        user_external_id='child:42',
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    event = Event.objects.create(
-        agenda=agenda,
-        start_datetime=make_aware(datetime.datetime(2021, 9, 15, 12, 00)),
-        places=10,
-        checked=True,
-    )
-    Booking.objects.create(event=event, user_external_id='child:42')
-    pricing = Pricing.objects.create(label='Foo bar')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    with pytest.raises(PricingBookingNotCheckedError):
-        agenda_pricing.get_booking_modifier(event, 'child:42')
-
-
-def test_get_booking_modifier_booking_absence():
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    Subscription.objects.create(
-        agenda=agenda,
-        user_external_id='child:42',
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    event = Event.objects.create(
-        agenda=agenda,
-        start_datetime=make_aware(datetime.datetime(2021, 9, 15, 12, 00)),
-        places=10,
-        checked=True,
-    )
-    booking = Booking.objects.create(event=event, user_external_id='child:42', user_was_present=False)
-    pricing = Pricing.objects.create(label='Foo bar')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-
-    # no check type
-    assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
-        'status': 'absence',
-        'check_type_group': None,
-        'check_type': None,
-        'modifier_type': 'rate',
-        'modifier_rate': 0,
-    }
-
-    # check_type but incomplete configuration
-    group = CheckTypeGroup.objects.create(label='Foo bar')
-    check_type = CheckType.objects.create(label='Foo reason', group=group, kind='absence')
-    booking.user_check_type = check_type
-    booking.save()
-    with pytest.raises(PricingBookingCheckTypeError) as e:
-        agenda_pricing.get_booking_modifier(event, 'child:42')
-    assert e.value.details == {
-        'check_type_group': 'foo-bar',
-        'check_type': 'foo-reason',
-        'reason': 'not-configured',
-    }
-
-    check_type.pricing = 42
-    check_type.save()
-    assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
-        'status': 'absence',
-        'check_type_group': 'foo-bar',
-        'check_type': 'foo-reason',
-        'modifier_type': 'fixed',
-        'modifier_fixed': 42,
-    }
-
-    check_type.pricing = 0
-    check_type.save()
-    assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
-        'status': 'absence',
-        'check_type_group': 'foo-bar',
-        'check_type': 'foo-reason',
-        'modifier_type': 'fixed',
-        'modifier_fixed': 0,
-    }
-
-    check_type.pricing = None
-    check_type.pricing_rate = 20
-    check_type.save()
-    assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
-        'status': 'absence',
-        'check_type_group': 'foo-bar',
-        'check_type': 'foo-reason',
-        'modifier_type': 'rate',
-        'modifier_rate': 20,
-    }
-
-    check_type.pricing_rate = 0
-    check_type.save()
-    assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
-        'status': 'absence',
-        'check_type_group': 'foo-bar',
-        'check_type': 'foo-reason',
-        'modifier_type': 'rate',
-        'modifier_rate': 0,
-    }
-
-    # bad check type kind
-    check_type.kind = 'presence'
-    check_type.save()
-    with pytest.raises(PricingBookingCheckTypeError) as e:
-        agenda_pricing.get_booking_modifier(event, 'child:42')
-    assert e.value.details == {
-        'check_type_group': 'foo-bar',
-        'check_type': 'foo-reason',
-        'reason': 'wrong-kind',
-    }
-
-
-def test_get_booking_modifier_booking_presence():
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    Subscription.objects.create(
-        agenda=agenda,
-        user_external_id='child:42',
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    event = Event.objects.create(
-        agenda=agenda,
-        start_datetime=make_aware(datetime.datetime(2021, 9, 15, 12, 00)),
-        places=10,
-        checked=True,
-    )
-    booking = Booking.objects.create(event=event, user_external_id='child:42', user_was_present=True)
-    pricing = Pricing.objects.create(label='Foo bar')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-
-    # no check type
-    assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
-        'status': 'presence',
-        'check_type_group': None,
-        'check_type': None,
-        'modifier_type': 'rate',
-        'modifier_rate': 100,
-    }
-
-    # check_type but incomplete configuration
-    group = CheckTypeGroup.objects.create(label='Foo bar')
-    check_type = CheckType.objects.create(label='Foo reason', group=group, kind='presence')
-    booking.user_check_type = check_type
-    booking.save()
-    with pytest.raises(PricingBookingCheckTypeError) as e:
-        agenda_pricing.get_booking_modifier(event, 'child:42')
-    assert e.value.details == {
-        'check_type_group': 'foo-bar',
-        'check_type': 'foo-reason',
-        'reason': 'not-configured',
-    }
-
-    check_type.pricing = 42
-    check_type.save()
-    assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
-        'status': 'presence',
-        'check_type_group': 'foo-bar',
-        'check_type': 'foo-reason',
-        'modifier_type': 'fixed',
-        'modifier_fixed': 42,
-    }
-
-    check_type.pricing = 0
-    check_type.save()
-    assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
-        'status': 'presence',
-        'check_type_group': 'foo-bar',
-        'check_type': 'foo-reason',
-        'modifier_type': 'fixed',
-        'modifier_fixed': 0,
-    }
-
-    check_type.pricing = None
-    check_type.pricing_rate = 150
-    check_type.save()
-    assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
-        'status': 'presence',
-        'check_type_group': 'foo-bar',
-        'check_type': 'foo-reason',
-        'modifier_type': 'rate',
-        'modifier_rate': 150,
-    }
-
-    check_type.pricing_rate = 0
-    check_type.save()
-    assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
-        'status': 'presence',
-        'check_type_group': 'foo-bar',
-        'check_type': 'foo-reason',
-        'modifier_type': 'rate',
-        'modifier_rate': 0,
-    }
-
-    # bad check type kind
-    check_type.kind = 'absence'
-    check_type.save()
-    with pytest.raises(PricingBookingCheckTypeError) as e:
-        agenda_pricing.get_booking_modifier(event, 'child:42')
-    assert e.value.details == {
-        'check_type_group': 'foo-bar',
-        'check_type': 'foo-reason',
-        'reason': 'wrong-kind',
-    }
-
-
-def test_get_pricing_data(context):
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    event = Event.objects.create(
-        agenda=agenda,
-        start_datetime=make_aware(datetime.datetime(2021, 9, 15, 12, 00)),
-        places=10,
-        checked=True,
-    )
-    Subscription.objects.create(
-        agenda=agenda,
-        user_external_id='child:42',
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    category = CriteriaCategory.objects.create(label='Foo', slug='foo')
-    criteria = Criteria.objects.create(label='Bar', slug='bar', condition='True', category=category)
-    pricing = Pricing.objects.create(
-        label='Foo bar',
-        extra_variables={
-            'domicile': 'commune',
-            'qf': '2',
-        },
-    )
-    pricing.criterias.add(criteria)
-    pricing.categories.add(category, through_defaults={'order': 1})
-    AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-        pricing_data={
-            'foo:bar': 42,
-        },
-    )
-    assert AgendaPricing.get_pricing_data(context['request'], event, 'child:42', 'parent:35') == {
-        'pricing': 0,
-        'calculation_details': {
-            'pricing': 42,
-            'criterias': {'foo': 'bar'},
-            'context': {'domicile': 'commune', 'qf': '2'},
-        },
-        'booking_details': {
-            'status': 'not-booked',
-            'modifier_type': 'rate',
-            'modifier_rate': 0,
-        },
-    }
-
-
-@pytest.mark.parametrize(
-    'modifier, pricing_amount',
-    [
-        # not booked
-        (
-            {
-                'status': 'not-booked',
-                'modifier_type': 'rate',
-                'modifier_rate': 0,
-            },
-            0,
-        ),
-        # cancelled
-        (
-            {
-                'status': 'cancelled',
-                'modifier_type': 'rate',
-                'modifier_rate': 0,
-            },
-            0,
-        ),
-        # absence
-        (
-            {
-                'status': 'absence',
-                'check_type_group': None,
-                'check_type': None,
-                'modifier_type': 'rate',
-                'modifier_rate': 0,
-            },
-            0,
-        ),
-        (
-            {
-                'status': 'absence',
-                'check_type_group': 'foo-bar',
-                'check_type': 'foo-reason',
-                'modifier_type': 'fixed',
-                'modifier_fixed': 35,
-            },
-            35,
-        ),
-        (
-            {
-                'status': 'absence',
-                'check_type_group': 'foo-bar',
-                'check_type': 'foo-reason',
-                'modifier_type': 'fixed',
-                'modifier_fixed': 0,
-            },
-            0,
-        ),
-        (
-            {
-                'status': 'absence',
-                'check_type_group': 'foo-bar',
-                'check_type': 'foo-reason',
-                'modifier_type': 'rate',
-                'modifier_rate': 20,
-            },
-            8.4,
-        ),
-        (
-            {
-                'status': 'absence',
-                'check_type_group': 'foo-bar',
-                'check_type': 'foo-reason',
-                'modifier_type': 'rate',
-                'modifier_rate': 0,
-            },
-            0,
-        ),
-        # presence
-        (
-            {
-                'status': 'presence',
-                'check_type_group': None,
-                'check_type': None,
-                'modifier_type': 'rate',
-                'modifier_rate': 100,
-            },
-            42,
-        ),
-        (
-            {
-                'status': 'presence',
-                'check_type_group': 'foo-bar',
-                'check_type': 'foo-reason',
-                'modifier_type': 'fixed',
-                'modifier_fixed': 35,
-            },
-            35,
-        ),
-        (
-            {
-                'status': 'presence',
-                'check_type_group': 'foo-bar',
-                'check_type': 'foo-reason',
-                'modifier_type': 'fixed',
-                'modifier_fixed': 0,
-            },
-            0,
-        ),
-        (
-            {
-                'status': 'presence',
-                'check_type_group': 'foo-bar',
-                'check_type': 'foo-reason',
-                'modifier_type': 'rate',
-                'modifier_rate': 150,
-            },
-            63,
-        ),
-        (
-            {
-                'status': 'presence',
-                'check_type_group': 'foo-bar',
-                'check_type': 'foo-reason',
-                'modifier_type': 'rate',
-                'modifier_rate': 0,
-            },
-            0,
-        ),
-    ],
-)
-def test_aggregate_pricing_data(modifier, pricing_amount):
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    pricing = Pricing.objects.create(label='Foo bar')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-
-    assert agenda_pricing.aggregate_pricing_data(
-        pricing=42, criterias={'foo': 'bar'}, context={'domicile': 'commune', 'qf': 2}, modifier=modifier
-    ) == {
-        'pricing': pricing_amount,
-        'calculation_details': {
-            'pricing': 42,
-            'criterias': {'foo': 'bar'},
-            'context': {'domicile': 'commune', 'qf': 2},
-        },
-        'booking_details': modifier,
-    }
-
-
-def test_agenda_pricing_iter_pricing_matrix_3_categories():
-    category1 = CriteriaCategory.objects.create(label='Cat 1')
-    criteria11 = Criteria.objects.create(label='Crit 1-1', slug='crit-1-1', category=category1, order=1)
-    criteria12 = Criteria.objects.create(label='Crit 1-2', slug='crit-1-2', category=category1, order=2)
-    category2 = CriteriaCategory.objects.create(label='Cat 2')
-    criteria21 = Criteria.objects.create(label='Crit 2-1', slug='crit-2-1', category=category2, order=1)
-    criteria22 = Criteria.objects.create(label='Crit 2-2', slug='crit-2-2', category=category2, order=2)
-    criteria23 = Criteria.objects.create(label='Crit 2-3', slug='crit-2-3', category=category2, order=3)
-    category3 = CriteriaCategory.objects.create(label='Cat 3')
-    criteria31 = Criteria.objects.create(label='Crit 3-1', slug='crit-3-1', category=category3, order=1)
-    criteria33 = Criteria.objects.create(label='Crit 3-3', slug='crit-3-3', category=category3, order=3)
-    criteria34 = Criteria.objects.create(label='Crit 3-4', slug='crit-3-4', category=category3, order=4)
-    criteria32 = Criteria.objects.create(label='Crit 3-2', slug='crit-3-2', category=category3, order=2)
-    not_used = Criteria.objects.create(label='Not used', slug='crit-3-notused', category=category3, order=5)
-    category4 = CriteriaCategory.objects.create(label='Cat 4')  # ignored
-
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    pricing = Pricing.objects.create(label='Foo bar')
-    pricing.categories.add(category1, through_defaults={'order': 1})
-    pricing.categories.add(category2, through_defaults={'order': 2})
-    pricing.categories.add(category3, through_defaults={'order': 3})
-    pricing.categories.add(category4, through_defaults={'order': 4})
-    pricing.criterias.set(Criteria.objects.exclude(pk=not_used.pk))
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-    assert list(agenda_pricing.iter_pricing_matrix()) == [
-        PricingMatrix(
-            criteria=criteria11,
-            rows=[
-                PricingMatrixRow(
-                    criteria=criteria31,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria32,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria33,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria34,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-            ],
-        ),
-        PricingMatrix(
-            criteria=criteria12,
-            rows=[
-                PricingMatrixRow(
-                    criteria=criteria31,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria32,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria33,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria34,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-            ],
-        ),
-    ]
-
-    # some data defined
-    agenda_pricing.pricing_data = {
-        'cat-1:crit-1-1': {
-            'cat-2:crit-2-1': {
-                'cat-3:crit-3-1': 111,
-                'cat-3:crit-3-3': 'not-a-decimal',
-                'cat-3:crit-3-4': 114,
-            },
-            'cat-2:crit-2-3': {
-                'cat-3:crit-3-2': 132,
-            },
-        },
-        'cat-1:crit-1-2': {
-            'cat-2:crit-2-2': {
-                'cat-3:crit-3-3': 223,
-            },
-        },
-    }
-    agenda_pricing.save()
-    assert list(agenda_pricing.iter_pricing_matrix()) == [
-        PricingMatrix(
-            criteria=criteria11,
-            rows=[
-                PricingMatrixRow(
-                    criteria=criteria31,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=111),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria32,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=132),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria33,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria34,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=114),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-            ],
-        ),
-        PricingMatrix(
-            criteria=criteria12,
-            rows=[
-                PricingMatrixRow(
-                    criteria=criteria31,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria32,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria33,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=223),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria34,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-            ],
-        ),
-    ]
-
-
-def test_agenda_pricing_iter_pricing_matrix_2_categories():
-    category2 = CriteriaCategory.objects.create(label='Cat 2')
-    criteria21 = Criteria.objects.create(label='Crit 2-1', slug='crit-2-1', category=category2, order=1)
-    criteria22 = Criteria.objects.create(label='Crit 2-2', slug='crit-2-2', category=category2, order=2)
-    criteria23 = Criteria.objects.create(label='Crit 2-3', slug='crit-2-3', category=category2, order=3)
-    category3 = CriteriaCategory.objects.create(label='Cat 3')
-    criteria31 = Criteria.objects.create(label='Crit 3-1', slug='crit-3-1', category=category3, order=1)
-    criteria33 = Criteria.objects.create(label='Crit 3-3', slug='crit-3-3', category=category3, order=3)
-    criteria34 = Criteria.objects.create(label='Crit 3-4', slug='crit-3-4', category=category3, order=4)
-    criteria32 = Criteria.objects.create(label='Crit 3-2', slug='crit-3-2', category=category3, order=2)
-    not_used = Criteria.objects.create(label='Not used', slug='crit-3-notused', category=category3, order=5)
-
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    pricing = Pricing.objects.create(label='Foo bar')
-    pricing.categories.add(category2, through_defaults={'order': 2})
-    pricing.categories.add(category3, through_defaults={'order': 3})
-    pricing.criterias.set(Criteria.objects.exclude(pk=not_used.pk))
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-
-    assert list(agenda_pricing.iter_pricing_matrix()) == [
-        PricingMatrix(
-            criteria=None,
-            rows=[
-                PricingMatrixRow(
-                    criteria=criteria31,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria32,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria33,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria34,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-            ],
-        ),
-    ]
-
-    # some data defined
-    agenda_pricing.pricing_data = {
-        'cat-2:crit-2-1': {
-            'cat-3:crit-3-1': 11,
-            'cat-3:crit-3-3': 'not-a-decimal',
-            'cat-3:crit-3-4': 14,
-        },
-        'cat-2:crit-2-3': {
-            'cat-3:crit-3-2': 32,
-        },
-    }
-    agenda_pricing.save()
-    assert list(agenda_pricing.iter_pricing_matrix()) == [
-        PricingMatrix(
-            criteria=None,
-            rows=[
-                PricingMatrixRow(
-                    criteria=criteria31,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=11),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria32,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=32),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria33,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=None),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria34,
-                    cells=[
-                        PricingMatrixCell(criteria=criteria21, value=14),
-                        PricingMatrixCell(criteria=criteria22, value=None),
-                        PricingMatrixCell(criteria=criteria23, value=None),
-                    ],
-                ),
-            ],
-        ),
-    ]
-
-
-def test_agenda_pricing_iter_pricing_matrix_1_category():
-    category3 = CriteriaCategory.objects.create(label='Cat 3')
-    criteria31 = Criteria.objects.create(label='Crit 3-1', slug='crit-3-1', category=category3, order=1)
-    criteria33 = Criteria.objects.create(label='Crit 3-3', slug='crit-3-3', category=category3, order=3)
-    criteria34 = Criteria.objects.create(label='Crit 3-4', slug='crit-3-4', category=category3, order=4)
-    criteria32 = Criteria.objects.create(label='Crit 3-2', slug='crit-3-2', category=category3, order=2)
-    not_used = Criteria.objects.create(label='Not used', slug='crit-3-notused', category=category3, order=5)
-
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    pricing = Pricing.objects.create(label='Foo bar')
-    pricing.categories.add(category3, through_defaults={'order': 3})
-    pricing.criterias.set(Criteria.objects.exclude(pk=not_used.pk))
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-
-    assert list(agenda_pricing.iter_pricing_matrix()) == [
-        PricingMatrix(
-            criteria=None,
-            rows=[
-                PricingMatrixRow(
-                    criteria=criteria31,
-                    cells=[
-                        PricingMatrixCell(criteria=None, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria32,
-                    cells=[
-                        PricingMatrixCell(criteria=None, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria33,
-                    cells=[
-                        PricingMatrixCell(criteria=None, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria34,
-                    cells=[
-                        PricingMatrixCell(criteria=None, value=None),
-                    ],
-                ),
-            ],
-        ),
-    ]
-
-    # some data defined
-    agenda_pricing.pricing_data = {
-        'cat-3:crit-3-1': 1,
-        'cat-3:crit-3-3': 'not-a-decimal',
-        'cat-3:crit-3-4': 4,
-    }
-    agenda_pricing.save()
-    assert list(agenda_pricing.iter_pricing_matrix()) == [
-        PricingMatrix(
-            criteria=None,
-            rows=[
-                PricingMatrixRow(
-                    criteria=criteria31,
-                    cells=[
-                        PricingMatrixCell(criteria=None, value=1),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria32,
-                    cells=[
-                        PricingMatrixCell(criteria=None, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria33,
-                    cells=[
-                        PricingMatrixCell(criteria=None, value=None),
-                    ],
-                ),
-                PricingMatrixRow(
-                    criteria=criteria34,
-                    cells=[
-                        PricingMatrixCell(criteria=None, value=4),
-                    ],
-                ),
-            ],
-        ),
-    ]
-
-
-def test_agenda_pricing_iter_pricing_matrix_empty():
-    agenda = Agenda.objects.create(label='Foo bar', kind='events')
-    pricing = Pricing.objects.create(label='Foo bar')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-    )
-
-    assert list(agenda_pricing.iter_pricing_matrix()) == []
diff --git a/tests/settings.py b/tests/settings.py
index 90d48a64..c7257967 100644
--- a/tests/settings.py
+++ b/tests/settings.py
@@ -34,4 +34,3 @@ LEGACY_URLS_MAPPING = {'old.org': 'new.org'}
 EXCEPTIONS_SOURCES = {}
 
 SITE_BASE_URL = 'https://example.com'
-CHRONO_ENABLE_PRICING = True
diff --git a/tests/test_import_export.py b/tests/test_import_export.py
index b5aaf7d9..c81cfb96 100644
--- a/tests/test_import_export.py
+++ b/tests/test_import_export.py
@@ -35,7 +35,6 @@ from chrono.agendas.models import (
     VirtualMember,
 )
 from chrono.manager.utils import import_site
-from chrono.pricing.models import AgendaPricing, Criteria, CriteriaCategory, Pricing, PricingCriteriaCategory
 
 pytestmark = pytest.mark.django_db
 
@@ -486,71 +485,6 @@ def test_import_export_agenda_with_events_type(app):
     assert agenda.events_type == events_type
 
 
-def test_import_export_agenda_with_pricing(app):
-    pricing = Pricing.objects.create(label='Foo')
-    agenda = Agenda.objects.create(label='Foo Bar', kind='events')
-    Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
-    agenda_pricing = AgendaPricing.objects.create(
-        agenda=agenda,
-        pricing=pricing,
-        date_start=datetime.date(year=2021, month=9, day=1),
-        date_end=datetime.date(year=2021, month=10, day=1),
-        pricing_data={
-            'foo': 'bar',
-        },
-    )
-    output = get_output_of_command('export_site')
-
-    import_site(data={}, clean=True)
-    assert Agenda.objects.count() == 0
-    assert Pricing.objects.count() == 0
-    data = json.loads(output)
-    del data['pricing_models']
-    print(data)
-
-    with pytest.raises(AgendaImportError) as excinfo:
-        import_site(data, overwrite=True)
-    assert str(excinfo.value) == 'Missing "foo" pricing model'
-
-    Pricing.objects.create(label='foobar')
-    with pytest.raises(AgendaImportError) as excinfo:
-        import_site(data, overwrite=True)
-    assert str(excinfo.value) == 'Missing "foo" pricing model'
-
-    pricing = Pricing.objects.create(label='Foo')
-    import_site(data, overwrite=True)
-    agenda = Agenda.objects.get(slug=agenda.slug)
-    assert agenda.agendapricing_set.count() == 1
-    agenda_pricing = agenda.agendapricing_set.get()
-    assert agenda_pricing.agenda == agenda
-    assert agenda_pricing.pricing == pricing
-    assert agenda_pricing.date_start == datetime.date(year=2021, month=9, day=1)
-    assert agenda_pricing.date_end == datetime.date(year=2021, month=10, day=1)
-
-    # again
-    import_site(data)
-    assert agenda.agendapricing_set.count() == 1
-    agenda_pricing = AgendaPricing.objects.get(pk=agenda_pricing.pk)
-    assert agenda_pricing.agenda == agenda
-    assert agenda_pricing.pricing == pricing
-
-    data['agendas'][0]['pricings'].append(
-        {
-            'pricing': 'foo',
-            'date_start': '2022-09-01',
-            'date_end': '2022-10-01',
-            'pricing_data': {'foo': 'bar'},
-        }
-    )
-    import_site(data)
-    assert agenda.agendapricing_set.count() == 2
-    agenda_pricing = AgendaPricing.objects.latest('pk')
-    assert agenda_pricing.agenda == agenda
-    assert agenda_pricing.pricing == pricing
-    assert agenda_pricing.date_start == datetime.date(year=2022, month=9, day=1)
-    assert agenda_pricing.date_end == datetime.date(year=2022, month=10, day=1)
-
-
 def test_import_export_virtual_agenda(app):
     virtual_agenda = Agenda.objects.create(label='Virtual Agenda', kind='virtual')
     output = get_output_of_command('export_site')
@@ -1166,221 +1100,6 @@ def test_import_export_resource(app):
     assert resource.slug == 'foo-bar'
 
 
-def test_import_export_pricing_criteria_category(app):
-    output = get_output_of_command('export_site')
-    payload = json.loads(output)
-    assert len(payload['pricing_categories']) == 0
-
-    category = CriteriaCategory.objects.create(label='Foo bar')
-    Criteria.objects.create(label='Foo reason', category=category)
-    Criteria.objects.create(label='Baz', category=category)
-
-    output = get_output_of_command('export_site')
-    payload = json.loads(output)
-    assert len(payload['pricing_categories']) == 1
-
-    category.delete()
-    assert not CriteriaCategory.objects.exists()
-    assert not Criteria.objects.exists()
-
-    import_site(copy.deepcopy(payload))
-    assert CriteriaCategory.objects.count() == 1
-    category = CriteriaCategory.objects.first()
-    assert category.label == 'Foo bar'
-    assert category.slug == 'foo-bar'
-    assert category.criterias.count() == 2
-    assert Criteria.objects.get(category=category, label='Foo reason', slug='foo-reason')
-    assert Criteria.objects.get(category=category, label='Baz', slug='baz')
-
-    # update
-    update_payload = copy.deepcopy(payload)
-    update_payload['pricing_categories'][0]['label'] = 'Foo bar Updated'
-    import_site(update_payload)
-    category.refresh_from_db()
-    assert category.label == 'Foo bar Updated'
-
-    # insert another category
-    category.slug = 'foo-bar-updated'
-    category.save()
-    import_site(copy.deepcopy(payload))
-    assert CriteriaCategory.objects.count() == 2
-    category = CriteriaCategory.objects.latest('pk')
-    assert category.label == 'Foo bar'
-    assert category.slug == 'foo-bar'
-    assert category.criterias.count() == 2
-    assert Criteria.objects.get(category=category, label='Foo reason', slug='foo-reason')
-    assert Criteria.objects.get(category=category, label='Baz', slug='baz')
-
-    # with overwrite
-    Criteria.objects.create(category=category, label='Baz2')
-    import_site(copy.deepcopy(payload), overwrite=True)
-    assert CriteriaCategory.objects.count() == 2
-    category = CriteriaCategory.objects.latest('pk')
-    assert category.label == 'Foo bar'
-    assert category.slug == 'foo-bar'
-    assert category.criterias.count() == 2
-    assert Criteria.objects.get(category=category, label='Foo reason', slug='foo-reason')
-    assert Criteria.objects.get(category=category, label='Baz', slug='baz')
-
-
-def test_import_export_pricing(app):
-    output = get_output_of_command('export_site')
-    payload = json.loads(output)
-    assert len(payload['pricing_models']) == 0
-
-    pricing = Pricing.objects.create(label='Foo bar', extra_variables={'foo': 'bar'})
-
-    output = get_output_of_command('export_site')
-    payload = json.loads(output)
-    assert len(payload['pricing_models']) == 1
-
-    pricing.delete()
-    assert not Pricing.objects.exists()
-
-    import_site(copy.deepcopy(payload))
-    assert Pricing.objects.count() == 1
-    pricing = Pricing.objects.first()
-    assert pricing.label == 'Foo bar'
-    assert pricing.slug == 'foo-bar'
-    assert pricing.extra_variables == {'foo': 'bar'}
-
-    # update
-    update_payload = copy.deepcopy(payload)
-    update_payload['pricing_models'][0]['label'] = 'Foo bar Updated'
-    import_site(update_payload)
-    pricing.refresh_from_db()
-    assert pricing.label == 'Foo bar Updated'
-
-    # insert another pricing
-    pricing.slug = 'foo-bar-updated'
-    pricing.save()
-    import_site(copy.deepcopy(payload))
-    assert Pricing.objects.count() == 2
-    pricing = Pricing.objects.latest('pk')
-    assert pricing.label == 'Foo bar'
-    assert pricing.slug == 'foo-bar'
-    assert pricing.extra_variables == {'foo': 'bar'}
-
-
-def test_import_export_pricing_with_categories(app):
-    pricing = Pricing.objects.create(label='Foo bar')
-    category = CriteriaCategory.objects.create(label='Foo bar')
-    pricing.categories.add(category, through_defaults={'order': 42})
-
-    output = get_output_of_command('export_site')
-
-    import_site(data={}, clean=True)
-    assert Pricing.objects.count() == 0
-    assert CriteriaCategory.objects.count() == 0
-    data = json.loads(output)
-    del data['pricing_categories']
-
-    with pytest.raises(AgendaImportError) as excinfo:
-        import_site(data, overwrite=True)
-    assert str(excinfo.value) == 'Missing "foo-bar" pricing category'
-
-    CriteriaCategory.objects.create(label='Foobar')
-    with pytest.raises(AgendaImportError) as excinfo:
-        import_site(data, overwrite=True)
-    assert str(excinfo.value) == 'Missing "foo-bar" pricing category'
-
-    category = CriteriaCategory.objects.create(label='Foo bar')
-    import_site(data, overwrite=True)
-    pricing = Pricing.objects.get(slug=pricing.slug)
-    assert list(pricing.categories.all()) == [category]
-    assert PricingCriteriaCategory.objects.first().order == 42
-
-    category2 = CriteriaCategory.objects.create(label='Foo bar 2')
-    category3 = CriteriaCategory.objects.create(label='Foo bar 3')
-    pricing.categories.add(category2, through_defaults={'order': 1})
-    output = get_output_of_command('export_site')
-    data = json.loads(output)
-    del data['pricing_categories']
-    data['pricing_models'][0]['categories'] = [
-        {
-            'category': 'foo-bar-3',
-            'order': 1,
-            'criterias': [],
-        },
-        {
-            'category': 'foo-bar',
-            'order': 35,
-            'criterias': [],
-        },
-    ]
-    import_site(data, overwrite=True)
-    assert list(pricing.categories.all()) == [category, category3]
-    assert list(
-        PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('category', flat=True)
-    ) == [category3.pk, category.pk]
-    assert list(PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('order', flat=True)) == [
-        1,
-        35,
-    ]
-    assert list(pricing.criterias.all()) == []
-
-    criteria1 = Criteria.objects.create(label='Crit 1', category=category)
-    Criteria.objects.create(label='Crit 2', category=category)
-    criteria3 = Criteria.objects.create(label='Crit 3', category=category)
-
-    # unknown criteria
-    data['pricing_models'][0]['categories'] = [
-        {
-            'category': 'foo-bar-3',
-            'order': 1,
-            'criterias': ['unknown'],
-        },
-        {
-            'category': 'foo-bar',
-            'order': 35,
-            'criterias': [],
-        },
-    ]
-    with pytest.raises(AgendaImportError) as excinfo:
-        import_site(data, overwrite=True)
-    assert str(excinfo.value) == 'Missing "unknown" pricing criteria for "foo-bar-3" category'
-
-    # wrong criteria (from another category)
-    data['pricing_models'][0]['categories'] = [
-        {
-            'category': 'foo-bar-3',
-            'order': 1,
-            'criterias': ['crit-1'],
-        },
-        {
-            'category': 'foo-bar',
-            'order': 35,
-            'criterias': [],
-        },
-    ]
-    with pytest.raises(AgendaImportError) as excinfo:
-        import_site(data, overwrite=True)
-    assert str(excinfo.value) == 'Missing "crit-1" pricing criteria for "foo-bar-3" category'
-
-    data['pricing_models'][0]['categories'] = [
-        {
-            'category': 'foo-bar-3',
-            'order': 1,
-            'criterias': [],
-        },
-        {
-            'category': 'foo-bar',
-            'order': 35,
-            'criterias': ['crit-1', 'crit-3'],
-        },
-    ]
-    import_site(data, overwrite=True)
-    assert list(pricing.categories.all()) == [category, category3]
-    assert list(
-        PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('category', flat=True)
-    ) == [category3.pk, category.pk]
-    assert list(PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('order', flat=True)) == [
-        1,
-        35,
-    ]
-    assert set(pricing.criterias.all()) == {criteria1, criteria3}
-
-
 @mock.patch('chrono.agendas.models.Agenda.is_available_for_simple_management')
 def test_import_export_desk_simple_management(available_mock):
     agenda = Agenda.objects.create(label='Foo bar', kind='meetings', desk_simple_management=True)
-- 
2.35.1

