pricing: compute pricing with data retrieved from chrono (#65456)
This commit is contained in:
parent
1092c8a75c
commit
cf75e822ee
|
@ -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,
|
||||
|
|
|
@ -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',
|
||||
],
|
||||
},
|
||||
|
|
|
@ -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',
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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,
|
||||
|
|
|
@ -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/',
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue