pricing: test tool for agenda pricing (#66892)

This commit is contained in:
Lauréline Guérin 2022-07-05 19:58:13 +02:00
parent 6fef766eab
commit 41eda72b2e
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
8 changed files with 560 additions and 9 deletions

View File

@ -17,12 +17,17 @@
import json
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from requests.exceptions import RequestException
from lingo.agendas.models import Agenda
from lingo.utils import requests
class ChronoError(Exception):
pass
def is_chrono_enabled():
return hasattr(settings, 'KNOWN_SERVICES') and settings.KNOWN_SERVICES.get('chrono')
@ -103,3 +108,27 @@ def refresh_agendas():
for slug, agenda in existing_agendas.items():
if slug not in seen_agendas:
agenda.delete()
def get_event(event_slug):
result = get_chrono_json('api/agendas/events/?slots=%s' % event_slug)
if not result:
raise ChronoError(_('Unable to get event details'))
if result.get('err'):
raise ChronoError(_('Unable to get event details (%s)') % result['err_desc'])
if not result.get('data'):
raise ChronoError(_('Unable to get event details'))
return result['data'][0]
def get_subscriptions(agenda_slug, user_external_id):
result = get_chrono_json(
'api/agenda/%s/subscription/?user_external_id=%s' % (agenda_slug, user_external_id)
)
if not result or not result.get('data'):
raise ChronoError(_('Unable to get subscription details'))
if result.get('err'):
raise ChronoError(_('Unable to get subscription details (%s)') % result['err_desc'])
if not result.get('data'):
raise ChronoError(_('Unable to get subscription details'))
return result['data']

View File

@ -47,3 +47,8 @@ ul.objects-list.sortable {
ul.objects-list.single-links li a.link::before {
content: "\f08e"; /* fa-external-link */
}
div.test-tool-result .infonotice h3 {
margin-top: 0;
font-weight: normal;
}

View File

@ -14,14 +14,17 @@
# 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
from django import forms
from django.forms import ValidationError
from django.template import Template, TemplateSyntaxError
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from lingo.agendas.chrono import ChronoError, get_event, get_subscriptions
from lingo.agendas.models import CheckType
from lingo.pricing.models import AgendaPricing, Criteria, CriteriaCategory
from lingo.pricing.models import AgendaPricing, Criteria, CriteriaCategory, PricingError
class ExportForm(forms.Form):
@ -162,6 +165,112 @@ class PricingMatrixForm(forms.Form):
self.fields['crit_%i' % i] = forms.DecimalField(required=True, max_digits=5, decimal_places=2)
class PricingTestToolForm(forms.Form):
event_slug = forms.CharField(label=_('Event identifier'))
user_external_id = forms.CharField(label=_('User external identifier'))
adult_external_id = forms.CharField(label=_('Adult external identifier'))
booking_status = forms.ChoiceField(label=_('Booking status'), choices=[])
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
self.agenda_pricing = kwargs.pop('agenda_pricing')
self.agenda = self.agenda_pricing.agenda
self.serialized_event = None
self.serialized_subscription = None
self.check_type_slug = None
self.booking_status = None
super().__init__(*args, **kwargs)
presence_check_types = (
self.agenda.check_type_group.check_types.presences() if self.agenda.check_type_group else []
)
absence_check_types = (
self.agenda.check_type_group.check_types.absences() if self.agenda.check_type_group else []
)
status_choices = [
('presence', _('Presence')),
]
status_choices += [
('presence::%s' % ct.slug, _('Presence (%s)') % ct.label) for ct in presence_check_types
]
status_choices += [('absence', _('Absence'))]
status_choices += [
('absence::%s' % ct.slug, _('Absence (%s)') % ct.label) for ct in absence_check_types
]
self.fields['booking_status'].choices = status_choices
def clean_event_slug(self):
original_event_slug = self.cleaned_data['event_slug']
event_slug = original_event_slug
if '@' not in event_slug:
# chrono's endpoint takes event ids like '<agenda_slug>@<event_slug>'
event_slug = '%s@%s' % (self.agenda.slug, event_slug)
elif event_slug.split('@')[0] != self.agenda.slug:
raise ValidationError(_('The agenda identifier is wrong (%s)') % event_slug.split('@')[0])
try:
self.serialized_event = get_event(event_slug)
except ChronoError as e:
raise forms.ValidationError(str(e).replace(event_slug, original_event_slug))
event_date = datetime.datetime.fromisoformat(self.serialized_event['start_datetime']).date()
if event_date < self.agenda_pricing.date_start or event_date >= self.agenda_pricing.date_end:
raise ValidationError(_('This event takes place outside the period covered by this pricing'))
return original_event_slug
def clean_booking_status(self):
original_booking_status = self.cleaned_data['booking_status']
self.booking_status = original_booking_status
if '::' in original_booking_status:
# split value to get booking status and selected check_type
self.booking_status, self.check_type_slug = original_booking_status.split('::')
return original_booking_status
def get_subscription(self, user_external_id):
start_date = datetime.datetime.fromisoformat(self.serialized_event['start_datetime']).date()
end_date = start_date + datetime.timedelta(days=1)
try:
subscriptions = get_subscriptions(self.agenda.slug, user_external_id)
except ChronoError as e:
self.add_error('user_external_id', str(e))
return
for subscription in subscriptions:
sub_start_date = datetime.date.fromisoformat(subscription['date_start'])
sub_end_date = datetime.date.fromisoformat(subscription['date_end'])
if sub_start_date >= end_date:
continue
if sub_end_date <= start_date:
continue
return subscription
self.add_error('user_external_id', _('No subscription found for this event'))
def clean(self):
super().clean()
if self.cleaned_data.get('user_external_id') and self.serialized_event:
user_external_id = self.cleaned_data['user_external_id']
self.serialized_subscription = self.get_subscription(user_external_id)
def compute(self):
if not self.serialized_event or not self.serialized_subscription:
return
try:
return AgendaPricing.get_pricing_data(
request=self.request,
agenda=self.agenda,
agenda_pricing=self.agenda_pricing,
event=self.serialized_event,
subscription=self.serialized_subscription,
check_status={
'status': self.booking_status,
'check_type': self.check_type_slug,
},
booking={},
user_external_id=self.cleaned_data['user_external_id'],
adult_external_id=self.cleaned_data['adult_external_id'],
)
except PricingError as e:
return {'error': e.details}
class NewCheckTypeForm(forms.ModelForm):
class Meta:
model = CheckType

View File

@ -363,9 +363,17 @@ class AgendaPricing(models.Model):
@staticmethod
def get_pricing_data(
request, agenda, event, subscription, check_status, booking, user_external_id, adult_external_id
request,
agenda,
event,
subscription,
check_status,
booking,
user_external_id,
adult_external_id,
agenda_pricing=None,
):
agenda_pricing = AgendaPricing.get_agenda_pricing(agenda=agenda, event=event)
agenda_pricing = agenda_pricing or AgendaPricing.get_agenda_pricing(agenda=agenda, event=event)
data = {
'event': event,
'subscription': subscription,

View File

@ -20,8 +20,31 @@
{% endblock %}
{% block content %}
{% for matrix in object.iter_pricing_matrix %}
<div class="section">
<h3>{% trans "Test tool" %}</h3>
<div>
<form method="get" enctype="multipart/form-data">
{{ test_tool_form.as_p }}
<div class="buttons">
<button class="submit-button">{% trans "Compute" %}</button>
</div>
</form>
{% if request.GET and test_tool_form.is_valid %}
{% with test_tool_form.compute as pricing_data %}
<div class="test-tool-result">
<div class="infonotice">
<h3>{% trans "Computed pricing data" %}</h3>
{% if pricing_data.pricing is not None %}<p>{% trans "Pricing:" %} {{ pricing_data.pricing|stringformat:".2f" }}</p>{% endif %}
<pre>{{ pricing_data|pprint }}</pre>
</div>
</div>
{% endwith %}
{% endif %}
</div>
</div>
{% for matrix in object.iter_pricing_matrix %}
<div class="section pricing-matrix">
{% if matrix.criteria %}<h3>{{ matrix.criteria.label }}</h3>{% endif %}
<div>
<table class="main pricing-matrix-{{ matrix.criteria.slug }}">

View File

@ -54,6 +54,7 @@ from lingo.pricing.forms import (
PricingCriteriaCategoryEditForm,
PricingDuplicateForm,
PricingMatrixForm,
PricingTestToolForm,
PricingVariableFormSet,
)
from lingo.pricing.models import AgendaPricing, Criteria, CriteriaCategory, Pricing, PricingCriteriaCategory
@ -717,6 +718,15 @@ class AgendaPricingDetailView(AgendaMixin, DetailView):
'pricing__criterias__category'
)
def get_context_data(self, **kwargs):
form = PricingTestToolForm(
agenda_pricing=self.object, request=self.request, data=self.request.GET or None
)
if self.request.GET:
form.is_valid()
kwargs['test_tool_form'] = form
return super().get_context_data(**kwargs)
agenda_pricing_detail = AgendaPricingDetailView.as_view()

View File

@ -5,7 +5,13 @@ import pytest
from requests.exceptions import ConnectionError
from requests.models import Response
from lingo.agendas.chrono import collect_agenda_data, refresh_agendas
from lingo.agendas.chrono import (
ChronoError,
collect_agenda_data,
get_event,
get_subscriptions,
refresh_agendas,
)
from lingo.agendas.models import Agenda
pytestmark = pytest.mark.django_db
@ -151,3 +157,120 @@ def test_refresh_agendas(mock_collect):
mock_collect.return_value = []
refresh_agendas()
assert Agenda.objects.count() == 0
def test_get_event_no_service(settings):
settings.KNOWN_SERVICES = {}
with pytest.raises(ChronoError) as e:
get_event('foo')
assert str(e.value) == 'Unable to get event details'
settings.KNOWN_SERVICES = {'other': []}
with pytest.raises(ChronoError) as e:
get_event('foo')
assert str(e.value) == 'Unable to get event details'
def test_get_event():
with mock.patch('requests.Session.get') as requests_get:
requests_get.side_effect = ConnectionError()
with pytest.raises(ChronoError) as e:
get_event('foo')
assert str(e.value) == 'Unable to get event details'
with mock.patch('requests.Session.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 500
requests_get.return_value = mock_resp
with pytest.raises(ChronoError) as e:
get_event('foo')
assert str(e.value) == 'Unable to get event details'
with mock.patch('requests.Session.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 404
requests_get.return_value = mock_resp
with pytest.raises(ChronoError) as e:
get_event('foo')
assert str(e.value) == 'Unable to get event details'
with mock.patch('requests.Session.get') as requests_get:
requests_get.return_value = MockedRequestResponse(content=json.dumps({'foo': 'bar'}))
with pytest.raises(ChronoError) as e:
get_event('foo')
assert str(e.value) == 'Unable to get event details'
data = {'data': []}
with mock.patch('requests.Session.get') as requests_get:
requests_get.return_value = MockedRequestResponse(content=json.dumps(data))
with pytest.raises(ChronoError) as e:
get_event('foo')
assert str(e.value) == 'Unable to get event details'
assert requests_get.call_args_list[0][0] == ('api/agendas/events/?slots=foo',)
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://chrono.example.org'
data = {'data': ['foo']}
with mock.patch('requests.Session.get') as requests_get:
requests_get.return_value = MockedRequestResponse(content=json.dumps(data))
assert get_event('foo') == 'foo'
data = {'data': ['foo', 'bar']} # should not happen
with mock.patch('requests.Session.get') as requests_get:
requests_get.return_value = MockedRequestResponse(content=json.dumps(data))
assert get_event('foo') == 'foo'
def test_get_subscriptions_no_service(settings):
settings.KNOWN_SERVICES = {}
with pytest.raises(ChronoError) as e:
get_subscriptions('foo', 'user:1')
assert str(e.value) == 'Unable to get subscription details'
settings.KNOWN_SERVICES = {'other': []}
with pytest.raises(ChronoError) as e:
get_subscriptions('foo', 'user:1')
assert str(e.value) == 'Unable to get subscription details'
def test_get_subscriptions():
with mock.patch('requests.Session.get') as requests_get:
requests_get.side_effect = ConnectionError()
with pytest.raises(ChronoError) as e:
get_subscriptions('foo', 'user:1')
assert str(e.value) == 'Unable to get subscription details'
with mock.patch('requests.Session.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 500
requests_get.return_value = mock_resp
with pytest.raises(ChronoError) as e:
get_subscriptions('foo', 'user:1')
assert str(e.value) == 'Unable to get subscription details'
with mock.patch('requests.Session.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 404
requests_get.return_value = mock_resp
with pytest.raises(ChronoError) as e:
get_subscriptions('foo', 'user:1')
assert str(e.value) == 'Unable to get subscription details'
with mock.patch('requests.Session.get') as requests_get:
requests_get.return_value = MockedRequestResponse(content=json.dumps({'foo': 'bar'}))
with pytest.raises(ChronoError) as e:
get_subscriptions('foo', 'user:1')
assert str(e.value) == 'Unable to get subscription details'
data = {'data': []}
with mock.patch('requests.Session.get') as requests_get:
requests_get.return_value = MockedRequestResponse(content=json.dumps(data))
with pytest.raises(ChronoError) as e:
get_subscriptions('foo', 'user:1')
assert str(e.value) == 'Unable to get subscription details'
assert requests_get.call_args_list[0][0] == ('api/agenda/foo/subscription/?user_external_id=user:1',)
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://chrono.example.org'
data = {'data': ['foo', 'bar']}
with mock.patch('requests.Session.get') as requests_get:
requests_get.return_value = MockedRequestResponse(content=json.dumps(data))
assert get_subscriptions('foo', 'user:1') == ['foo', 'bar']

View File

@ -1,11 +1,13 @@
import datetime
from decimal import Decimal
from unittest import mock
import pytest
from django.utils.timezone import now
from lingo.agendas.models import Agenda, CheckTypeGroup
from lingo.pricing.models import AgendaPricing, Criteria, CriteriaCategory, Pricing
from lingo.agendas.chrono import ChronoError
from lingo.agendas.models import Agenda, CheckType, CheckTypeGroup
from lingo.pricing.models import AgendaPricing, Criteria, CriteriaCategory, Pricing, PricingError
from tests.utils import login
pytestmark = pytest.mark.django_db
@ -353,7 +355,7 @@ def test_detail_agenda_pricing_2_categories(app, admin_user):
app = login(app)
resp = app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
assert '<h3>' not in resp
assert len(resp.pyquery.find('div.section.prixing-matrix h3')) == 0
ths = resp.pyquery.find('table thead th')
assert len(ths) == 4
assert ths[0].text is None
@ -400,7 +402,7 @@ def test_detail_agenda_pricing_1_category(app, admin_user):
app = login(app)
resp = app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
assert '<h3>' not in resp
assert len(resp.pyquery.find('div.section.prixing-matrix h3')) == 0
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'
@ -413,6 +415,248 @@ def test_detail_agenda_pricing_1_category(app, admin_user):
assert resp.pyquery.find('table tr.pricing-row-crit-3-4 td')[0].text == '114.00'
@mock.patch('lingo.pricing.forms.get_event')
@mock.patch('lingo.pricing.forms.get_subscriptions')
@mock.patch('lingo.pricing.models.AgendaPricing.get_pricing_data')
def test_detail_agenda_pricing_test_tool(mock_pricing_data, mock_subscriptions, mock_event, app, admin_user):
agenda = Agenda.objects.create(label='Foo bar')
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)
resp = app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
assert 'Computed pricing data' not in resp
# check event date
mock_event.return_value = {'start_datetime': '2021-08-31T12:00:00+02:00'}
resp.form['event_slug'] = 'foo'
resp.form['user_external_id'] = 'user:1'
resp.form['adult_external_id'] = 'adult:1'
resp.form['booking_status'] = 'presence'
resp = resp.form.submit()
assert 'Computed pricing data' not in resp
assert resp.context['test_tool_form'].errors['event_slug'] == [
'This event takes place outside the period covered by this pricing'
]
assert mock_event.call_args_list == [mock.call('foo-bar@foo')]
assert mock_pricing_data.call_args_list == []
mock_event.return_value = {'start_datetime': '2021-10-01T12:00:00+02:00'}
resp = resp.form.submit()
assert 'Computed pricing data' not in resp
assert resp.context['test_tool_form'].errors['event_slug'] == [
'This event takes place outside the period covered by this pricing'
]
mock_event.return_value = {'start_datetime': '2021-09-01T12:00:00+02:00'}
# check event_slug & agenda
resp.form['event_slug'] = 'foo@foo'
resp = resp.form.submit()
assert resp.context['test_tool_form'].errors['event_slug'] == ['The agenda identifier is wrong (foo)']
# check subscriptions dates
mock_subscriptions.return_value = []
mock_event.reset_mock()
resp.form['event_slug'] = 'foo-bar@foo'
resp = resp.form.submit()
assert mock_event.call_args_list == [mock.call('foo-bar@foo')]
assert mock_pricing_data.call_args_list == []
assert 'Computed pricing data' not in resp
assert resp.context['test_tool_form'].errors['user_external_id'] == [
'No subscription found for this event'
]
mock_subscriptions.return_value = [
{
'date_start': '2021-08-01',
'date_end': '2021-09-01',
},
{
'date_start': '2021-09-02',
'date_end': '2021-09-03',
},
]
resp = resp.form.submit()
assert 'Computed pricing data' not in resp
assert resp.context['test_tool_form'].errors['user_external_id'] == [
'No subscription found for this event'
]
mock_subscriptions.return_value = [
{
'date_start': '2021-08-01',
'date_end': '2021-09-01',
},
{
'date_start': '2021-09-01',
'date_end': '2021-09-02',
},
{
'date_start': '2021-09-02',
'date_end': '2021-09-03',
},
]
mock_pricing_data.return_value = {'foo': 'bar', 'pricing': Decimal('42')}
resp = resp.form.submit()
assert 'Computed pricing data' in resp
assert mock_pricing_data.call_args_list == [
mock.call(
request=mock.ANY,
agenda=agenda,
agenda_pricing=agenda_pricing,
event={'start_datetime': '2021-09-01T12:00:00+02:00'},
subscription={'date_start': '2021-09-01', 'date_end': '2021-09-02'},
check_status={'status': 'presence', 'check_type': None},
booking={},
user_external_id='user:1',
adult_external_id='adult:1',
)
]
assert '<p>Pricing: 42.00</p>' in resp
assert '<pre>{&#39;foo&#39;: &#39;bar&#39;, &#39;pricing&#39;: Decimal(&#39;42&#39;)}</pre>' in resp
mock_pricing_data.side_effect = PricingError(details={'foo': 'error'})
resp = resp.form.submit()
assert 'Computed pricing data' in resp
assert '<pre>{&#39;error&#39;: {&#39;foo&#39;: &#39;error&#39;}}</pre>' in resp
@mock.patch('lingo.pricing.forms.get_event')
@mock.patch('lingo.pricing.forms.get_subscriptions')
def test_detail_agenda_pricing_test_tool_event_error(mock_subscriptions, mock_event, app, admin_user):
agenda = Agenda.objects.create(label='Foo bar')
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),
)
mock_event.side_effect = ChronoError('foo bar foo-bar@foo-event')
app = login(app)
resp = app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
resp.form['event_slug'] = 'foo-event'
resp.form['user_external_id'] = 'user:1'
resp.form['adult_external_id'] = 'adult:1'
resp.form['booking_status'] = 'presence'
# agenda slug is removed from error message
resp = resp.form.submit()
assert resp.context['test_tool_form'].errors['event_slug'] == ['foo bar foo-event']
# except it was included in event_slug
resp.form['event_slug'] = 'foo-bar@foo-event'
resp = resp.form.submit()
assert resp.context['test_tool_form'].errors['event_slug'] == ['foo bar foo-bar@foo-event']
@mock.patch('lingo.pricing.forms.get_event')
@mock.patch('lingo.pricing.forms.get_subscriptions')
def test_detail_agenda_pricing_test_tool_subscription_error(mock_subscriptions, mock_event, app, admin_user):
agenda = Agenda.objects.create(label='Foo bar')
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),
)
mock_event.return_value = {'start_datetime': '2021-09-01T12:00:00+02:00'}
mock_subscriptions.side_effect = ChronoError('foo bar')
app = login(app)
resp = app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
resp.form['event_slug'] = 'foo-event'
resp.form['user_external_id'] = 'user:1'
resp.form['adult_external_id'] = 'adult:1'
resp.form['booking_status'] = 'presence'
resp = resp.form.submit()
assert resp.context['test_tool_form'].errors['user_external_id'] == ['foo bar']
@mock.patch('lingo.pricing.forms.get_event')
@mock.patch('lingo.pricing.forms.get_subscriptions')
@mock.patch('lingo.pricing.models.AgendaPricing.get_pricing_data')
def test_detail_agenda_pricing_test_tool_booking_status(
mock_pricing_data, mock_subscriptions, mock_event, app, admin_user
):
agenda = Agenda.objects.create(label='Foo bar')
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),
)
mock_event.return_value = {'start_datetime': '2021-09-01T12:00:00+02:00'}
mock_subscriptions.return_value = [
{
'date_start': '2021-09-01',
'date_end': '2021-09-02',
},
]
app = login(app)
resp = app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
assert resp.form['booking_status'].options == [
('presence', False, 'Presence'),
('absence', False, 'Absence'),
]
group = CheckTypeGroup.objects.create(label='Foo bar')
CheckType.objects.create(label='Foo presence reason', group=group, kind='presence')
CheckType.objects.create(label='Foo absence reason', group=group, kind='absence')
agenda.check_type_group = group
agenda.save()
resp = app.get('/manage/pricing/agenda/%s/pricing/%s/' % (agenda.pk, agenda_pricing.pk))
assert resp.form['booking_status'].options == [
('presence', False, 'Presence'),
('presence::foo-presence-reason', False, 'Presence (Foo presence reason)'),
('absence', False, 'Absence'),
('absence::foo-absence-reason', False, 'Absence (Foo absence reason)'),
]
resp.form['event_slug'] = 'foo'
resp.form['user_external_id'] = 'user:1'
resp.form['adult_external_id'] = 'adult:1'
resp.form['booking_status'] = 'presence'
resp = resp.form.submit()
assert mock_pricing_data.call_args_list[0][1]['check_status'] == {
'check_type': None,
'status': 'presence',
}
mock_pricing_data.reset_mock()
resp.form['booking_status'] = 'presence::foo-presence-reason'
resp = resp.form.submit()
assert mock_pricing_data.call_args_list[0][1]['check_status'] == {
'check_type': 'foo-presence-reason',
'status': 'presence',
}
mock_pricing_data.reset_mock()
resp.form['booking_status'] = 'absence'
resp = resp.form.submit()
assert mock_pricing_data.call_args_list[0][1]['check_status'] == {'check_type': None, 'status': 'absence'}
mock_pricing_data.reset_mock()
resp.form['booking_status'] = 'absence::foo-absence-reason'
resp = resp.form.submit()
assert mock_pricing_data.call_args_list[0][1]['check_status'] == {
'check_type': 'foo-absence-reason',
'status': 'absence',
}
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)