api: endpoint to get pricing data for flat fee schedule mode (#67675)
This commit is contained in:
parent
f0503f9190
commit
2cae1d52c5
|
@ -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
|
||||
|
|
|
@ -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',
|
||||
),
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue