pricing: apply modifier according to booking status (#64565)
This commit is contained in:
parent
301d280c9e
commit
e504199eab
|
@ -22,6 +22,7 @@ from django.template import Context, Template, TemplateSyntaxError
|
|||
from django.utils.text import slugify
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from chrono.agendas.models import Agenda, Booking, Subscription
|
||||
from chrono.utils.misc import generate_slug
|
||||
|
||||
|
||||
|
@ -47,6 +48,26 @@ class PricingDataFormatError(PricingError):
|
|||
pass
|
||||
|
||||
|
||||
class PricingEventNotCheckedError(PricingError):
|
||||
pass
|
||||
|
||||
|
||||
class PricingBookingNotCheckedError(PricingError):
|
||||
pass
|
||||
|
||||
|
||||
class PricingSubscriptionError(PricingError):
|
||||
pass
|
||||
|
||||
|
||||
class PricingMultipleBookingError(PricingError):
|
||||
pass
|
||||
|
||||
|
||||
class PricingBookingCheckTypeError(PricingError):
|
||||
pass
|
||||
|
||||
|
||||
class CriteriaCategory(models.Model):
|
||||
label = models.CharField(_('Label'), max_length=150)
|
||||
slug = models.SlugField(_('Identifier'), max_length=160, unique=True)
|
||||
|
@ -156,7 +177,7 @@ class PricingCriteriaCategory(models.Model):
|
|||
|
||||
|
||||
class AgendaPricing(models.Model):
|
||||
agenda = models.ForeignKey('agendas.Agenda', on_delete=models.CASCADE)
|
||||
agenda = models.ForeignKey(Agenda, on_delete=models.CASCADE)
|
||||
pricing = models.ForeignKey(Pricing, on_delete=models.CASCADE)
|
||||
date_start = models.DateField()
|
||||
date_end = models.DateField()
|
||||
|
@ -167,10 +188,22 @@ class AgendaPricing(models.Model):
|
|||
agenda_pricing = AgendaPricing.get_agenda_pricing(event)
|
||||
context = agenda_pricing.get_pricing_context(event, user_external_id, adult_external_id)
|
||||
pricing, criterias = agenda_pricing.compute_pricing(context)
|
||||
modifier = agenda_pricing.get_booking_modifier(event, user_external_id)
|
||||
return agenda_pricing.aggregate_pricing_data(pricing, criterias, context, modifier)
|
||||
|
||||
def aggregate_pricing_data(self, pricing, criterias, context, modifier):
|
||||
if modifier['modifier_type'] == 'fixed':
|
||||
pricing_amount = modifier['modifier_fixed']
|
||||
else:
|
||||
pricing_amount = pricing * modifier['modifier_rate'] / 100
|
||||
return {
|
||||
'pricing': pricing,
|
||||
'criterias': criterias,
|
||||
'context': context,
|
||||
'pricing': pricing_amount,
|
||||
'calculation_details': {
|
||||
'pricing': pricing,
|
||||
'criterias': criterias,
|
||||
'context': context,
|
||||
},
|
||||
'booking_details': modifier,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
|
@ -184,6 +217,16 @@ class AgendaPricing(models.Model):
|
|||
except (AgendaPricing.DoesNotExist, AgendaPricing.MultipleObjectsReturned):
|
||||
raise AgendaPricingNotFound
|
||||
|
||||
def get_subscription(self, event, user_external_id):
|
||||
try:
|
||||
return self.agenda.subscriptions.get(
|
||||
user_external_id=user_external_id,
|
||||
date_start__lte=event.start_datetime,
|
||||
date_end__gt=event.start_datetime,
|
||||
)
|
||||
except (Subscription.DoesNotExist, Subscription.MultipleObjectsReturned):
|
||||
raise PricingSubscriptionError
|
||||
|
||||
def get_pricing_context(self, event, user_external_id, adult_external_id):
|
||||
# FIXME: compute agenda pricing variables, add event data
|
||||
return {
|
||||
|
@ -227,3 +270,85 @@ class AgendaPricing(models.Model):
|
|||
raise PricingDataFormatError(details={'pricing': pricing_data, 'wanted': 'decimal'})
|
||||
|
||||
return pricing, criterias
|
||||
|
||||
def get_booking_modifier(self, event, user_external_id):
|
||||
# event must be checked
|
||||
if event.checked is False:
|
||||
raise PricingEventNotCheckedError
|
||||
|
||||
# search for an available subscription
|
||||
self.get_subscription(event, user_external_id)
|
||||
|
||||
# search for a booking
|
||||
try:
|
||||
booking = event.booking_set.get(user_external_id=user_external_id)
|
||||
except Booking.DoesNotExist:
|
||||
# no booking
|
||||
return {
|
||||
'status': 'not-booked',
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 0,
|
||||
}
|
||||
except Booking.MultipleObjectsReturned:
|
||||
raise PricingMultipleBookingError
|
||||
|
||||
# booking cancelled
|
||||
if booking.cancellation_datetime is not None:
|
||||
return {
|
||||
'status': 'cancelled',
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 0,
|
||||
}
|
||||
|
||||
# booking not cancelled, is must be checked
|
||||
if booking.user_was_present is None:
|
||||
raise PricingBookingNotCheckedError
|
||||
|
||||
status = 'presence' if booking.user_was_present else 'absence'
|
||||
# no check_type, default rates
|
||||
if booking.user_check_type is None:
|
||||
return {
|
||||
'status': status,
|
||||
'check_type_group': None,
|
||||
'check_type': None,
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 100 if booking.user_was_present else 0,
|
||||
}
|
||||
|
||||
check_type = booking.user_check_type
|
||||
kind_mapping = {'presence': True, 'absence': False}
|
||||
# check_type kind and user_was_present mismatch
|
||||
if kind_mapping[check_type.kind] != booking.user_was_present:
|
||||
raise PricingBookingCheckTypeError(
|
||||
details={
|
||||
'check_type_group': check_type.group.slug,
|
||||
'check_type': check_type.slug,
|
||||
'reason': 'wrong-kind',
|
||||
}
|
||||
)
|
||||
|
||||
# get pricing modifier
|
||||
if check_type.pricing is not None:
|
||||
return {
|
||||
'status': status,
|
||||
'check_type_group': check_type.group.slug,
|
||||
'check_type': check_type.slug,
|
||||
'modifier_type': 'fixed',
|
||||
'modifier_fixed': check_type.pricing,
|
||||
}
|
||||
if check_type.pricing_rate is not None:
|
||||
return {
|
||||
'status': status,
|
||||
'check_type_group': check_type.group.slug,
|
||||
'check_type': check_type.slug,
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': check_type.pricing_rate,
|
||||
}
|
||||
# pricing not found
|
||||
raise PricingBookingCheckTypeError(
|
||||
details={
|
||||
'check_type_group': check_type.group.slug,
|
||||
'check_type': check_type.slug,
|
||||
'reason': 'not-configured',
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import datetime
|
||||
|
||||
import pytest
|
||||
from django.utils.timezone import make_aware
|
||||
from django.utils.timezone import make_aware, now
|
||||
|
||||
from chrono.agendas.models import Agenda, Event
|
||||
from chrono.agendas.models import Agenda, Booking, CheckType, CheckTypeGroup, Event, Subscription
|
||||
from chrono.pricing.models import (
|
||||
AgendaPricing,
|
||||
AgendaPricingNotFound,
|
||||
|
@ -11,9 +11,14 @@ from chrono.pricing.models import (
|
|||
CriteriaCategory,
|
||||
CriteriaConditionNotFound,
|
||||
Pricing,
|
||||
PricingBookingCheckTypeError,
|
||||
PricingBookingNotCheckedError,
|
||||
PricingCriteriaCategory,
|
||||
PricingDataError,
|
||||
PricingDataFormatError,
|
||||
PricingEventNotCheckedError,
|
||||
PricingMultipleBookingError,
|
||||
PricingSubscriptionError,
|
||||
)
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
@ -199,32 +204,6 @@ def test_get_agenda_pricing_event_date(event_date, found):
|
|||
AgendaPricing.get_agenda_pricing(event)
|
||||
|
||||
|
||||
def test_get_pricing_data():
|
||||
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
|
||||
)
|
||||
category = CriteriaCategory.objects.create(label='Foo', slug='foo')
|
||||
criteria = Criteria.objects.create(label='Bar', slug='bar', condition='True', category=category)
|
||||
pricing = Pricing.objects.create(label='Foo bar')
|
||||
pricing.criterias.add(criteria)
|
||||
pricing.categories.add(category, through_defaults={'order': 1})
|
||||
AgendaPricing.objects.create(
|
||||
agenda=agenda,
|
||||
pricing=pricing,
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
pricing_data={
|
||||
'foo:bar': 42,
|
||||
},
|
||||
)
|
||||
assert AgendaPricing.get_pricing_data(event, 'child:42', 'parent:35') == {
|
||||
'pricing': 42,
|
||||
'criterias': {'foo': 'bar'},
|
||||
'context': {'domicile': 'commune', 'qf': 2},
|
||||
}
|
||||
|
||||
|
||||
def test_get_pricing_context():
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
event = Event.objects.create(
|
||||
|
@ -380,3 +359,578 @@ def test_compute_pricing():
|
|||
7,
|
||||
{'domicile': 'dom-1', 'qf': 'qf-0'},
|
||||
)
|
||||
|
||||
|
||||
def test_get_booking_modifier_event_not_checked():
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
event = Event.objects.create(
|
||||
agenda=agenda, start_datetime=make_aware(datetime.datetime(2021, 9, 15, 12, 00)), places=10
|
||||
)
|
||||
pricing = Pricing.objects.create(label='Foo bar')
|
||||
agenda_pricing = AgendaPricing.objects.create(
|
||||
agenda=agenda,
|
||||
pricing=pricing,
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
with pytest.raises(PricingEventNotCheckedError):
|
||||
agenda_pricing.get_booking_modifier(event, 'child:42')
|
||||
|
||||
|
||||
def test_get_booking_modifier_no_subscription():
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
event = Event.objects.create(
|
||||
agenda=agenda,
|
||||
start_datetime=make_aware(datetime.datetime(2021, 9, 15, 12, 00)),
|
||||
places=10,
|
||||
checked=True,
|
||||
)
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='child:35', # another user
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
pricing = Pricing.objects.create(label='Foo bar')
|
||||
agenda_pricing = AgendaPricing.objects.create(
|
||||
agenda=agenda,
|
||||
pricing=pricing,
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
with pytest.raises(PricingSubscriptionError):
|
||||
agenda_pricing.get_booking_modifier(event, 'child:42')
|
||||
|
||||
# more than one subscription found !
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='child:42',
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='child:42',
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
with pytest.raises(PricingSubscriptionError):
|
||||
agenda_pricing.get_booking_modifier(event, 'child:42')
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'event_date, success',
|
||||
[
|
||||
# just before first day
|
||||
((2021, 8, 31, 12, 00), False),
|
||||
# first day
|
||||
((2021, 9, 1, 12, 00), True),
|
||||
# last day
|
||||
((2021, 9, 30, 12, 00), True),
|
||||
# just after last day
|
||||
((2021, 10, 1, 12, 00), False),
|
||||
],
|
||||
)
|
||||
def test_get_booking_modifier_subscription_date(event_date, success):
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='child:42',
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
event = Event.objects.create(
|
||||
agenda=agenda, start_datetime=make_aware(datetime.datetime(*event_date)), places=10, checked=True
|
||||
)
|
||||
pricing = Pricing.objects.create(label='Foo bar')
|
||||
agenda_pricing = AgendaPricing.objects.create(
|
||||
agenda=agenda,
|
||||
pricing=pricing,
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
if success:
|
||||
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
|
||||
'status': 'not-booked',
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 0,
|
||||
}
|
||||
else:
|
||||
with pytest.raises(PricingSubscriptionError):
|
||||
agenda_pricing.get_booking_modifier(event, 'child:42')
|
||||
|
||||
|
||||
def test_get_booking_modifier_no_booking():
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='child:42',
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
event = Event.objects.create(
|
||||
agenda=agenda,
|
||||
start_datetime=make_aware(datetime.datetime(2021, 9, 15, 12, 00)),
|
||||
places=10,
|
||||
checked=True,
|
||||
)
|
||||
pricing = Pricing.objects.create(label='Foo bar')
|
||||
agenda_pricing = AgendaPricing.objects.create(
|
||||
agenda=agenda,
|
||||
pricing=pricing,
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
|
||||
'status': 'not-booked',
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 0,
|
||||
}
|
||||
|
||||
# more than one booking found !
|
||||
Booking.objects.create(event=event, user_external_id='child:42')
|
||||
Booking.objects.create(event=event, user_external_id='child:42')
|
||||
with pytest.raises(PricingMultipleBookingError):
|
||||
agenda_pricing.get_booking_modifier(event, 'child:42')
|
||||
|
||||
|
||||
def test_get_booking_modifier_booking_cancelled():
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='child:42',
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
event = Event.objects.create(
|
||||
agenda=agenda,
|
||||
start_datetime=make_aware(datetime.datetime(2021, 9, 15, 12, 00)),
|
||||
places=10,
|
||||
checked=True,
|
||||
)
|
||||
Booking.objects.create(event=event, user_external_id='child:42', cancellation_datetime=now())
|
||||
pricing = Pricing.objects.create(label='Foo bar')
|
||||
agenda_pricing = AgendaPricing.objects.create(
|
||||
agenda=agenda,
|
||||
pricing=pricing,
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
|
||||
'status': 'cancelled',
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 0,
|
||||
}
|
||||
|
||||
|
||||
def test_get_booking_modifier_booking_not_checked():
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='child:42',
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
event = Event.objects.create(
|
||||
agenda=agenda,
|
||||
start_datetime=make_aware(datetime.datetime(2021, 9, 15, 12, 00)),
|
||||
places=10,
|
||||
checked=True,
|
||||
)
|
||||
Booking.objects.create(event=event, user_external_id='child:42')
|
||||
pricing = Pricing.objects.create(label='Foo bar')
|
||||
agenda_pricing = AgendaPricing.objects.create(
|
||||
agenda=agenda,
|
||||
pricing=pricing,
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
with pytest.raises(PricingBookingNotCheckedError):
|
||||
agenda_pricing.get_booking_modifier(event, 'child:42')
|
||||
|
||||
|
||||
def test_get_booking_modifier_booking_absence():
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='child:42',
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
event = Event.objects.create(
|
||||
agenda=agenda,
|
||||
start_datetime=make_aware(datetime.datetime(2021, 9, 15, 12, 00)),
|
||||
places=10,
|
||||
checked=True,
|
||||
)
|
||||
booking = Booking.objects.create(event=event, user_external_id='child:42', user_was_present=False)
|
||||
pricing = Pricing.objects.create(label='Foo bar')
|
||||
agenda_pricing = AgendaPricing.objects.create(
|
||||
agenda=agenda,
|
||||
pricing=pricing,
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
|
||||
# no check type
|
||||
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
|
||||
'status': 'absence',
|
||||
'check_type_group': None,
|
||||
'check_type': None,
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 0,
|
||||
}
|
||||
|
||||
# check_type but incomplete configuration
|
||||
group = CheckTypeGroup.objects.create(label='Foo bar')
|
||||
check_type = CheckType.objects.create(label='Foo reason', group=group, kind='absence')
|
||||
booking.user_check_type = check_type
|
||||
booking.save()
|
||||
with pytest.raises(PricingBookingCheckTypeError) as e:
|
||||
agenda_pricing.get_booking_modifier(event, 'child:42')
|
||||
assert e.value.details == {
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'reason': 'not-configured',
|
||||
}
|
||||
|
||||
check_type.pricing = 42
|
||||
check_type.save()
|
||||
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
|
||||
'status': 'absence',
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'modifier_type': 'fixed',
|
||||
'modifier_fixed': 42,
|
||||
}
|
||||
|
||||
check_type.pricing = 0
|
||||
check_type.save()
|
||||
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
|
||||
'status': 'absence',
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'modifier_type': 'fixed',
|
||||
'modifier_fixed': 0,
|
||||
}
|
||||
|
||||
check_type.pricing = None
|
||||
check_type.pricing_rate = 20
|
||||
check_type.save()
|
||||
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
|
||||
'status': 'absence',
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 20,
|
||||
}
|
||||
|
||||
check_type.pricing_rate = 0
|
||||
check_type.save()
|
||||
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
|
||||
'status': 'absence',
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 0,
|
||||
}
|
||||
|
||||
# bad check type kind
|
||||
check_type.kind = 'presence'
|
||||
check_type.save()
|
||||
with pytest.raises(PricingBookingCheckTypeError) as e:
|
||||
agenda_pricing.get_booking_modifier(event, 'child:42')
|
||||
assert e.value.details == {
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'reason': 'wrong-kind',
|
||||
}
|
||||
|
||||
|
||||
def test_get_booking_modifier_booking_presence():
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='child:42',
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
event = Event.objects.create(
|
||||
agenda=agenda,
|
||||
start_datetime=make_aware(datetime.datetime(2021, 9, 15, 12, 00)),
|
||||
places=10,
|
||||
checked=True,
|
||||
)
|
||||
booking = Booking.objects.create(event=event, user_external_id='child:42', user_was_present=True)
|
||||
pricing = Pricing.objects.create(label='Foo bar')
|
||||
agenda_pricing = AgendaPricing.objects.create(
|
||||
agenda=agenda,
|
||||
pricing=pricing,
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
|
||||
# no check type
|
||||
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
|
||||
'status': 'presence',
|
||||
'check_type_group': None,
|
||||
'check_type': None,
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 100,
|
||||
}
|
||||
|
||||
# check_type but incomplete configuration
|
||||
group = CheckTypeGroup.objects.create(label='Foo bar')
|
||||
check_type = CheckType.objects.create(label='Foo reason', group=group, kind='presence')
|
||||
booking.user_check_type = check_type
|
||||
booking.save()
|
||||
with pytest.raises(PricingBookingCheckTypeError) as e:
|
||||
agenda_pricing.get_booking_modifier(event, 'child:42')
|
||||
assert e.value.details == {
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'reason': 'not-configured',
|
||||
}
|
||||
|
||||
check_type.pricing = 42
|
||||
check_type.save()
|
||||
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
|
||||
'status': 'presence',
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'modifier_type': 'fixed',
|
||||
'modifier_fixed': 42,
|
||||
}
|
||||
|
||||
check_type.pricing = 0
|
||||
check_type.save()
|
||||
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
|
||||
'status': 'presence',
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'modifier_type': 'fixed',
|
||||
'modifier_fixed': 0,
|
||||
}
|
||||
|
||||
check_type.pricing = None
|
||||
check_type.pricing_rate = 150
|
||||
check_type.save()
|
||||
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
|
||||
'status': 'presence',
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 150,
|
||||
}
|
||||
|
||||
check_type.pricing_rate = 0
|
||||
check_type.save()
|
||||
assert agenda_pricing.get_booking_modifier(event, 'child:42') == {
|
||||
'status': 'presence',
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 0,
|
||||
}
|
||||
|
||||
# bad check type kind
|
||||
check_type.kind = 'absence'
|
||||
check_type.save()
|
||||
with pytest.raises(PricingBookingCheckTypeError) as e:
|
||||
agenda_pricing.get_booking_modifier(event, 'child:42')
|
||||
assert e.value.details == {
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'reason': 'wrong-kind',
|
||||
}
|
||||
|
||||
|
||||
def test_get_pricing_data():
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
event = Event.objects.create(
|
||||
agenda=agenda,
|
||||
start_datetime=make_aware(datetime.datetime(2021, 9, 15, 12, 00)),
|
||||
places=10,
|
||||
checked=True,
|
||||
)
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='child:42',
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
category = CriteriaCategory.objects.create(label='Foo', slug='foo')
|
||||
criteria = Criteria.objects.create(label='Bar', slug='bar', condition='True', category=category)
|
||||
pricing = Pricing.objects.create(label='Foo bar')
|
||||
pricing.criterias.add(criteria)
|
||||
pricing.categories.add(category, through_defaults={'order': 1})
|
||||
AgendaPricing.objects.create(
|
||||
agenda=agenda,
|
||||
pricing=pricing,
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
pricing_data={
|
||||
'foo:bar': 42,
|
||||
},
|
||||
)
|
||||
assert AgendaPricing.get_pricing_data(event, 'child:42', 'parent:35') == {
|
||||
'pricing': 0,
|
||||
'calculation_details': {
|
||||
'pricing': 42,
|
||||
'criterias': {'foo': 'bar'},
|
||||
'context': {'domicile': 'commune', 'qf': 2},
|
||||
},
|
||||
'booking_details': {
|
||||
'status': 'not-booked',
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 0,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'modifier, pricing_amount',
|
||||
[
|
||||
# not booked
|
||||
(
|
||||
{
|
||||
'status': 'not-booked',
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 0,
|
||||
},
|
||||
0,
|
||||
),
|
||||
# cancelled
|
||||
(
|
||||
{
|
||||
'status': 'cancelled',
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 0,
|
||||
},
|
||||
0,
|
||||
),
|
||||
# absence
|
||||
(
|
||||
{
|
||||
'status': 'absence',
|
||||
'check_type_group': None,
|
||||
'check_type': None,
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 0,
|
||||
},
|
||||
0,
|
||||
),
|
||||
(
|
||||
{
|
||||
'status': 'absence',
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'modifier_type': 'fixed',
|
||||
'modifier_fixed': 35,
|
||||
},
|
||||
35,
|
||||
),
|
||||
(
|
||||
{
|
||||
'status': 'absence',
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'modifier_type': 'fixed',
|
||||
'modifier_fixed': 0,
|
||||
},
|
||||
0,
|
||||
),
|
||||
(
|
||||
{
|
||||
'status': 'absence',
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 20,
|
||||
},
|
||||
8.4,
|
||||
),
|
||||
(
|
||||
{
|
||||
'status': 'absence',
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 0,
|
||||
},
|
||||
0,
|
||||
),
|
||||
# presence
|
||||
(
|
||||
{
|
||||
'status': 'presence',
|
||||
'check_type_group': None,
|
||||
'check_type': None,
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 100,
|
||||
},
|
||||
42,
|
||||
),
|
||||
(
|
||||
{
|
||||
'status': 'presence',
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'modifier_type': 'fixed',
|
||||
'modifier_fixed': 35,
|
||||
},
|
||||
35,
|
||||
),
|
||||
(
|
||||
{
|
||||
'status': 'presence',
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'modifier_type': 'fixed',
|
||||
'modifier_fixed': 0,
|
||||
},
|
||||
0,
|
||||
),
|
||||
(
|
||||
{
|
||||
'status': 'presence',
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 150,
|
||||
},
|
||||
63,
|
||||
),
|
||||
(
|
||||
{
|
||||
'status': 'presence',
|
||||
'check_type_group': 'foo-bar',
|
||||
'check_type': 'foo-reason',
|
||||
'modifier_type': 'rate',
|
||||
'modifier_rate': 0,
|
||||
},
|
||||
0,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_aggregate_pricing_data(modifier, pricing_amount):
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
pricing = Pricing.objects.create(label='Foo bar')
|
||||
agenda_pricing = AgendaPricing.objects.create(
|
||||
agenda=agenda,
|
||||
pricing=pricing,
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
|
||||
assert agenda_pricing.aggregate_pricing_data(
|
||||
pricing=42, criterias={'foo': 'bar'}, context={'domicile': 'commune', 'qf': 2}, modifier=modifier
|
||||
) == {
|
||||
'pricing': pricing_amount,
|
||||
'calculation_details': {
|
||||
'pricing': 42,
|
||||
'criterias': {'foo': 'bar'},
|
||||
'context': {'domicile': 'commune', 'qf': 2},
|
||||
},
|
||||
'booking_details': modifier,
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue