lingo/tests/pricing/test_models.py

1695 lines
62 KiB
Python

import datetime
import json
from unittest import mock
import pytest
from django.template import Context
from django.test.client import RequestFactory
from django.utils.timezone import make_aware
from publik_django_templatetags.wcs.context_processors import Cards
from lingo.agendas.models import Agenda, CheckType, CheckTypeGroup
from lingo.pricing.models import (
AgendaPricing,
AgendaPricingNotFound,
Criteria,
CriteriaCategory,
CriteriaConditionNotFound,
MultipleDefaultCriteriaCondition,
Pricing,
PricingBookingCheckTypeError,
PricingBookingNotCheckedError,
PricingCriteriaCategory,
PricingDataError,
PricingDataFormatError,
PricingEventNotCheckedError,
PricingMatrix,
PricingMatrixCell,
PricingMatrixRow,
PricingMultipleBookingError,
PricingUnknownCheckStatusError,
)
pytestmark = pytest.mark.django_db
@pytest.fixture
def context():
return Context(
{
'cards': Cards(),
'request': RequestFactory().get('/'),
}
)
class MockedRequestResponse(mock.Mock):
status_code = 200
def json(self):
return json.loads(self.content)
def mocked_requests_send(request, **kwargs):
data = [{'id': 1, 'fields': {'foo': 'bar'}}, {'id': 2, 'fields': {'foo': 'baz'}}] # fake result
return MockedRequestResponse(content=json.dumps({'data': data}))
def test_criteria_category_slug():
category = CriteriaCategory.objects.create(label='Foo bar')
assert category.slug == 'foo-bar'
def test_criteria_category_existing_slug():
category = CriteriaCategory.objects.create(label='Foo bar', slug='bar')
assert category.slug == 'bar'
def test_criteria_category_duplicate_slugs():
category = CriteriaCategory.objects.create(label='Foo baz')
assert category.slug == 'foo-baz'
category = CriteriaCategory.objects.create(label='Foo baz')
assert category.slug == 'foo-baz-1'
category = CriteriaCategory.objects.create(label='Foo baz')
assert category.slug == 'foo-baz-2'
def test_criteria_slug():
category = CriteriaCategory.objects.create(label='Foo')
criteria = Criteria.objects.create(label='Foo bar', category=category)
assert criteria.slug == 'foo-bar'
def test_criteria_existing_slug():
category = CriteriaCategory.objects.create(label='Foo')
criteria = Criteria.objects.create(label='Foo bar', slug='bar', category=category)
assert criteria.slug == 'bar'
def test_criteria_duplicate_slugs():
category = CriteriaCategory.objects.create(label='Foo')
category2 = CriteriaCategory.objects.create(label='Bar')
Criteria.objects.create(label='Foo baz', slug='foo-baz', category=category2)
criteria = Criteria.objects.create(label='Foo baz', category=category)
assert criteria.slug == 'foo-baz'
criteria = Criteria.objects.create(label='Foo baz', category=category)
assert criteria.slug == 'foo-baz-1'
criteria = Criteria.objects.create(label='Foo baz', category=category)
assert criteria.slug == 'foo-baz-2'
def test_criteria_order():
category = CriteriaCategory.objects.create(label='Foo')
criteria = Criteria.objects.create(label='Foo bar', category=category)
assert criteria.order == 1
criteria = Criteria.objects.create(label='Foo bar', category=category, default=True)
assert criteria.order == 0
def test_criteria_existing_order():
category = CriteriaCategory.objects.create(label='Foo')
criteria = Criteria.objects.create(label='Foo bar', order=42, category=category)
assert criteria.order == 42
criteria = Criteria.objects.create(label='Foo bar', order=42, category=category, default=True)
assert criteria.order == 0
def test_criteria_duplicate_orders():
category = CriteriaCategory.objects.create(label='Foo')
category2 = CriteriaCategory.objects.create(label='Bar')
Criteria.objects.create(label='Foo baz', order=1, category=category2)
criteria = Criteria.objects.create(label='Foo baz', category=category)
assert criteria.order == 1
criteria = Criteria.objects.create(label='Foo baz', category=category)
assert criteria.order == 2
criteria = Criteria.objects.create(label='Foo baz', category=category)
assert criteria.order == 3
criteria.default = True
criteria.save()
assert criteria.order == 0
criteria = Criteria.objects.create(label='Foo baz', category=category, default=True)
assert criteria.order == 0
def test_pricing_slug():
pricing = Pricing.objects.create(label='Foo bar')
assert pricing.slug == 'foo-bar'
def test_pricing_existing_slug():
pricing = Pricing.objects.create(label='Foo bar', slug='bar')
assert pricing.slug == 'bar'
def test_pricing_duplicate_slugs():
pricing = Pricing.objects.create(label='Foo baz')
assert pricing.slug == 'foo-baz'
pricing = Pricing.objects.create(label='Foo baz')
assert pricing.slug == 'foo-baz-1'
pricing = Pricing.objects.create(label='Foo baz')
assert pricing.slug == 'foo-baz-2'
def test_pricing_category_criteria_order():
category = CriteriaCategory.objects.create(label='Foo')
pricing = Pricing.objects.create(label='Foo bar')
pcc = PricingCriteriaCategory.objects.create(pricing=pricing, category=category)
assert pcc.order == 1
def test_pricing_category_criteria_existing_order():
category = CriteriaCategory.objects.create(label='Foo')
pricing = Pricing.objects.create(label='Foo bar')
pcc = PricingCriteriaCategory.objects.create(order=42, pricing=pricing, category=category)
assert pcc.order == 42
def test_pricing_category_criteria_duplicate_orders():
category1 = CriteriaCategory.objects.create(label='Foo')
category2 = CriteriaCategory.objects.create(label='Bar')
category3 = CriteriaCategory.objects.create(label='Baz')
pricing = Pricing.objects.create(label='Foo bar')
pricing2 = Pricing.objects.create(label='Foo baz')
PricingCriteriaCategory.objects.create(order=1, pricing=pricing2, category=category1)
PricingCriteriaCategory.objects.create(order=2, pricing=pricing2, category=category2)
PricingCriteriaCategory.objects.create(order=3, pricing=pricing2, category=category3)
pcc = PricingCriteriaCategory.objects.create(pricing=pricing, category=category1)
assert pcc.order == 1
pcc = PricingCriteriaCategory.objects.create(pricing=pricing, category=category2)
assert pcc.order == 2
pcc = PricingCriteriaCategory.objects.create(pricing=pricing, category=category3)
assert pcc.order == 3
def test_pricing_duplicate():
category1 = CriteriaCategory.objects.create(label='Cat 1')
Criteria.objects.create(label='Crit 1-1', slug='crit-1-1', category=category1, order=1)
Criteria.objects.create(label='Crit 1-2', slug='crit-1-2', category=category1, order=2)
category2 = CriteriaCategory.objects.create(label='Cat 2')
Criteria.objects.create(label='Crit 2-1', slug='crit-2-1', category=category2, order=1)
Criteria.objects.create(label='Crit 2-2', slug='crit-2-2', category=category2, order=2)
Criteria.objects.create(label='Crit 2-3', slug='crit-2-3', category=category2, order=3)
category3 = CriteriaCategory.objects.create(label='Cat 3')
Criteria.objects.create(label='Crit 3-1', slug='crit-3-1', category=category3, order=1)
Criteria.objects.create(label='Crit 3-3', slug='crit-3-3', category=category3, order=3)
Criteria.objects.create(label='Crit 3-4', slug='crit-3-4', category=category3, order=4)
Criteria.objects.create(label='Crit 3-2', slug='crit-3-2', category=category3, order=2)
not_used = Criteria.objects.create(label='Not used', slug='crit-3-notused', category=category3, order=5)
pricing = Pricing.objects.create(
label='Foo',
extra_variables={
'foo': 'bar',
},
)
pricing.categories.add(category1, through_defaults={'order': 1})
pricing.categories.add(category2, through_defaults={'order': 2})
pricing.categories.add(category3, through_defaults={'order': 3})
pricing.criterias.set(Criteria.objects.exclude(pk=not_used.pk))
new_pricing = pricing.duplicate()
assert new_pricing.label == 'Copy of Foo'
assert new_pricing.slug == 'copy-of-foo'
assert new_pricing.extra_variables == pricing.extra_variables
assert list(new_pricing.criterias.all()) == list(pricing.criterias.all())
original_pcc_categories = list(
PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('category', flat=True)
)
new_pcc_categories = list(
PricingCriteriaCategory.objects.filter(pricing=new_pricing).values_list('category', flat=True)
)
assert new_pcc_categories == original_pcc_categories
original_pcc_orders = list(
PricingCriteriaCategory.objects.filter(pricing=pricing).values_list('order', flat=True)
)
new_pcc_orders = list(
PricingCriteriaCategory.objects.filter(pricing=new_pricing).values_list('order', flat=True)
)
assert new_pcc_orders == original_pcc_orders
new_pricing = pricing.duplicate(label='Bar')
assert new_pricing.label == 'Bar'
assert new_pricing.slug == 'bar'
def test_agenda_pricing_slug():
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
label='Foo bar',
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.slug == 'foo-bar'
def test_agenda_pricing_existing_slug():
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
label='Foo bar',
slug='bar',
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.slug == 'bar'
def test_agenda_pricing_duplicate_slugs():
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
label='Foo baz',
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.slug == 'foo-baz'
agenda_pricing = AgendaPricing.objects.create(
label='Foo baz',
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.slug == 'foo-baz-1'
agenda_pricing = AgendaPricing.objects.create(
label='Foo baz',
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.slug == 'foo-baz-2'
def test_get_agenda_pricing():
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
start_date = datetime.datetime(2021, 9, 15)
# not found
with pytest.raises(AgendaPricingNotFound):
AgendaPricing.get_agenda_pricing(
agenda=agenda,
start_date=start_date,
flat_fee_schedule=False,
)
with pytest.raises(AgendaPricingNotFound):
AgendaPricing.get_agenda_pricing(
agenda=agenda,
start_date=start_date,
flat_fee_schedule=True,
)
# ok
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
flat_fee_schedule=False,
)
agenda_pricing.agendas.add(agenda)
agenda_pricing2 = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
flat_fee_schedule=True,
)
agenda_pricing2.agendas.add(agenda)
assert (
AgendaPricing.get_agenda_pricing(
agenda=agenda,
start_date=start_date,
flat_fee_schedule=False,
)
== agenda_pricing
)
assert (
AgendaPricing.get_agenda_pricing(
agenda=agenda,
start_date=start_date,
flat_fee_schedule=True,
)
== agenda_pricing2
)
# more than one matching
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=14),
date_end=datetime.date(year=2021, month=9, day=16),
flat_fee_schedule=False,
)
agenda_pricing.agendas.add(agenda)
agenda_pricing2 = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=14),
date_end=datetime.date(year=2021, month=9, day=16),
flat_fee_schedule=True,
)
agenda_pricing2.agendas.add(agenda)
with pytest.raises(AgendaPricingNotFound):
AgendaPricing.get_agenda_pricing(
agenda=agenda,
start_date=start_date,
flat_fee_schedule=False,
)
AgendaPricing.get_agenda_pricing(
agenda=agenda,
start_date=start_date,
flat_fee_schedule=True,
)
@pytest.mark.parametrize(
'start_date, found',
[
# just before first day
((2021, 8, 31), False),
# first day
((2021, 9, 1), True),
# last day
((2021, 9, 30), True),
# just after last day
((2021, 10, 1), False),
],
)
def test_get_agenda_pricing_start_date(start_date, found):
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
flat_fee_schedule=False,
)
agenda_pricing.agendas.add(agenda)
agenda_pricing2 = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
flat_fee_schedule=True,
)
agenda_pricing2.agendas.add(agenda)
start_date = datetime.date(*start_date)
if found:
assert (
AgendaPricing.get_agenda_pricing(
agenda=agenda,
start_date=start_date,
flat_fee_schedule=False,
)
== agenda_pricing
)
assert (
AgendaPricing.get_agenda_pricing(
agenda=agenda,
start_date=start_date,
flat_fee_schedule=True,
)
== agenda_pricing2
)
else:
with pytest.raises(AgendaPricingNotFound):
AgendaPricing.get_agenda_pricing(
agenda=agenda,
start_date=start_date,
flat_fee_schedule=False,
)
AgendaPricing.get_agenda_pricing(
agenda=agenda,
start_date=start_date,
flat_fee_schedule=True,
)
@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')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
)
agenda_pricing.agendas.add(agenda)
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:"," }}',
'syntax_error': '{% for %}',
'variable_error': '{{ "foo"|add:user.email }}',
'event': '{{ data.event.foo }}',
'subscription': '{{ data.subscription.foo }}',
'booking': '{{ data.booking.foo }}',
}
pricing.save()
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
pricing.extra_variables = {
'qf': '{{ cards|objects:"qf"|filter_by:"foo"|filter_value:user_external_id|filter_by:"bar"|filter_value:adult_external_id|list }}',
}
pricing.save()
mock_send.reset_mock()
agenda_pricing.get_pricing_context(
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 = {
'qf': '{{ cards|objects:"qf"|filter_by:"foo"|filter_value:user_external_raw_id|filter_by:"bar"|filter_value:adult_external_raw_id|list }}',
}
pricing.save()
mock_send.reset_mock()
agenda_pricing.get_pricing_context(
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
@pytest.mark.parametrize(
'condition, context, result',
[
('qf < 1', {}, False),
('qf < 1', {'qf': 'foo'}, False),
('qf < 1', {'qf': 1}, False),
('qf < 1', {'qf': 0.9}, True),
('1 <= qf and qf < 2', {'qf': 0}, False),
('1 <= qf and qf < 2', {'qf': 2}, False),
('1 <= qf and qf < 2', {'qf': 10}, False),
('1 <= qf and qf < 2', {'qf': 1}, True),
('1 <= qf and qf < 2', {'qf': 1.5}, True),
# no condition
('', {}, False),
],
)
def test_compute_condition(condition, context, result):
category = CriteriaCategory.objects.create(label='QF', slug='qf')
criteria = Criteria.objects.create(label='FOO', condition=condition, category=category)
assert criteria.compute_condition(context) == result
def test_compute_pricing():
agenda = Agenda.objects.create(label='Foo bar')
category = CriteriaCategory.objects.create(label='QF', slug='qf')
pricing = Pricing.objects.create(label='Foo bar')
pricing.categories.add(category, through_defaults={'order': 1})
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
)
agenda_pricing.agendas.add(agenda)
# no criteria defined on agenda_pricing
with pytest.raises(CriteriaConditionNotFound) as e:
agenda_pricing.compute_pricing(context={'qf': 2})
assert e.value.details == {'category': 'qf'}
# conditions are not set
criteria1 = Criteria.objects.create(label='QF < 1', slug='qf-0', category=category)
criteria2 = Criteria.objects.create(label='QF >= 1', slug='qf-1', category=category)
pricing.criterias.add(criteria1)
pricing.criterias.add(criteria2)
with pytest.raises(CriteriaConditionNotFound) as e:
agenda_pricing.compute_pricing(context={'qf': 2})
assert e.value.details == {'category': 'qf'}
# conditions set, but no match
criteria1.condition = 'qf < 1'
criteria1.save()
criteria2.condition = 'False'
criteria2.save()
with pytest.raises(CriteriaConditionNotFound) as e:
agenda_pricing.compute_pricing(context={'qf': 2})
assert e.value.details == {'category': 'qf'}
# but with a default criteria, there is a match, but agenda_pricing.pricing_data is not defined
default_criteria1 = Criteria.objects.create(
label='Else 1', slug='else-1', category=category, default=True
)
pricing.criterias.add(default_criteria1)
with pytest.raises(PricingDataError) as e:
agenda_pricing.compute_pricing(context={'qf': 2})
assert e.value.details == {'criterias': {'qf': 'else-1'}}
# with more than one default criteria, fail
default_criteria2 = Criteria.objects.create(
label='Else 2', slug='else-2', category=category, default=True
)
pricing.criterias.add(default_criteria2)
with pytest.raises(MultipleDefaultCriteriaCondition) as e:
agenda_pricing.compute_pricing(context={'qf': 2})
assert e.value.details == {'category': 'qf'}
Criteria.objects.filter(default=True).delete() # remove default criterias
# criteria found, but agenda_pricing.pricing_data is not defined
criteria1.condition = 'qf < 1'
criteria1.save()
criteria2.condition = 'qf >= 1'
criteria2.save()
with pytest.raises(PricingDataError) as e:
agenda_pricing.compute_pricing(context={'qf': 2})
assert e.value.details == {'criterias': {'qf': 'qf-1'}}
# criteria not found in pricing_data
agenda_pricing.pricing_data = {
'qf:qf-0': 42,
}
agenda_pricing.save()
with pytest.raises(PricingDataError) as e:
agenda_pricing.compute_pricing(context={'qf': 2})
assert e.value.details == {'criterias': {'qf': 'qf-1'}}
# criteria found, but value is wrong
for value in ['foo', ['foo']]:
agenda_pricing.pricing_data = {
'qf:qf-0': 42,
'qf:qf-1': value,
}
agenda_pricing.save()
with pytest.raises(PricingDataFormatError) as e:
agenda_pricing.compute_pricing(context={'qf': 2})
assert e.value.details == {'pricing': value, 'wanted': 'decimal'}
for value in [[], {}]:
agenda_pricing.pricing_data = {
'qf:qf-0': 42,
'qf:qf-1': value,
}
agenda_pricing.save()
with pytest.raises(PricingDataError) as e:
agenda_pricing.compute_pricing(context={'qf': 2})
assert e.value.details == {'criterias': {'qf': 'qf-1'}}
# correct value (decimal)
agenda_pricing.pricing_data = {
'qf:qf-0': 42,
'qf:qf-1': 52,
}
agenda_pricing.save()
assert agenda_pricing.compute_pricing(context={'qf': 2}) == (52, {'qf': 'qf-1'})
# more complexe pricing model
category2 = CriteriaCategory.objects.create(label='Domicile', slug='domicile')
criteria1 = Criteria.objects.create(
label='Commune', slug='dom-0', condition='domicile == "commune"', category=category2, order=1
)
criteria2 = Criteria.objects.create(
label='Hors commune', slug='else', category=category2, default=True, order=0
)
pricing.categories.add(category2, through_defaults={'order': 2})
pricing.criterias.add(criteria1)
pricing.criterias.add(criteria2)
# correct definition
agenda_pricing.pricing_data = {
'domicile:dom-0': {
'qf:qf-0': 3,
'qf:qf-1': 5,
},
'domicile:else': {
'qf:qf-0': 7,
'qf:qf-1': 10,
},
}
agenda_pricing.save()
assert agenda_pricing.compute_pricing(context={'qf': 2, 'domicile': 'commune'}) == (
5,
{'domicile': 'dom-0', 'qf': 'qf-1'},
)
assert agenda_pricing.compute_pricing(context={'qf': 0, 'domicile': 'commune'}) == (
3,
{'domicile': 'dom-0', 'qf': 'qf-0'},
)
assert agenda_pricing.compute_pricing(context={'qf': 2, 'domicile': 'ext'}) == (
10,
{'domicile': 'else', 'qf': 'qf-1'},
)
assert agenda_pricing.compute_pricing(context={'qf': 0, 'domicile': 'ext'}) == (
7,
{'domicile': 'else', 'qf': 'qf-0'},
)
# category ordering doesn't matter
PricingCriteriaCategory.objects.filter(pricing=pricing, category=category).update(order=2)
PricingCriteriaCategory.objects.filter(pricing=pricing, category=category2).update(order=1)
assert agenda_pricing.compute_pricing(context={'qf': 2, 'domicile': 'commune'}) == (
5,
{'domicile': 'dom-0', 'qf': 'qf-1'},
)
assert agenda_pricing.compute_pricing(context={'qf': 0, 'domicile': 'commune'}) == (
3,
{'domicile': 'dom-0', 'qf': 'qf-0'},
)
assert agenda_pricing.compute_pricing(context={'qf': 2, 'domicile': 'ext'}) == (
10,
{'domicile': 'else', 'qf': 'qf-1'},
)
assert agenda_pricing.compute_pricing(context={'qf': 0, 'domicile': 'ext'}) == (
7,
{'domicile': 'else', 'qf': 'qf-0'},
)
def test_format_pricing_data():
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
)
agenda_pricing.agendas.add(agenda)
assert agenda_pricing.format_pricing_data() == {}
agenda_pricing.pricing_data = {
'cat-1:crit-1-1': {
'cat-2:crit-2-1': {
'cat-3:crit-3-1': 111,
'cat-3:crit-3-3': 'not-a-decimal',
'cat-3:crit-3-4': 114,
},
'cat-2:crit-2-3': {
'cat-3:crit-3-2': 132,
},
},
'cat-1:crit-1-2': {
'cat-2:crit-2-2': {
'cat-3:crit-3-3': 223,
},
},
}
agenda_pricing.save()
assert agenda_pricing.format_pricing_data() == {
'cat-1:crit-1-1||cat-2:crit-2-1||cat-3:crit-3-1': 111,
'cat-1:crit-1-1||cat-2:crit-2-1||cat-3:crit-3-3': 'not-a-decimal',
'cat-1:crit-1-1||cat-2:crit-2-1||cat-3:crit-3-4': 114,
'cat-1:crit-1-1||cat-2:crit-2-3||cat-3:crit-3-2': 132,
'cat-1:crit-1-2||cat-2:crit-2-2||cat-3:crit-3-3': 223,
}
agenda_pricing.pricing_data = {'foo': 42}
agenda_pricing.save()
assert agenda_pricing.format_pricing_data() == {'foo': 42}
# wrong data
agenda_pricing.pricing_data = 'foo'
agenda_pricing.save()
assert agenda_pricing.format_pricing_data() == {'': 'foo'}
agenda_pricing.pricing_data = []
agenda_pricing.save()
assert agenda_pricing.format_pricing_data() == {}
agenda_pricing.pricing_data = ['foo']
agenda_pricing.save()
assert agenda_pricing.format_pricing_data() == {'': ['foo']}
agenda_pricing.pricing_data = {'foo': []}
agenda_pricing.save()
assert agenda_pricing.format_pricing_data() == {}
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(
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(agenda=agenda, check_status=check_status)
def test_get_booking_modifier_event_not_checked():
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
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': 'error', 'error_reason': 'event-not-checked'}
with pytest.raises(PricingEventNotCheckedError):
agenda_pricing.get_booking_modifier(agenda=agenda, check_status=check_status)
def test_get_booking_modifier_no_booking():
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
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': 'not-booked'}
assert agenda_pricing.get_booking_modifier(agenda=agenda, check_status=check_status) == {
'status': 'not-booked',
'modifier_type': 'rate',
'modifier_rate': 0,
}
# more than one booking found !
check_status = {'status': 'error', 'error_reason': 'too-many-bookings-found'}
with pytest.raises(PricingMultipleBookingError):
agenda_pricing.get_booking_modifier(agenda=agenda, check_status=check_status)
def test_get_booking_modifier_booking_cancelled():
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
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': 'cancelled'}
assert agenda_pricing.get_booking_modifier(agenda=agenda, check_status=check_status) == {
'status': 'cancelled',
'modifier_type': 'rate',
'modifier_rate': 0,
}
def test_get_booking_modifier_booking_not_checked():
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
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': 'error', 'error_reason': 'booking-not-checked'}
with pytest.raises(PricingBookingNotCheckedError):
agenda_pricing.get_booking_modifier(agenda=agenda, check_status=check_status)
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(
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': 'presence', 'check_type': 'unknown'}
with pytest.raises(PricingBookingCheckTypeError) as e:
agenda_pricing.get_booking_modifier(agenda=agenda, 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(agenda=agenda, 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(
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
check_status = {'status': 'absence', 'check_type': ''}
assert agenda_pricing.get_booking_modifier(agenda=agenda, check_status=check_status) == {
'status': 'absence',
'check_type_group': None,
'check_type': None,
'modifier_type': 'rate',
'modifier_rate': 0,
}
# 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')
check_status = {'status': 'absence', 'check_type': check_type.slug}
with pytest.raises(PricingBookingCheckTypeError) as e:
agenda_pricing.get_booking_modifier(agenda=agenda, 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(agenda=agenda, check_status=check_status)
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(agenda=agenda, check_status=check_status) == {
'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(agenda=agenda, check_status=check_status) == {
'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(agenda=agenda, check_status=check_status) == {
'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(agenda=agenda, check_status=check_status) == {
'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(agenda=agenda, check_status=check_status)
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')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
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
check_status = {'status': 'presence', 'check_type': ''}
assert agenda_pricing.get_booking_modifier(agenda=agenda, check_status=check_status) == {
'status': 'presence',
'check_type_group': None,
'check_type': None,
'modifier_type': 'rate',
'modifier_rate': 100,
}
# 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')
check_status = {'status': 'presence', 'check_type': check_type.slug}
with pytest.raises(PricingBookingCheckTypeError) as e:
agenda_pricing.get_booking_modifier(agenda=agenda, 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(agenda=agenda, check_status=check_status)
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(agenda=agenda, check_status=check_status) == {
'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(agenda=agenda, check_status=check_status) == {
'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(agenda=agenda, check_status=check_status) == {
'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(agenda=agenda, check_status=check_status) == {
'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(agenda=agenda, check_status=check_status)
assert e.value.details == {
'check_type_group': 'foo-bar',
'check_type': 'foo-reason',
'reason': 'wrong-kind',
}
def test_get_pricing_data(context):
agenda = Agenda.objects.create(label='Foo bar')
category = CriteriaCategory.objects.create(label='Foo', slug='foo')
criteria = Criteria.objects.create(label='Bar', slug='bar', condition='True', category=category)
pricing = Pricing.objects.create(
label='Foo bar',
extra_variables={
'domicile': 'commune',
'qf': '2',
},
)
pricing.criterias.add(criteria)
pricing.categories.add(category, through_defaults={'order': 1})
agenda_pricing = AgendaPricing.objects.create(
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,
},
)
agenda_pricing.agendas.add(agenda)
for subscription in [None, {'foo': 'bar'}]:
assert agenda_pricing.get_pricing_data(
request=context['request'],
pricing_date=datetime.date(year=2021, month=9, day=1),
subscription=subscription,
user_external_id='child:42',
adult_external_id='parent:35',
) == {
'pricing': 42,
'calculation_details': {
'pricing': 42,
'criterias': {'foo': 'bar'},
'context': {'domicile': 'commune', 'qf': '2'},
},
}
def test_get_pricing_data_for_event(context):
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(
label='Foo bar',
extra_variables={
'domicile': 'commune',
'qf': '2',
},
)
pricing.criterias.add(criteria)
pricing.categories.add(category, through_defaults={'order': 1})
agenda_pricing = AgendaPricing.objects.create(
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,
},
)
agenda_pricing.agendas.add(agenda)
assert agenda_pricing.get_pricing_data_for_event(
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,
'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')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
)
agenda_pricing.agendas.add(agenda)
assert agenda_pricing.aggregate_pricing_data(
pricing=42, criterias={'foo': 'bar'}, context={'domicile': 'commune', 'qf': 2}, modifier=modifier
) == {
'pricing': pricing_amount,
'calculation_details': {
'pricing': 42,
'criterias': {'foo': 'bar'},
'context': {'domicile': 'commune', 'qf': 2},
},
'booking_details': modifier,
}
def test_agenda_pricing_iter_pricing_matrix_3_categories():
category1 = CriteriaCategory.objects.create(label='Cat 1')
criteria11 = Criteria.objects.create(label='Crit 1-1', slug='crit-1-1', category=category1, order=1)
criteria12 = Criteria.objects.create(label='Crit 1-2', slug='crit-1-2', category=category1, order=2)
category2 = CriteriaCategory.objects.create(label='Cat 2')
criteria21 = Criteria.objects.create(label='Crit 2-1', slug='crit-2-1', category=category2, order=1)
criteria22 = Criteria.objects.create(label='Crit 2-2', slug='crit-2-2', category=category2, order=2)
criteria23 = Criteria.objects.create(label='Crit 2-3', slug='crit-2-3', category=category2, order=3)
category3 = CriteriaCategory.objects.create(label='Cat 3')
criteria31 = Criteria.objects.create(label='Crit 3-1', slug='crit-3-1', category=category3, order=1)
criteria33 = Criteria.objects.create(label='Crit 3-3', slug='crit-3-3', category=category3, order=3)
criteria34 = Criteria.objects.create(label='Crit 3-4', slug='crit-3-4', category=category3, order=4)
criteria32 = Criteria.objects.create(label='Crit 3-2', slug='crit-3-2', category=category3, order=2)
not_used = Criteria.objects.create(label='Not used', slug='crit-3-notused', category=category3, order=5)
category4 = CriteriaCategory.objects.create(label='Cat 4') # ignored
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
pricing.categories.add(category1, through_defaults={'order': 1})
pricing.categories.add(category2, through_defaults={'order': 2})
pricing.categories.add(category3, through_defaults={'order': 3})
pricing.categories.add(category4, through_defaults={'order': 4})
pricing.criterias.set(Criteria.objects.exclude(pk=not_used.pk))
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
)
agenda_pricing.agendas.add(agenda)
assert list(agenda_pricing.iter_pricing_matrix()) == [
PricingMatrix(
criteria=criteria11,
rows=[
PricingMatrixRow(
criteria=criteria31,
cells=[
PricingMatrixCell(criteria=criteria21, value=None),
PricingMatrixCell(criteria=criteria22, value=None),
PricingMatrixCell(criteria=criteria23, value=None),
],
),
PricingMatrixRow(
criteria=criteria32,
cells=[
PricingMatrixCell(criteria=criteria21, value=None),
PricingMatrixCell(criteria=criteria22, value=None),
PricingMatrixCell(criteria=criteria23, value=None),
],
),
PricingMatrixRow(
criteria=criteria33,
cells=[
PricingMatrixCell(criteria=criteria21, value=None),
PricingMatrixCell(criteria=criteria22, value=None),
PricingMatrixCell(criteria=criteria23, value=None),
],
),
PricingMatrixRow(
criteria=criteria34,
cells=[
PricingMatrixCell(criteria=criteria21, value=None),
PricingMatrixCell(criteria=criteria22, value=None),
PricingMatrixCell(criteria=criteria23, value=None),
],
),
],
),
PricingMatrix(
criteria=criteria12,
rows=[
PricingMatrixRow(
criteria=criteria31,
cells=[
PricingMatrixCell(criteria=criteria21, value=None),
PricingMatrixCell(criteria=criteria22, value=None),
PricingMatrixCell(criteria=criteria23, value=None),
],
),
PricingMatrixRow(
criteria=criteria32,
cells=[
PricingMatrixCell(criteria=criteria21, value=None),
PricingMatrixCell(criteria=criteria22, value=None),
PricingMatrixCell(criteria=criteria23, value=None),
],
),
PricingMatrixRow(
criteria=criteria33,
cells=[
PricingMatrixCell(criteria=criteria21, value=None),
PricingMatrixCell(criteria=criteria22, value=None),
PricingMatrixCell(criteria=criteria23, value=None),
],
),
PricingMatrixRow(
criteria=criteria34,
cells=[
PricingMatrixCell(criteria=criteria21, value=None),
PricingMatrixCell(criteria=criteria22, value=None),
PricingMatrixCell(criteria=criteria23, value=None),
],
),
],
),
]
# some data defined
agenda_pricing.pricing_data = {
'cat-1:crit-1-1': {
'cat-2:crit-2-1': {
'cat-3:crit-3-1': 111,
'cat-3:crit-3-3': 'not-a-decimal',
'cat-3:crit-3-4': 114,
},
'cat-2:crit-2-3': {
'cat-3:crit-3-2': 132,
},
},
'cat-1:crit-1-2': {
'cat-2:crit-2-2': {
'cat-3:crit-3-3': 223,
},
},
}
agenda_pricing.save()
# category ordering doesn't matter
PricingCriteriaCategory.objects.filter(pricing=pricing, category=category1).update(order=2)
PricingCriteriaCategory.objects.filter(pricing=pricing, category=category2).update(order=1)
assert list(agenda_pricing.iter_pricing_matrix()) == [
PricingMatrix(
criteria=criteria21,
rows=[
PricingMatrixRow(
criteria=criteria31,
cells=[
PricingMatrixCell(criteria=criteria11, value=111),
PricingMatrixCell(criteria=criteria12, value=None),
],
),
PricingMatrixRow(
criteria=criteria32,
cells=[
PricingMatrixCell(criteria=criteria11, value=None),
PricingMatrixCell(criteria=criteria12, value=None),
],
),
PricingMatrixRow(
criteria=criteria33,
cells=[
PricingMatrixCell(criteria=criteria11, value=None),
PricingMatrixCell(criteria=criteria12, value=None),
],
),
PricingMatrixRow(
criteria=criteria34,
cells=[
PricingMatrixCell(criteria=criteria11, value=114),
PricingMatrixCell(criteria=criteria12, value=None),
],
),
],
),
PricingMatrix(
criteria=criteria22,
rows=[
PricingMatrixRow(
criteria=criteria31,
cells=[
PricingMatrixCell(criteria=criteria11, value=None),
PricingMatrixCell(criteria=criteria12, value=None),
],
),
PricingMatrixRow(
criteria=criteria32,
cells=[
PricingMatrixCell(criteria=criteria11, value=None),
PricingMatrixCell(criteria=criteria12, value=None),
],
),
PricingMatrixRow(
criteria=criteria33,
cells=[
PricingMatrixCell(criteria=criteria11, value=None),
PricingMatrixCell(criteria=criteria12, value=223),
],
),
PricingMatrixRow(
criteria=criteria34,
cells=[
PricingMatrixCell(criteria=criteria11, value=None),
PricingMatrixCell(criteria=criteria12, value=None),
],
),
],
),
PricingMatrix(
criteria=criteria23,
rows=[
PricingMatrixRow(
criteria=criteria31,
cells=[
PricingMatrixCell(criteria=criteria11, value=None),
PricingMatrixCell(criteria=criteria12, value=None),
],
),
PricingMatrixRow(
criteria=criteria32,
cells=[
PricingMatrixCell(criteria=criteria11, value=132),
PricingMatrixCell(criteria=criteria12, value=None),
],
),
PricingMatrixRow(
criteria=criteria33,
cells=[
PricingMatrixCell(criteria=criteria11, value=None),
PricingMatrixCell(criteria=criteria12, value=None),
],
),
PricingMatrixRow(
criteria=criteria34,
cells=[
PricingMatrixCell(criteria=criteria11, value=None),
PricingMatrixCell(criteria=criteria12, value=None),
],
),
],
),
]
def test_agenda_pricing_iter_pricing_matrix_2_categories():
category2 = CriteriaCategory.objects.create(label='Cat 2')
criteria21 = Criteria.objects.create(label='Crit 2-1', slug='crit-2-1', category=category2, order=1)
criteria22 = Criteria.objects.create(label='Crit 2-2', slug='crit-2-2', category=category2, order=2)
criteria23 = Criteria.objects.create(label='Crit 2-3', slug='crit-2-3', category=category2, order=3)
category3 = CriteriaCategory.objects.create(label='Cat 3')
criteria31 = Criteria.objects.create(label='Crit 3-1', slug='crit-3-1', category=category3, order=1)
criteria33 = Criteria.objects.create(label='Crit 3-3', slug='crit-3-3', category=category3, order=3)
criteria34 = Criteria.objects.create(label='Crit 3-4', slug='crit-3-4', category=category3, order=4)
criteria32 = Criteria.objects.create(label='Crit 3-2', slug='crit-3-2', category=category3, order=2)
not_used = Criteria.objects.create(label='Not used', slug='crit-3-notused', category=category3, order=5)
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
pricing.categories.add(category2, through_defaults={'order': 2})
pricing.categories.add(category3, through_defaults={'order': 3})
pricing.criterias.set(Criteria.objects.exclude(pk=not_used.pk))
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
)
agenda_pricing.agendas.add(agenda)
assert list(agenda_pricing.iter_pricing_matrix()) == [
PricingMatrix(
criteria=None,
rows=[
PricingMatrixRow(
criteria=criteria31,
cells=[
PricingMatrixCell(criteria=criteria21, value=None),
PricingMatrixCell(criteria=criteria22, value=None),
PricingMatrixCell(criteria=criteria23, value=None),
],
),
PricingMatrixRow(
criteria=criteria32,
cells=[
PricingMatrixCell(criteria=criteria21, value=None),
PricingMatrixCell(criteria=criteria22, value=None),
PricingMatrixCell(criteria=criteria23, value=None),
],
),
PricingMatrixRow(
criteria=criteria33,
cells=[
PricingMatrixCell(criteria=criteria21, value=None),
PricingMatrixCell(criteria=criteria22, value=None),
PricingMatrixCell(criteria=criteria23, value=None),
],
),
PricingMatrixRow(
criteria=criteria34,
cells=[
PricingMatrixCell(criteria=criteria21, value=None),
PricingMatrixCell(criteria=criteria22, value=None),
PricingMatrixCell(criteria=criteria23, value=None),
],
),
],
),
]
# some data defined
agenda_pricing.pricing_data = {
'cat-2:crit-2-1': {
'cat-3:crit-3-1': 11,
'cat-3:crit-3-3': 'not-a-decimal',
'cat-3:crit-3-4': 14,
},
'cat-2:crit-2-3': {
'cat-3:crit-3-2': 32,
},
}
agenda_pricing.save()
assert list(agenda_pricing.iter_pricing_matrix()) == [
PricingMatrix(
criteria=None,
rows=[
PricingMatrixRow(
criteria=criteria31,
cells=[
PricingMatrixCell(criteria=criteria21, value=11),
PricingMatrixCell(criteria=criteria22, value=None),
PricingMatrixCell(criteria=criteria23, value=None),
],
),
PricingMatrixRow(
criteria=criteria32,
cells=[
PricingMatrixCell(criteria=criteria21, value=None),
PricingMatrixCell(criteria=criteria22, value=None),
PricingMatrixCell(criteria=criteria23, value=32),
],
),
PricingMatrixRow(
criteria=criteria33,
cells=[
PricingMatrixCell(criteria=criteria21, value=None),
PricingMatrixCell(criteria=criteria22, value=None),
PricingMatrixCell(criteria=criteria23, value=None),
],
),
PricingMatrixRow(
criteria=criteria34,
cells=[
PricingMatrixCell(criteria=criteria21, value=14),
PricingMatrixCell(criteria=criteria22, value=None),
PricingMatrixCell(criteria=criteria23, value=None),
],
),
],
),
]
def test_agenda_pricing_iter_pricing_matrix_1_category():
category3 = CriteriaCategory.objects.create(label='Cat 3')
criteria31 = Criteria.objects.create(label='Crit 3-1', slug='crit-3-1', category=category3, order=1)
criteria33 = Criteria.objects.create(label='Crit 3-3', slug='crit-3-3', category=category3, order=3)
criteria34 = Criteria.objects.create(label='Crit 3-4', slug='crit-3-4', category=category3, order=4)
criteria32 = Criteria.objects.create(label='Crit 3-2', slug='crit-3-2', category=category3, order=2)
not_used = Criteria.objects.create(label='Not used', slug='crit-3-notused', category=category3, order=5)
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
pricing.categories.add(category3, through_defaults={'order': 3})
pricing.criterias.set(Criteria.objects.exclude(pk=not_used.pk))
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
)
agenda_pricing.agendas.add(agenda)
assert list(agenda_pricing.iter_pricing_matrix()) == [
PricingMatrix(
criteria=None,
rows=[
PricingMatrixRow(
criteria=criteria31,
cells=[
PricingMatrixCell(criteria=None, value=None),
],
),
PricingMatrixRow(
criteria=criteria32,
cells=[
PricingMatrixCell(criteria=None, value=None),
],
),
PricingMatrixRow(
criteria=criteria33,
cells=[
PricingMatrixCell(criteria=None, value=None),
],
),
PricingMatrixRow(
criteria=criteria34,
cells=[
PricingMatrixCell(criteria=None, value=None),
],
),
],
),
]
# some data defined
agenda_pricing.pricing_data = {
'cat-3:crit-3-1': 1,
'cat-3:crit-3-3': 'not-a-decimal',
'cat-3:crit-3-4': 4,
}
agenda_pricing.save()
assert list(agenda_pricing.iter_pricing_matrix()) == [
PricingMatrix(
criteria=None,
rows=[
PricingMatrixRow(
criteria=criteria31,
cells=[
PricingMatrixCell(criteria=None, value=1),
],
),
PricingMatrixRow(
criteria=criteria32,
cells=[
PricingMatrixCell(criteria=None, value=None),
],
),
PricingMatrixRow(
criteria=criteria33,
cells=[
PricingMatrixCell(criteria=None, value=None),
],
),
PricingMatrixRow(
criteria=criteria34,
cells=[
PricingMatrixCell(criteria=None, value=4),
],
),
],
),
]
def test_agenda_pricing_iter_pricing_matrix_empty():
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
date_start=datetime.date(year=2021, month=9, day=1),
date_end=datetime.date(year=2021, month=10, day=1),
)
agenda_pricing.agendas.add(agenda)
assert list(agenda_pricing.iter_pricing_matrix()) == []