pricing: compute pricing with data retrieved from chrono (#65456)

This commit is contained in:
Lauréline Guérin 2022-06-02 12:04:45 +02:00
parent 1092c8a75c
commit cf75e822ee
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
6 changed files with 227 additions and 322 deletions

View File

@ -16,16 +16,17 @@
import copy
import dataclasses
import datetime
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.template import Context, RequestContext, Template, TemplateSyntaxError, VariableDoesNotExist
from django.utils.text import slugify
from django.utils.translation import ugettext_lazy as _
from lingo.agendas.models import Agenda
from lingo.agendas.models import Agenda, CheckType
from lingo.utils.misc import AgendaImportError, clean_import_data, generate_slug
@ -51,6 +52,10 @@ class PricingDataFormatError(PricingError):
pass
class PricingUnknownCheckStatusError(PricingError):
pass
class PricingEventNotCheckedError(PricingError):
pass
@ -59,10 +64,6 @@ class PricingBookingNotCheckedError(PricingError):
pass
class PricingSubscriptionError(PricingError):
pass
class PricingMultipleBookingError(PricingError):
pass
@ -203,10 +204,9 @@ class Pricing(models.Model):
context.push(original_context)
for key, tplt in (self.extra_variables or {}).items():
try:
template = Template(tplt)
except TemplateSyntaxError:
result[key] = Template(tplt).render(context)
except (TemplateSyntaxError, VariableDoesNotExist):
continue
result[key] = template.render(context)
return result
def get_extra_variables_keys(self):
@ -353,12 +353,26 @@ class AgendaPricing(models.Model):
}
@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 get_pricing_data(
request, agenda, event, subscription, check_status, booking, user_external_id, adult_external_id
):
agenda_pricing = AgendaPricing.get_agenda_pricing(agenda=agenda, event=event)
data = {
'event': event,
'subscription': subscription,
'booking': booking,
}
context = agenda_pricing.get_pricing_context(
request=request,
data=data,
user_external_id=user_external_id,
adult_external_id=adult_external_id,
)
pricing, criterias = agenda_pricing.compute_pricing(context=context)
modifier = agenda_pricing.get_booking_modifier(check_status=check_status)
return agenda_pricing.aggregate_pricing_data(
pricing=pricing, criterias=criterias, context=context, modifier=modifier
)
def aggregate_pricing_data(self, pricing, criterias, context, modifier):
if modifier['modifier_type'] == 'fixed':
@ -376,29 +390,18 @@ class AgendaPricing(models.Model):
}
@staticmethod
def get_agenda_pricing(event):
agenda = event.agenda
def get_agenda_pricing(agenda, event):
start_datetime = datetime.datetime.fromisoformat(event['start_datetime'])
try:
return agenda.agendapricing_set.get(
date_start__lte=event.start_datetime,
date_end__gt=event.start_datetime,
date_start__lte=start_datetime,
date_end__gt=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,
)
# noqa pylint: disable=undefined-variable
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}
def get_pricing_context(self, request, data, user_external_id, adult_external_id):
context = {'data': data, '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:
@ -442,54 +445,61 @@ class AgendaPricing(models.Model):
return pricing, criterias
def get_booking_modifier(self, event, user_external_id):
# event must be checked
if event.checked is False:
raise PricingEventNotCheckedError
def get_booking_modifier(self, check_status):
status = check_status['status']
if status not in ['error', 'not-booked', 'cancelled', 'presence', 'absence']:
raise PricingUnknownCheckStatusError
# search for an available subscription
self.get_subscription(event, user_external_id)
if status == 'error':
reason = check_status['error_reason']
# event must be checked
if reason == 'event-not-checked':
raise PricingEventNotCheckedError
# booking must be checked
if reason == 'booking-not-checked':
raise PricingBookingNotCheckedError
# too many bookings found
if reason == 'too-many-bookings-found':
raise PricingMultipleBookingError
# search for a booking
try:
booking = event.booking_set.get(user_external_id=user_external_id)
except Booking.DoesNotExist: # noqa pylint: disable=undefined-variable
# no booking
# no booking found
if status == 'not-booked':
return {
'status': 'not-booked',
'modifier_type': 'rate',
'modifier_rate': 0,
}
except Booking.MultipleObjectsReturned: # noqa pylint: disable=undefined-variable
raise PricingMultipleBookingError
# booking cancelled
if booking.cancellation_datetime is not None:
if status == 'cancelled':
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:
if not check_status['check_type']:
return {
'status': status,
'check_type_group': None,
'check_type': None,
'modifier_type': 'rate',
'modifier_rate': 100 if booking.user_was_present else 0,
'modifier_rate': 100 if status == 'presence' else 0,
}
check_type = booking.user_check_type
kind_mapping = {'presence': True, 'absence': False}
try:
check_type = CheckType.objects.get(
group=self.agenda.check_type_group_id, slug=check_status['check_type']
)
except CheckType.DoesNotExist:
raise PricingBookingCheckTypeError(
details={
'reason': 'not-found',
}
)
# check_type kind and user_was_present mismatch
if kind_mapping[check_type.kind] != booking.user_was_present:
if check_type.kind != status:
raise PricingBookingCheckTypeError(
details={
'check_type_group': check_type.group.slug,

View File

@ -89,9 +89,11 @@ TEMPLATES = [
'django.template.context_processors.static',
'django.template.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'publik_django_templatetags.wcs.context_processors.cards',
],
'builtins': [
'publik_django_templatetags.publik.templatetags.publik',
'publik_django_templatetags.wcs.templatetags.wcs',
'django.contrib.humanize.templatetags.humanize',
],
},

View File

@ -26,3 +26,12 @@ def simple_user():
@pytest.fixture
def admin_user():
return User.objects.create_superuser('admin', email=None, password='admin')
@pytest.fixture
def nocache(settings):
settings.CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
}
}

View File

@ -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

View File

@ -5,7 +5,7 @@ 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 django.utils.timezone import make_aware
from publik_django_templatetags.wcs.context_processors import Cards
from lingo.agendas.models import Agenda, CheckType, CheckTypeGroup
@ -26,7 +26,7 @@ from lingo.pricing.models import (
PricingMatrixCell,
PricingMatrixRow,
PricingMultipleBookingError,
PricingSubscriptionError,
PricingUnknownCheckStatusError,
)
pytestmark = pytest.mark.django_db
@ -222,17 +222,16 @@ def test_pricing_duplicate():
assert new_pricing.slug == 'bar'
@pytest.mark.xfail(reason='no link to events yet')
def test_get_agenda_pricing():
agenda = Agenda.objects.create(label='Foo bar', kind='events')
agenda = Agenda.objects.create(label='Foo bar')
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
)
event = {
'start_datetime': make_aware(datetime.datetime(2021, 9, 15, 12, 00)).isoformat(),
}
# not found
with pytest.raises(AgendaPricingNotFound):
AgendaPricing.get_agenda_pricing(event)
AgendaPricing.get_agenda_pricing(agenda=agenda, event=event)
# ok
agenda_pricing = AgendaPricing.objects.create(
@ -241,7 +240,7 @@ def test_get_agenda_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
assert AgendaPricing.get_agenda_pricing(agenda=agenda, event=event) == agenda_pricing
# more than one matching
AgendaPricing.objects.create(
@ -251,10 +250,9 @@ def test_get_agenda_pricing():
date_end=datetime.date(year=2021, month=9, day=16),
)
with pytest.raises(AgendaPricingNotFound):
AgendaPricing.get_agenda_pricing(event)
AgendaPricing.get_agenda_pricing(agenda=agenda, event=event)
@pytest.mark.xfail(reason='no link to events yet')
@pytest.mark.parametrize(
'event_date, found',
[
@ -269,11 +267,11 @@ def test_get_agenda_pricing():
],
)
def test_get_agenda_pricing_event_date(event_date, found):
agenda = Agenda.objects.create(label='Foo bar', kind='events')
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
event = Event.objects.create(
agenda=agenda, start_datetime=make_aware(datetime.datetime(*event_date)), places=10
)
event = {
'start_datetime': make_aware(datetime.datetime(*event_date)).isoformat(),
}
agenda_pricing = AgendaPricing.objects.create(
agenda=agenda,
pricing=pricing,
@ -281,19 +279,15 @@ def test_get_agenda_pricing_event_date(event_date, found):
date_end=datetime.date(year=2021, month=10, day=1),
)
if found:
assert AgendaPricing.get_agenda_pricing(event) == agenda_pricing
assert AgendaPricing.get_agenda_pricing(agenda=agenda, event=event) == agenda_pricing
else:
with pytest.raises(AgendaPricingNotFound):
AgendaPricing.get_agenda_pricing(event)
AgendaPricing.get_agenda_pricing(agenda=agenda, event=event)
@pytest.mark.xfail(reason='no link to events yet')
@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
)
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
agenda=agenda,
@ -301,20 +295,39 @@ def test_get_pricing_context(mock_send, context, nocache):
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') == {}
assert (
agenda_pricing.get_pricing_context(
request=context['request'], data={}, user_external_id='child:42', adult_external_id='parent:35'
)
== {}
)
pricing.extra_variables = {
'foo': 'bar',
'qf': '{{ 40|add:2 }}',
'domicile': 'commune',
'ids': '{{ cards|objects:"foo"|getlist:"id"|join:"," }}',
'bad': '{% if foo %}',
'syntax_error': '{% for %}',
'variable_error': '{{ "foo"|add:user.email }}',
'event': '{{ data.event.foo }}',
'subscription': '{{ data.subscription.foo }}',
'booking': '{{ data.booking.foo }}',
}
pricing.save()
assert agenda_pricing.get_pricing_context(event, 'child:42', 'parent:35') == {
data = {
'event': {'foo': 42},
'subscription': {'foo': 43},
'booking': {'foo': 44},
}
assert agenda_pricing.get_pricing_context(
request=context['request'], data=data, user_external_id='child:42', adult_external_id='parent:35'
) == {
'foo': 'bar',
'qf': '42',
'domicile': 'commune',
'ids': '1,2',
'event': '42',
'subscription': '43',
'booking': '44',
}
# user_external_id and adult_external_id can be used in variables
@ -323,7 +336,9 @@ def test_get_pricing_context(mock_send, context, nocache):
}
pricing.save()
mock_send.reset_mock()
agenda_pricing.get_pricing_context(event, 'child:42', 'parent:35')
agenda_pricing.get_pricing_context(
request=context['request'], data={}, user_external_id='child:42', adult_external_id='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 = {
@ -331,7 +346,9 @@ def test_get_pricing_context(mock_send, context, nocache):
}
pricing.save()
mock_send.reset_mock()
agenda_pricing.get_pricing_context(event, 'child:42', 'parent:35')
agenda_pricing.get_pricing_context(
request=context['request'], data={}, user_external_id='child:42', adult_external_id='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
@ -475,12 +492,22 @@ def test_compute_pricing():
)
@pytest.mark.xfail(reason='no link to events yet')
def test_get_booking_modifier_unknown_check_status():
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),
)
check_status = {'status': 'unknown'}
with pytest.raises(PricingUnknownCheckStatusError):
agenda_pricing.get_booking_modifier(check_status=check_status)
def test_get_booking_modifier_event_not_checked():
agenda = Agenda.objects.create(label='Foo bar')
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,
@ -488,110 +515,13 @@ def test_get_booking_modifier_event_not_checked():
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
)
check_status = {'status': 'error', 'error_reason': 'event-not-checked'}
with pytest.raises(PricingEventNotCheckedError):
agenda_pricing.get_booking_modifier(event, 'child:42')
agenda_pricing.get_booking_modifier(check_status=check_status)
@pytest.mark.xfail(reason='no link to events yet')
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),
],
)
@pytest.mark.xfail(reason='no link to events yet')
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')
@pytest.mark.xfail(reason='no link to events yet')
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,
)
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
agenda=agenda,
@ -599,35 +529,21 @@ def test_get_booking_modifier_no_booking():
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') == {
check_status = {'status': 'not-booked'}
assert agenda_pricing.get_booking_modifier(check_status=check_status) == {
'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')
check_status = {'status': 'error', 'error_reason': 'too-many-bookings-found'}
with pytest.raises(PricingMultipleBookingError):
agenda_pricing.get_booking_modifier(event, 'child:42')
agenda_pricing.get_booking_modifier(check_status=check_status)
@pytest.mark.xfail(reason='no link to events yet')
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())
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
agenda=agenda,
@ -635,29 +551,16 @@ def test_get_booking_modifier_booking_cancelled():
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') == {
check_status = {'status': 'cancelled'}
assert agenda_pricing.get_booking_modifier(check_status=check_status) == {
'status': 'cancelled',
'modifier_type': 'rate',
'modifier_rate': 0,
}
@pytest.mark.xfail(reason='no link to events yet')
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')
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
agenda=agenda,
@ -665,26 +568,36 @@ def test_get_booking_modifier_booking_not_checked():
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
)
check_status = {'status': 'error', 'error_reason': 'booking-not-checked'}
with pytest.raises(PricingBookingNotCheckedError):
agenda_pricing.get_booking_modifier(event, 'child:42')
agenda_pricing.get_booking_modifier(check_status=check_status)
@pytest.mark.xfail(reason='no link to events yet')
def test_get_booking_modifier_booking_absence():
agenda = Agenda.objects.create(label='Foo bar', kind='events')
Subscription.objects.create(
def test_get_booking_modifier_unknown_check_type():
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
agenda=agenda,
user_external_id='child:42',
pricing=pricing,
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)
check_status = {'status': 'presence', 'check_type': 'unknown'}
with pytest.raises(PricingBookingCheckTypeError) as e:
agenda_pricing.get_booking_modifier(check_status=check_status)
assert e.value.details == {
'reason': 'not-found',
}
check_status = {'status': 'absence', 'check_type': 'unknown'}
with pytest.raises(PricingBookingCheckTypeError) as e:
agenda_pricing.get_booking_modifier(check_status=check_status)
assert e.value.details == {
'reason': 'not-found',
}
def test_get_booking_modifier_booking_absence():
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
agenda=agenda,
@ -694,7 +607,8 @@ def test_get_booking_modifier_booking_absence():
)
# no check type
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
check_status = {'status': 'absence', 'check_type': ''}
assert agenda_pricing.get_booking_modifier(check_status=check_status) == {
'status': 'absence',
'check_type_group': None,
'check_type': None,
@ -702,13 +616,20 @@ def test_get_booking_modifier_booking_absence():
'modifier_rate': 0,
}
# check_type but incomplete configuration
# check_type but not configured on agenda
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()
check_status = {'status': 'absence', 'check_type': check_type.slug}
with pytest.raises(PricingBookingCheckTypeError) as e:
agenda_pricing.get_booking_modifier(event, 'child:42')
agenda_pricing.get_booking_modifier(check_status=check_status)
assert e.value.details == {
'reason': 'not-found',
}
# incomplete configuration
agenda.check_type_group = group
agenda.save()
with pytest.raises(PricingBookingCheckTypeError) as e:
agenda_pricing.get_booking_modifier(check_status=check_status)
assert e.value.details == {
'check_type_group': 'foo-bar',
'check_type': 'foo-reason',
@ -717,7 +638,7 @@ def test_get_booking_modifier_booking_absence():
check_type.pricing = 42
check_type.save()
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
assert agenda_pricing.get_booking_modifier(check_status=check_status) == {
'status': 'absence',
'check_type_group': 'foo-bar',
'check_type': 'foo-reason',
@ -727,7 +648,7 @@ def test_get_booking_modifier_booking_absence():
check_type.pricing = 0
check_type.save()
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
assert agenda_pricing.get_booking_modifier(check_status=check_status) == {
'status': 'absence',
'check_type_group': 'foo-bar',
'check_type': 'foo-reason',
@ -738,7 +659,7 @@ def test_get_booking_modifier_booking_absence():
check_type.pricing = None
check_type.pricing_rate = 20
check_type.save()
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
assert agenda_pricing.get_booking_modifier(check_status=check_status) == {
'status': 'absence',
'check_type_group': 'foo-bar',
'check_type': 'foo-reason',
@ -748,7 +669,7 @@ def test_get_booking_modifier_booking_absence():
check_type.pricing_rate = 0
check_type.save()
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
assert agenda_pricing.get_booking_modifier(check_status=check_status) == {
'status': 'absence',
'check_type_group': 'foo-bar',
'check_type': 'foo-reason',
@ -760,7 +681,7 @@ def test_get_booking_modifier_booking_absence():
check_type.kind = 'presence'
check_type.save()
with pytest.raises(PricingBookingCheckTypeError) as e:
agenda_pricing.get_booking_modifier(event, 'child:42')
agenda_pricing.get_booking_modifier(check_status=check_status)
assert e.value.details == {
'check_type_group': 'foo-bar',
'check_type': 'foo-reason',
@ -768,22 +689,8 @@ def test_get_booking_modifier_booking_absence():
}
@pytest.mark.xfail(reason='no link to events yet')
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)
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
agenda=agenda,
@ -793,7 +700,8 @@ def test_get_booking_modifier_booking_presence():
)
# no check type
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
check_status = {'status': 'presence', 'check_type': ''}
assert agenda_pricing.get_booking_modifier(check_status=check_status) == {
'status': 'presence',
'check_type_group': None,
'check_type': None,
@ -801,13 +709,20 @@ def test_get_booking_modifier_booking_presence():
'modifier_rate': 100,
}
# check_type but incomplete configuration
# check_type but not configured on agenda
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()
check_status = {'status': 'presence', 'check_type': check_type.slug}
with pytest.raises(PricingBookingCheckTypeError) as e:
agenda_pricing.get_booking_modifier(event, 'child:42')
agenda_pricing.get_booking_modifier(check_status=check_status)
assert e.value.details == {
'reason': 'not-found',
}
# incomplete configuration
agenda.check_type_group = group
agenda.save()
with pytest.raises(PricingBookingCheckTypeError) as e:
agenda_pricing.get_booking_modifier(check_status=check_status)
assert e.value.details == {
'check_type_group': 'foo-bar',
'check_type': 'foo-reason',
@ -816,7 +731,7 @@ def test_get_booking_modifier_booking_presence():
check_type.pricing = 42
check_type.save()
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
assert agenda_pricing.get_booking_modifier(check_status=check_status) == {
'status': 'presence',
'check_type_group': 'foo-bar',
'check_type': 'foo-reason',
@ -826,7 +741,7 @@ def test_get_booking_modifier_booking_presence():
check_type.pricing = 0
check_type.save()
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
assert agenda_pricing.get_booking_modifier(check_status=check_status) == {
'status': 'presence',
'check_type_group': 'foo-bar',
'check_type': 'foo-reason',
@ -837,7 +752,7 @@ def test_get_booking_modifier_booking_presence():
check_type.pricing = None
check_type.pricing_rate = 150
check_type.save()
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
assert agenda_pricing.get_booking_modifier(check_status=check_status) == {
'status': 'presence',
'check_type_group': 'foo-bar',
'check_type': 'foo-reason',
@ -847,7 +762,7 @@ def test_get_booking_modifier_booking_presence():
check_type.pricing_rate = 0
check_type.save()
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
assert agenda_pricing.get_booking_modifier(check_status=check_status) == {
'status': 'presence',
'check_type_group': 'foo-bar',
'check_type': 'foo-reason',
@ -859,7 +774,7 @@ def test_get_booking_modifier_booking_presence():
check_type.kind = 'absence'
check_type.save()
with pytest.raises(PricingBookingCheckTypeError) as e:
agenda_pricing.get_booking_modifier(event, 'child:42')
agenda_pricing.get_booking_modifier(check_status=check_status)
assert e.value.details == {
'check_type_group': 'foo-bar',
'check_type': 'foo-reason',
@ -867,21 +782,8 @@ def test_get_booking_modifier_booking_presence():
}
@pytest.mark.xfail(reason='no link to events yet')
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),
)
agenda = Agenda.objects.create(label='Foo bar')
category = CriteriaCategory.objects.create(label='Foo', slug='foo')
criteria = Criteria.objects.create(label='Bar', slug='bar', condition='True', category=category)
pricing = Pricing.objects.create(
@ -902,7 +804,16 @@ def test_get_pricing_data(context):
'foo:bar': 42,
},
)
assert AgendaPricing.get_pricing_data(context['request'], event, 'child:42', 'parent:35') == {
assert AgendaPricing.get_pricing_data(
request=context['request'],
agenda=agenda,
event={'start_datetime': make_aware(datetime.datetime(2021, 9, 15, 12, 00)).isoformat()},
subscription={},
check_status={'status': 'not-booked'},
booking={},
user_external_id='child:42',
adult_external_id='parent:35',
) == {
'pricing': 0,
'calculation_details': {
'pricing': 42,

View File

@ -1,7 +1,7 @@
import os
TIME_ZONE = 'Europe/Paris'
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
CACHES = {
'default': {
@ -38,4 +38,13 @@ KNOWN_SERVICES = {
'secondary': True,
},
},
'wcs': {
'default': {
'title': 'test',
'url': 'http://example.org',
'secret': 'chrono',
'orig': 'chrono',
'backoffice-menu-url': 'http://example.org/manage/',
}
},
}