api: endpoint to get pricing data for flat fee schedule mode (#67675)

This commit is contained in:
Lauréline Guérin 2022-07-29 18:18:05 +02:00
parent f0503f9190
commit 2cae1d52c5
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
2 changed files with 673 additions and 47 deletions

View File

@ -36,19 +36,29 @@ class CommaSeparatedStringField(serializers.ListField):
class PricingComputeSerializer(serializers.Serializer):
slots = CommaSeparatedStringField(
required=True, child=serializers.CharField(max_length=160, allow_blank=False)
required=False, child=serializers.CharField(max_length=160, allow_blank=False)
)
agenda = serializers.SlugField(required=False, allow_blank=False, max_length=160)
agenda_pricing = serializers.SlugField(required=False, allow_blank=False, max_length=160)
start_date = serializers.DateTimeField(required=False, input_formats=['iso-8601', '%Y-%m-%d'])
user_external_id = serializers.CharField(required=True, max_length=250)
adult_external_id = serializers.CharField(required=True, max_length=250)
agenda_slugs = []
agendas = {}
serialized_events = {}
event_subscriptions = {}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._agenda_slugs = []
self._agendas = {}
self._serialized_events = {}
self._event_subscriptions = {}
self._agenda = None
self._agenda_subscription = None
self._agenda_pricing = None
self._billing_date = None
def validate_slots(self, value):
self.agendas = {a.slug: a for a in Agenda.objects.all()}
allowed_agenda_slugs = self.agendas.keys()
self._agendas = {a.slug: a for a in Agenda.objects.all()}
allowed_agenda_slugs = self._agendas.keys()
agenda_slugs = set()
for slot in value:
try:
@ -64,7 +74,7 @@ class PricingComputeSerializer(serializers.Serializer):
if extra_agendas:
extra_agendas = ', '.join(sorted(extra_agendas))
raise ValidationError(_('Unknown agendas: %s') % extra_agendas)
self.agenda_slugs = sorted(agenda_slugs)
self._agenda_slugs = sorted(agenda_slugs)
try:
serialized_events = get_events(value)
@ -73,61 +83,168 @@ class PricingComputeSerializer(serializers.Serializer):
else:
for serialized_event in serialized_events:
event_slug = '%s@%s' % (serialized_event['agenda'], serialized_event['slug'])
self.serialized_events[event_slug] = serialized_event
self._serialized_events[event_slug] = serialized_event
return value
def get_subscriptions(self, user_external_id):
def _validate_agenda(self, value, start_date):
try:
self._agenda = Agenda.objects.get(slug=value)
try:
self._agenda_pricing = AgendaPricing.get_agenda_pricing(
agenda=self._agenda,
start_date=start_date.date(),
flat_fee_schedule=True,
)
if not self._agenda_pricing.subscription_required:
self._agenda_pricing = None
except AgendaPricingNotFound:
self._agenda_pricing = None
except Agenda.DoesNotExist:
raise ValidationError({'agenda': _('Unknown agenda: %s') % value})
return self._agenda
def _validate_agenda_pricing(self, value, start_date):
try:
self._agenda_pricing = AgendaPricing.objects.get(
slug=value,
flat_fee_schedule=True,
subscription_required=False,
date_start__lte=start_date.date(),
date_end__gt=start_date.date(),
)
except AgendaPricing.DoesNotExist:
raise ValidationError({'agenda_pricing': _('Unknown pricing: %s') % value})
return self._agenda_pricing
def validate(self, attrs):
super().validate(attrs)
if 'slots' not in attrs and 'agenda' not in attrs and 'agenda_pricing' not in attrs:
raise ValidationError(_('Either "slots", "agenda" or "agenda_pricing" parameter is required.'))
if 'agenda' in attrs:
# flat_fee_schedule mode + subscription_required True
if 'start_date' not in attrs:
raise ValidationError(
{'start_date': _('This field is required when using "agenda" parameter.')}
)
self._validate_agenda(attrs['agenda'], attrs['start_date'])
if 'agenda_pricing' in attrs:
# flat_fee_schedule mode + subscription_required False
if 'start_date' not in attrs:
raise ValidationError(
{'start_date': _('This field is required when using "agenda_pricing" parameter.')}
)
self._validate_agenda_pricing(attrs['agenda_pricing'], attrs['start_date'])
if attrs.get('start_date'):
# flat_fee_schedule mode: get billing_date from start_date param
self.get_billing_date(attrs['start_date'])
if attrs.get('user_external_id') and not attrs.get('agenda_pricing'):
# don't check subscriptions if agenda_pricing in params (== subscription_required is False)
self.get_subscriptions(attrs['user_external_id'], attrs.get('start_date'))
return attrs
def get_billing_date(self, start_date):
if self._agenda_pricing:
self._billing_date = (
self._agenda_pricing.billingdates.filter(date_start__lte=start_date)
.order_by('date_start')
.last()
)
if not self._billing_date:
self._billing_date = self._agenda_pricing.billingdates.order_by('date_start').first()
def get_subscriptions(self, user_external_id, start_date):
if self._serialized_events:
# event mode
self.get_subscriptions_for_events(user_external_id)
elif self._agenda and self._agenda_pricing:
# flat_fee_schedule mode
self.get_subscriptions_for_agenda(user_external_id, start_date)
def _get_subscription(self, subscriptions, start_date, end_date):
# get subscription matching start_date & end_date
for subscription in subscriptions:
sub_start_date = datetime.date.fromisoformat(subscription['date_start'])
sub_end_date = datetime.date.fromisoformat(subscription['date_end'])
if sub_start_date >= end_date:
continue
if sub_end_date <= start_date:
continue
return subscription
def get_subscriptions_for_events(self, user_external_id):
agenda_subscriptions = {}
for agenda_slug in self.agenda_slugs:
# get subscription list for each agenda
for agenda_slug in self._agenda_slugs:
try:
agenda_subscriptions[agenda_slug] = get_subscriptions(agenda_slug, user_external_id)
except ChronoError as e:
raise ValidationError({'user_external_id': e})
self.event_subscriptions = {}
for event_slug, serialized_event in self.serialized_events.items():
# for each event, get a matching subscription
for event_slug, serialized_event in self._serialized_events.items():
start_date = datetime.datetime.fromisoformat(serialized_event['start_datetime']).date()
end_date = start_date + datetime.timedelta(days=1)
agenda_slug = serialized_event['agenda']
event_subscription = None
for subscription in agenda_subscriptions[agenda_slug]:
sub_start_date = datetime.date.fromisoformat(subscription['date_start'])
sub_end_date = datetime.date.fromisoformat(subscription['date_end'])
if sub_start_date >= end_date:
continue
if sub_end_date <= start_date:
continue
event_subscription = subscription
break
event_subscription = self._get_subscription(
agenda_subscriptions[agenda_slug], start_date, end_date
)
if event_subscription is None:
raise ValidationError(
{'user_external_id': _('No subscription found for event %s') % event_slug}
)
self.event_subscriptions[event_slug] = event_subscription
self._event_subscriptions[event_slug] = event_subscription
def validate(self, attrs):
super().validate(attrs)
if attrs.get('user_external_id') and self.serialized_events:
self.get_subscriptions(attrs['user_external_id'])
return attrs
def get_subscriptions_for_agenda(self, user_external_id, start_date):
# get subscription list for this agenda
try:
subscriptions = get_subscriptions(self._agenda.slug, user_external_id)
except ChronoError as e:
raise ValidationError({'user_external_id': e})
# get correct period, from billing_date or agenda_pricing dates
if not self._agenda_pricing.billingdates.exists():
start_date = self._agenda_pricing.date_start
end_date = self._agenda_pricing.date_end
else:
start_date = self._billing_date.date_start
next_billing_date = self._agenda_pricing.billingdates.filter(date_start__gt=start_date).first()
end_date = next_billing_date.date_start if next_billing_date else self._agenda_pricing.date_end
# get a matching subscriptions
self._agenda_subscription = self._get_subscription(subscriptions, start_date, end_date)
if not self._agenda_subscription:
raise ValidationError(
{'user_external_id': _('No subscription found for agenda %s') % self._agenda.slug}
)
def compute(self, request):
if not self.serialized_events or not self.event_subscriptions:
return
try:
if not self.validated_data.get('slots'):
return self.compute_for_flat_fee_schedule(request)
return self.compute_for_event(request)
except PricingError as e:
return {
'error': type(e),
'error_details': e.details,
}
def compute_for_event(self, request):
result = []
event_slugs = sorted(self.serialized_events.keys())
event_slugs = sorted(self._serialized_events.keys())
for event_slug in event_slugs:
serialized_event = self.serialized_events[event_slug]
serialized_event = self._serialized_events[event_slug]
start_date = datetime.datetime.fromisoformat(serialized_event['start_datetime']).date()
agenda = self.agendas[serialized_event['agenda']]
agenda = self._agendas[serialized_event['agenda']]
try:
agenda_pricing = AgendaPricing.get_agenda_pricing(agenda=agenda, start_date=start_date)
agenda_pricing = AgendaPricing.get_agenda_pricing(
agenda=agenda, start_date=start_date, flat_fee_schedule=False
)
pricing_data = agenda_pricing.get_pricing_data_for_event(
request=request,
agenda=agenda,
event=serialized_event,
subscription=self.event_subscriptions[event_slug],
subscription=self._event_subscriptions[event_slug],
check_status={
'status': 'presence',
'check_type': None,
@ -151,3 +268,30 @@ class PricingComputeSerializer(serializers.Serializer):
result = sorted(result, key=lambda d: d['event'])
return result
def compute_for_flat_fee_schedule(self, request):
result = {}
if self._agenda:
result['agenda'] = self._agenda.slug
if not self._agenda_pricing:
result['error'] = _('No agenda pricing found for agenda %s') % self._agenda.slug
return result
else:
result['agenda_pricing'] = self._agenda_pricing.slug
try:
pricing_data = self._agenda_pricing.get_pricing_data(
request=request,
pricing_date=(
self._billing_date.date_start if self._billing_date else self._agenda_pricing.date_start
),
subscription=self._agenda_subscription,
user_external_id=self.validated_data['user_external_id'],
adult_external_id=self.validated_data['adult_external_id'],
)
result['pricing_data'] = pricing_data
return result
except PricingError as e:
result['error'] = type(e).__name__
result['error_details'] = e.details
return result

View File

@ -13,7 +13,17 @@ pytestmark = pytest.mark.django_db
def test_pricing_compute_params(app, user):
app.authorization = ('Basic', ('john.doe', 'password'))
# missing slots
Agenda.objects.create(label='Foo')
pricing = Pricing.objects.create(label='Foo bar')
AgendaPricing.objects.create(
label='Foo',
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,
)
# missing slots, agenda, agenda_pricing
resp = app.get(
'/api/pricing/compute/',
params={'user_external_id': 'user:1', 'adult_external_id': 'adult:1'},
@ -21,27 +31,59 @@ def test_pricing_compute_params(app, user):
)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'invalid payload'
assert resp.json['errors']['slots'] == ['This field is required.']
assert resp.json['errors'] == {
'non_field_errors': ['Either "slots", "agenda" or "agenda_pricing" parameter is required.']
}
# missing user_external_id
# missing start_date
resp = app.get(
'/api/pricing/compute/',
params={'slots': 'foo@foo', 'adult_external_id': 'adult:1'},
params={'agenda': 'foo', 'user_external_id': 'user:1', 'adult_external_id': 'adult:1'},
status=400,
)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'invalid payload'
assert resp.json['errors']['user_external_id'] == ['This field is required.']
# missing adult_external_id
assert resp.json['errors']['start_date'] == ['This field is required when using "agenda" parameter.']
resp = app.get(
'/api/pricing/compute/',
params={'slots': 'foo@foo', 'user_external_id': 'user:1'},
params={'agenda_pricing': 'foo', 'user_external_id': 'user:1', 'adult_external_id': 'adult:1'},
status=400,
)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'invalid payload'
assert resp.json['errors']['adult_external_id'] == ['This field is required.']
assert resp.json['errors']['start_date'] == [
'This field is required when using "agenda_pricing" parameter.'
]
params = [
{'slots': 'foo@foo'},
{'agenda': 'foo', 'start_date': '2021-09-01'},
{'agenda_pricing': 'foo', 'start_date': '2021-09-01'},
]
for param in params:
# missing user_external_id
_param = param.copy()
_param.update({'adult_external_id': 'adult:1'})
resp = app.get(
'/api/pricing/compute/',
params=_param,
status=400,
)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'invalid payload'
assert resp.json['errors']['user_external_id'] == ['This field is required.']
# missing adult_external_id
_param = param.copy()
_param.update({'user_external_id': 'user:1'})
resp = app.get(
'/api/pricing/compute/',
params=_param,
status=400,
)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'invalid payload'
assert resp.json['errors']['adult_external_id'] == ['This field is required.']
def test_pricing_compute_slots(app, user):
@ -100,6 +142,74 @@ def test_pricing_compute_slots(app, user):
assert resp.json['errors']['slots'] == ['Unknown agendas: agenda, agenda2']
def test_pricing_compute_agenda(app, user):
app.authorization = ('Basic', ('john.doe', 'password'))
# unknown agenda
resp = app.get(
'/api/pricing/compute/',
params={
'agenda': 'agenda',
'start_date': '2021-09-01',
'user_external_id': 'user:1',
'adult_external_id': 'adult:1',
},
status=400,
)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'invalid payload'
assert resp.json['errors']['agenda'] == ['Unknown agenda: agenda']
def test_pricing_compute_agenda_pricing(app, user):
app.authorization = ('Basic', ('john.doe', 'password'))
def test():
resp = app.get(
'/api/pricing/compute/',
params={
'agenda_pricing': 'baz',
'start_date': '2021-09-01',
'user_external_id': 'user:1',
'adult_external_id': 'adult:1',
},
status=400,
)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'invalid payload'
assert resp.json['errors']['agenda_pricing'] == ['Unknown pricing: baz']
# unknown agenda_pricing
test()
# bad dates
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
label='Baz',
pricing=pricing,
date_start=datetime.date(year=2021, month=8, day=1),
date_end=datetime.date(year=2021, month=9, day=1),
flat_fee_schedule=True,
subscription_required=False,
)
test()
agenda_pricing.date_start = datetime.date(year=2021, month=9, day=3)
agenda_pricing.date_end = datetime.date(year=2021, month=10, day=1)
agenda_pricing.save()
test()
# wrong flat_fee_schedule value
agenda_pricing.flat_fee_schedule = False
agenda_pricing.save()
test()
# wrong subscription_required value
agenda_pricing.flat_fee_schedule = True
agenda_pricing.subscription_required = True
agenda_pricing.save()
test()
@mock.patch('lingo.api.serializers.get_events')
def test_pricing_compute_events_error(mock_events, app, user):
Agenda.objects.create(label='Agenda')
@ -147,7 +257,7 @@ def test_pricing_compute_subscriptions_error(mock_subscriptions, mock_events, ap
@mock.patch('lingo.api.serializers.get_events')
@mock.patch('lingo.api.serializers.get_subscriptions')
@mock.patch('lingo.pricing.models.AgendaPricing.get_pricing_data_for_event')
def test_pricing_compute(mock_pricing_data_event, mock_subscriptions, mock_events, app, user):
def test_pricing_compute_for_event(mock_pricing_data_event, mock_subscriptions, mock_events, app, user):
agenda = Agenda.objects.create(label='Agenda')
agenda2 = Agenda.objects.create(label='Agenda2')
app.authorization = ('Basic', ('john.doe', 'password'))
@ -277,12 +387,12 @@ def test_pricing_compute(mock_pricing_data_event, mock_subscriptions, mock_event
},
]
# ok
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=True, # wrong config
)
agenda_pricing.agendas.add(agenda, agenda2)
resp = app.get(
@ -293,6 +403,28 @@ def test_pricing_compute(mock_pricing_data_event, mock_subscriptions, mock_event
'adult_external_id': 'adult:1',
},
)
assert resp.json['data'] == [
{
'event': 'agenda2@event-baz-slug',
'error': 'No agenda pricing found for event agenda2@event-baz-slug',
},
{
'event': 'agenda@event-bar-slug',
'error': 'No agenda pricing found for event agenda@event-bar-slug',
},
]
# ok
agenda_pricing.flat_fee_schedule = False
agenda_pricing.save()
resp = app.get(
'/api/pricing/compute/',
params={
'slots': 'agenda@event-bar-slug, agenda2@event-baz-slug',
'user_external_id': 'user:1',
'adult_external_id': 'adult:1',
},
)
assert resp.json['data'] == [
{'event': 'agenda2@event-baz-slug', 'pricing_data': {'foo': 'baz'}},
{'event': 'agenda@event-bar-slug', 'pricing_data': {'foo': 'bar'}},
@ -345,3 +477,353 @@ def test_pricing_compute(mock_pricing_data_event, mock_subscriptions, mock_event
{'event': 'agenda2@event-baz-slug', 'error': {'foo': 'error'}},
{'event': 'agenda@event-bar-slug', 'pricing_data': {'foo': 'bar'}},
]
@mock.patch('lingo.api.serializers.get_subscriptions')
@mock.patch('lingo.pricing.models.AgendaPricing.get_pricing_data')
def test_pricing_compute_for_flat_fee_schedule_with_subscription(
mock_pricing_data, mock_subscriptions, app, user
):
agenda = Agenda.objects.create(label='Foo bar')
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
label='Foo bar pricing',
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,
subscription_required=True,
)
agenda_pricing.agendas.add(agenda)
app.authorization = ('Basic', ('john.doe', 'password'))
# no subscription
mock_subscriptions.return_value = []
resp = app.get(
'/api/pricing/compute/',
params={
'agenda': 'foo-bar',
'start_date': '2021-09-01',
'user_external_id': 'user:1',
'adult_external_id': 'adult:1',
},
status=400,
)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'invalid payload'
assert resp.json['errors']['user_external_id'] == ['No subscription found for agenda foo-bar']
assert mock_subscriptions.call_args_list == [mock.call('foo-bar', 'user:1')]
# no matching subscription
mock_subscriptions.reset_mock()
mock_subscriptions.return_value = [
{
'date_start': '2021-08-01',
'date_end': '2021-09-01',
},
{
'date_start': '2021-10-01',
'date_end': '2021-11-01',
},
]
resp = app.get(
'/api/pricing/compute/',
params={
'agenda': 'foo-bar',
'start_date': '2021-09-02',
'user_external_id': 'user:1',
'adult_external_id': 'adult:1',
},
status=400,
)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'invalid payload'
assert resp.json['errors']['user_external_id'] == ['No subscription found for agenda foo-bar']
assert mock_subscriptions.call_args_list == [mock.call('foo-bar', 'user:1')]
# no agenda_pricing found
agenda_pricing.delete()
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
# bad dates
date_start=datetime.date(year=2021, month=8, day=1),
date_end=datetime.date(year=2021, month=9, day=1),
)
agenda_pricing.agendas.add(agenda)
agenda_pricing = AgendaPricing.objects.create(
pricing=pricing,
# bad dates
date_start=datetime.date(year=2021, month=9, day=3),
date_end=datetime.date(year=2021, month=10, day=1),
)
agenda_pricing.agendas.add(agenda)
mock_subscriptions.return_value = [
{
'date_start': '2021-08-01',
'date_end': '2021-09-01',
},
{
'date_start': '2021-09-02',
'date_end': '2021-09-03',
},
{
'date_start': '2021-10-01',
'date_end': '2021-11-01',
},
]
mock_pricing_data.return_value = {'foo': 'bar'}
resp = app.get(
'/api/pricing/compute/',
params={
'agenda': 'foo-bar',
'start_date': '2021-09-02',
'user_external_id': 'user:1',
'adult_external_id': 'adult:1',
},
)
assert resp.json['data'] == {
'agenda': 'foo-bar',
'error': 'No agenda pricing found for agenda foo-bar',
}
agenda_pricing.delete()
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, # wrong config
subscription_required=True,
)
agenda_pricing.agendas.add(agenda)
resp = app.get(
'/api/pricing/compute/',
params={
'agenda': 'foo-bar',
'start_date': '2021-09-02',
'user_external_id': 'user:1',
'adult_external_id': 'adult:1',
},
)
assert resp.json['data'] == {
'agenda': 'foo-bar',
'error': 'No agenda pricing found for agenda foo-bar',
}
agenda_pricing.flat_fee_schedule = True
agenda_pricing.subscription_required = False # wrong config
agenda_pricing.save()
resp = app.get(
'/api/pricing/compute/',
params={
'agenda': 'foo-bar',
'start_date': '2021-09-02',
'user_external_id': 'user:1',
'adult_external_id': 'adult:1',
},
)
assert resp.json['data'] == {
'agenda': 'foo-bar',
'error': 'No agenda pricing found for agenda foo-bar',
}
# ok
agenda_pricing.subscription_required = True
agenda_pricing.save()
resp = app.get(
'/api/pricing/compute/',
params={
'agenda': 'foo-bar',
'start_date': '2021-09-02',
'user_external_id': 'user:1',
'adult_external_id': 'adult:1',
},
)
assert resp.json['data'] == {'agenda': 'foo-bar', 'pricing_data': {'foo': 'bar'}}
assert mock_pricing_data.call_args_list == [
mock.call(
request=mock.ANY,
pricing_date=datetime.date(2021, 9, 1),
subscription={'date_start': '2021-09-02', 'date_end': '2021-09-03'},
user_external_id='user:1',
adult_external_id='adult:1',
),
]
# get_pricing_data with error
mock_pricing_data.side_effect = PricingError(details={'foo': 'error'})
resp = app.get(
'/api/pricing/compute/',
params={
'agenda': 'foo-bar',
'start_date': '2021-09-02',
'user_external_id': 'user:1',
'adult_external_id': 'adult:1',
},
)
assert resp.json['data'] == {
'agenda': 'foo-bar',
'error': 'PricingError',
'error_details': {'foo': 'error'},
}
# check with billing dates
mock_pricing_data.return_value = {'foo': 'bar'}
agenda_pricing.billingdates.create(
date_start=datetime.date(2021, 9, 1),
label='Foo 1',
)
agenda_pricing.billingdates.create(
date_start=datetime.date(2021, 9, 15),
label='Foo 2',
)
mock_subscriptions.return_value = [
{
'date_start': '2021-09-01',
'date_end': '2021-09-15',
},
]
resp = app.get(
'/api/pricing/compute/',
params={
'agenda': 'foo-bar',
'start_date': '2021-09-16',
'user_external_id': 'user:1',
'adult_external_id': 'adult:1',
},
status=400,
)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'invalid payload'
assert resp.json['errors']['user_external_id'] == ['No subscription found for agenda foo-bar']
mock_subscriptions.return_value = [
{
'date_start': '2021-09-15',
'date_end': '2021-09-16',
},
]
mock_pricing_data.reset_mock()
resp = app.get(
'/api/pricing/compute/',
params={
'agenda': 'foo-bar',
'start_date': '2021-09-16',
'user_external_id': 'user:1',
'adult_external_id': 'adult:1',
},
)
assert mock_pricing_data.call_args_list == [
mock.call(
request=mock.ANY,
pricing_date=datetime.date(2021, 9, 15),
subscription={'date_start': '2021-09-15', 'date_end': '2021-09-16'},
user_external_id='user:1',
adult_external_id='adult:1',
),
]
mock_subscriptions.return_value = [
{
'date_start': '2021-09-30',
'date_end': '2021-10-01',
},
]
mock_pricing_data.reset_mock()
resp = app.get(
'/api/pricing/compute/',
params={
'agenda': 'foo-bar',
'start_date': '2021-09-16',
'user_external_id': 'user:1',
'adult_external_id': 'adult:1',
},
)
assert mock_pricing_data.call_args_list == [
mock.call(
request=mock.ANY,
pricing_date=datetime.date(2021, 9, 15),
subscription={'date_start': '2021-09-30', 'date_end': '2021-10-01'},
user_external_id='user:1',
adult_external_id='adult:1',
),
]
@mock.patch('lingo.pricing.models.AgendaPricing.get_pricing_data')
def test_pricing_compute_for_flat_fee_schedule_without_subscription(mock_pricing_data, app, user):
pricing = Pricing.objects.create(label='Foo bar')
agenda_pricing = AgendaPricing.objects.create(
label='Foo bar pricing',
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,
subscription_required=False,
)
app.authorization = ('Basic', ('john.doe', 'password'))
mock_pricing_data.return_value = {'foo': 'bar'}
resp = app.get(
'/api/pricing/compute/',
params={
'agenda_pricing': 'foo-bar-pricing',
'start_date': '2021-09-02',
'user_external_id': 'user:1',
'adult_external_id': 'adult:1',
},
)
assert resp.json['data'] == {'agenda_pricing': 'foo-bar-pricing', 'pricing_data': {'foo': 'bar'}}
assert mock_pricing_data.call_args_list == [
mock.call(
request=mock.ANY,
pricing_date=datetime.date(2021, 9, 1),
subscription=None,
user_external_id='user:1',
adult_external_id='adult:1',
),
]
# get_pricing_data with error
mock_pricing_data.side_effect = PricingError(details={'foo': 'error'})
resp = app.get(
'/api/pricing/compute/',
params={
'agenda_pricing': 'foo-bar-pricing',
'start_date': '2021-09-02',
'user_external_id': 'user:1',
'adult_external_id': 'adult:1',
},
)
assert resp.json['data'] == {
'agenda_pricing': 'foo-bar-pricing',
'error': 'PricingError',
'error_details': {'foo': 'error'},
}
# check with billing dates
mock_pricing_data.return_value = {'foo': 'bar'}
agenda_pricing.billingdates.create(
date_start=datetime.date(2021, 9, 1),
label='Foo 1',
)
agenda_pricing.billingdates.create(
date_start=datetime.date(2021, 9, 15),
label='Foo 2',
)
mock_pricing_data.reset_mock()
resp = app.get(
'/api/pricing/compute/',
params={
'agenda_pricing': 'foo-bar-pricing',
'start_date': '2021-09-16',
'user_external_id': 'user:1',
'adult_external_id': 'adult:1',
},
)
assert mock_pricing_data.call_args_list == [
mock.call(
request=mock.ANY,
pricing_date=datetime.date(2021, 9, 15),
subscription=None,
user_external_id='user:1',
adult_external_id='adult:1',
),
]