pricing: adapt test tool for flat fee schedule mode (#67675)
This commit is contained in:
parent
9531507e12
commit
bbe4dce2cf
|
@ -292,6 +292,9 @@ class PricingMatrixForm(forms.Form):
|
|||
class PricingTestToolForm(forms.Form):
|
||||
agenda = forms.ModelChoiceField(label=_('Agenda'), empty_label=None, queryset=Agenda.objects.none())
|
||||
event_slug = forms.CharField(label=_('Event identifier'))
|
||||
billing_date = forms.ModelChoiceField(
|
||||
label=_('Billing date'), empty_label=None, queryset=BillingDate.objects.none()
|
||||
)
|
||||
user_external_id = forms.CharField(label=_('User external identifier'))
|
||||
adult_external_id = forms.CharField(label=_('Adult external identifier'))
|
||||
booking_status = forms.ChoiceField(label=_('Booking status'), choices=[])
|
||||
|
@ -307,7 +310,25 @@ class PricingTestToolForm(forms.Form):
|
|||
self.check_type_slug = None
|
||||
self.booking_status = None
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['agenda'].queryset = self.agenda_pricing.agendas.all()
|
||||
if self.agenda_pricing.subscription_required:
|
||||
self.fields['agenda'].queryset = self.agenda_pricing.agendas.all()
|
||||
else:
|
||||
del self.fields['agenda']
|
||||
if self.agenda_pricing.flat_fee_schedule:
|
||||
del self.fields['event_slug']
|
||||
del self.fields['booking_status']
|
||||
self.init_billing_date()
|
||||
else:
|
||||
del self.fields['billing_date']
|
||||
self.init_booking_status()
|
||||
|
||||
def init_agenda(self, agenda_id):
|
||||
try:
|
||||
self.agenda = self.agenda_pricing.agendas.get(pk=agenda_id)
|
||||
except Agenda.DoesNotExist:
|
||||
pass
|
||||
|
||||
def init_booking_status(self):
|
||||
presence_check_types = (
|
||||
self.agenda.check_type_group.check_types.presences()
|
||||
if self.agenda and self.agenda.check_type_group
|
||||
|
@ -330,11 +351,12 @@ class PricingTestToolForm(forms.Form):
|
|||
]
|
||||
self.fields['booking_status'].choices = status_choices
|
||||
|
||||
def init_agenda(self, agenda_id):
|
||||
try:
|
||||
self.agenda = self.agenda_pricing.agendas.get(pk=agenda_id)
|
||||
except Agenda.DoesNotExist:
|
||||
pass
|
||||
def init_billing_date(self):
|
||||
billing_dates = self.agenda_pricing.billingdates.order_by('date_start')
|
||||
if not billing_dates:
|
||||
del self.fields['billing_date']
|
||||
return
|
||||
self.fields['billing_date'].queryset = billing_dates
|
||||
|
||||
def clean_event_slug(self):
|
||||
event_slug = self.cleaned_data['event_slug']
|
||||
|
@ -359,9 +381,7 @@ class PricingTestToolForm(forms.Form):
|
|||
self.booking_status, self.check_type_slug = original_booking_status.split('::')
|
||||
return original_booking_status
|
||||
|
||||
def get_subscription(self, user_external_id):
|
||||
start_date = datetime.datetime.fromisoformat(self.serialized_event['start_datetime']).date()
|
||||
end_date = start_date + datetime.timedelta(days=1)
|
||||
def get_subscription(self, user_external_id, start_date, end_date):
|
||||
try:
|
||||
subscriptions = get_subscriptions(self.agenda.slug, user_external_id)
|
||||
except ChronoError as e:
|
||||
|
@ -375,33 +395,70 @@ class PricingTestToolForm(forms.Form):
|
|||
if sub_end_date <= start_date:
|
||||
continue
|
||||
return subscription
|
||||
self.add_error('user_external_id', _('No subscription found for this event'))
|
||||
error_message = _('No subscription found for this event')
|
||||
if self.agenda_pricing.flat_fee_schedule:
|
||||
error_message = _('No subscription found for this period')
|
||||
self.add_error('user_external_id', error_message)
|
||||
|
||||
def clean(self):
|
||||
super().clean()
|
||||
if self.cleaned_data.get('user_external_id') and self.serialized_event:
|
||||
user_external_id = self.cleaned_data['user_external_id']
|
||||
self.serialized_subscription = self.get_subscription(user_external_id)
|
||||
|
||||
user_external_id = self.cleaned_data.get('user_external_id')
|
||||
start_date = None
|
||||
end_date = None
|
||||
if self.agenda_pricing.flat_fee_schedule and self.agenda_pricing.subscription_required:
|
||||
if self.cleaned_data.get('billing_date'):
|
||||
start_date = self.cleaned_data['billing_date'].date_start
|
||||
next_billing_date = (
|
||||
self.fields['billing_date'].queryset.filter(date_start__gt=start_date).first()
|
||||
)
|
||||
end_date = next_billing_date.date_start if next_billing_date else self.agenda_pricing.date_end
|
||||
else:
|
||||
start_date = self.agenda_pricing.date_start
|
||||
end_date = self.agenda_pricing.date_end
|
||||
elif self.serialized_event:
|
||||
start_date = datetime.datetime.fromisoformat(self.serialized_event['start_datetime']).date()
|
||||
end_date = start_date + datetime.timedelta(days=1)
|
||||
if user_external_id and start_date and end_date:
|
||||
self.serialized_subscription = self.get_subscription(user_external_id, start_date, end_date)
|
||||
|
||||
def compute(self):
|
||||
try:
|
||||
if self.agenda_pricing.flat_fee_schedule:
|
||||
return self.compute_for_flat_fee_schedule()
|
||||
return self.compute_for_event()
|
||||
except PricingError as e:
|
||||
return {
|
||||
'error': type(e),
|
||||
'error_details': e.details,
|
||||
}
|
||||
|
||||
def compute_for_flat_fee_schedule(self):
|
||||
if self.agenda_pricing.subscription_required and not self.serialized_subscription:
|
||||
return
|
||||
return self.agenda_pricing.get_pricing_data(
|
||||
request=self.request,
|
||||
subscription=self.serialized_subscription,
|
||||
user_external_id=self.cleaned_data['user_external_id'],
|
||||
adult_external_id=self.cleaned_data['adult_external_id'],
|
||||
)
|
||||
|
||||
def compute_for_event(self):
|
||||
if not self.serialized_event or not self.serialized_subscription:
|
||||
return
|
||||
try:
|
||||
return self.agenda_pricing.get_pricing_data_for_event(
|
||||
request=self.request,
|
||||
agenda=self.agenda,
|
||||
event=self.serialized_event,
|
||||
subscription=self.serialized_subscription,
|
||||
check_status={
|
||||
'status': self.booking_status,
|
||||
'check_type': self.check_type_slug,
|
||||
},
|
||||
booking={},
|
||||
user_external_id=self.cleaned_data['user_external_id'],
|
||||
adult_external_id=self.cleaned_data['adult_external_id'],
|
||||
)
|
||||
except PricingError as e:
|
||||
return {'error': e.details}
|
||||
return self.agenda_pricing.get_pricing_data_for_event(
|
||||
request=self.request,
|
||||
agenda=self.agenda,
|
||||
event=self.serialized_event,
|
||||
subscription=self.serialized_subscription,
|
||||
check_status={
|
||||
'status': self.booking_status,
|
||||
'check_type': self.check_type_slug,
|
||||
},
|
||||
booking={},
|
||||
user_external_id=self.cleaned_data['user_external_id'],
|
||||
adult_external_id=self.cleaned_data['adult_external_id'],
|
||||
)
|
||||
|
||||
|
||||
class NewCheckTypeForm(forms.ModelForm):
|
||||
|
|
|
@ -694,6 +694,9 @@ class BillingDate(models.Model):
|
|||
date_start = models.DateField(_('Billing start date'))
|
||||
label = models.CharField(_('Label'), max_length=150)
|
||||
|
||||
def __str__(self):
|
||||
return '%s (%s)' % (self.date_start.strftime('%d/%m/%Y'), self.label)
|
||||
|
||||
def export_json(self):
|
||||
return {
|
||||
'date_start': self.date_start.strftime('%Y-%m-%d'),
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
<div aria-labelledby="tab-debug" hidden id="panel-debug" role="tabpanel" tabindex="0">
|
||||
<form method="get" enctype="multipart/form-data" action="{% url 'lingo-manager-agenda-pricing-test-tool' object.pk %}">
|
||||
{{ test_tool_form.as_p }}
|
||||
{% if not object.flat_fee_schedule %}
|
||||
<script>
|
||||
$(function() {
|
||||
var presences = {};
|
||||
|
@ -109,6 +110,7 @@
|
|||
});
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
||||
<div class="buttons">
|
||||
<button class="submit-button">{% trans "Compute" %}</button>
|
||||
</div>
|
||||
|
@ -133,7 +135,7 @@
|
|||
{% for billing_date in billing_dates %}
|
||||
<li>
|
||||
<a rel="popup" href="{% url 'lingo-manager-agenda-pricing-billing-date-edit' object.pk billing_date.pk %}">
|
||||
{{ billing_date.date_start|date:'d/m/Y' }} ({{ billing_date.label }})
|
||||
{{ billing_date }}
|
||||
</a>
|
||||
<a class="delete" rel="popup" href="{% url 'lingo-manager-agenda-pricing-billing-date-delete' object.pk billing_date.pk %}">{% trans "remove"%}</a>
|
||||
</li>
|
||||
|
|
|
@ -822,7 +822,7 @@ def test_detail_agenda_pricing_1_category(app, admin_user):
|
|||
@mock.patch('lingo.pricing.forms.get_event')
|
||||
@mock.patch('lingo.pricing.forms.get_subscriptions')
|
||||
@mock.patch('lingo.pricing.models.AgendaPricing.get_pricing_data_for_event')
|
||||
def test_detail_agenda_pricing_test_tool(
|
||||
def test_detail_agenda_pricing_test_tool_for_event(
|
||||
mock_pricing_data_event, mock_subscriptions, mock_event, app, admin_user
|
||||
):
|
||||
agenda = Agenda.objects.create(label='Foo bar')
|
||||
|
@ -836,6 +836,7 @@ def test_detail_agenda_pricing_test_tool(
|
|||
|
||||
app = login(app)
|
||||
resp = app.get('/manage/pricing/agenda-pricing/%s/' % agenda_pricing.pk)
|
||||
assert 'billing_date' not in resp.context['test_tool_form'].fields
|
||||
assert 'Computed pricing data' not in resp
|
||||
|
||||
# check event date
|
||||
|
@ -921,12 +922,15 @@ def test_detail_agenda_pricing_test_tool(
|
|||
mock_pricing_data_event.side_effect = PricingError(details={'foo': 'error'})
|
||||
resp = resp.form.submit().follow()
|
||||
assert 'Computed pricing data' in resp
|
||||
assert '<pre>{'error': {'foo': 'error'}}</pre>' in resp
|
||||
assert ''error': <class 'lingo.pricing.models.PricingError'>' in resp
|
||||
assert ''error_details': {'foo': 'error'}' in resp
|
||||
|
||||
|
||||
@mock.patch('lingo.pricing.forms.get_event')
|
||||
@mock.patch('lingo.pricing.forms.get_subscriptions')
|
||||
def test_detail_agenda_pricing_test_tool_event_error(mock_subscriptions, mock_event, app, admin_user):
|
||||
def test_detail_agenda_pricing_test_tool_for_event_event_error(
|
||||
mock_subscriptions, mock_event, app, admin_user
|
||||
):
|
||||
agenda = Agenda.objects.create(label='Foo bar')
|
||||
pricing = Pricing.objects.create(label='Foo bar')
|
||||
agenda_pricing = AgendaPricing.objects.create(
|
||||
|
@ -951,7 +955,9 @@ def test_detail_agenda_pricing_test_tool_event_error(mock_subscriptions, mock_ev
|
|||
|
||||
@mock.patch('lingo.pricing.forms.get_event')
|
||||
@mock.patch('lingo.pricing.forms.get_subscriptions')
|
||||
def test_detail_agenda_pricing_test_tool_subscription_error(mock_subscriptions, mock_event, app, admin_user):
|
||||
def test_detail_agenda_pricing_test_tool_for_event_subscription_error(
|
||||
mock_subscriptions, mock_event, app, admin_user
|
||||
):
|
||||
agenda = Agenda.objects.create(label='Foo bar')
|
||||
pricing = Pricing.objects.create(label='Foo bar')
|
||||
agenda_pricing = AgendaPricing.objects.create(
|
||||
|
@ -978,7 +984,7 @@ def test_detail_agenda_pricing_test_tool_subscription_error(mock_subscriptions,
|
|||
@mock.patch('lingo.pricing.forms.get_event')
|
||||
@mock.patch('lingo.pricing.forms.get_subscriptions')
|
||||
@mock.patch('lingo.pricing.models.AgendaPricing.get_pricing_data_for_event')
|
||||
def test_detail_agenda_pricing_test_tool_booking_status(
|
||||
def test_detail_agenda_pricing_test_tool_for_event_booking_status(
|
||||
mock_pricing_data_event, mock_subscriptions, mock_event, app, admin_user
|
||||
):
|
||||
agenda = Agenda.objects.create(label='Foo bar')
|
||||
|
@ -1058,6 +1064,213 @@ def test_detail_agenda_pricing_test_tool_booking_status(
|
|||
}
|
||||
|
||||
|
||||
@mock.patch('lingo.pricing.forms.get_subscriptions')
|
||||
@mock.patch('lingo.pricing.models.AgendaPricing.get_pricing_data')
|
||||
def test_detail_agenda_pricing_test_tool_for_flat_fee_schedule(
|
||||
mock_pricing_data, mock_subscriptions, app, admin_user
|
||||
):
|
||||
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=True,
|
||||
subscription_required=True,
|
||||
)
|
||||
agenda_pricing.agendas.add(agenda)
|
||||
|
||||
app = login(app)
|
||||
resp = app.get('/manage/pricing/agenda-pricing/%s/' % agenda_pricing.pk)
|
||||
assert 'event_slug' not in resp.context['test_tool_form'].fields
|
||||
assert 'booking_status' not in resp.context['test_tool_form'].fields
|
||||
assert 'billing_date' not in resp.context['test_tool_form'].fields
|
||||
assert 'Computed pricing data' not in resp
|
||||
|
||||
# check subscriptions dates
|
||||
mock_subscriptions.return_value = []
|
||||
resp.form['agenda'] = agenda.pk
|
||||
resp.form['user_external_id'] = 'user:1'
|
||||
resp.form['adult_external_id'] = 'adult:1'
|
||||
resp = resp.form.submit().follow()
|
||||
assert mock_pricing_data.call_args_list == []
|
||||
assert 'Computed pricing data' not in resp
|
||||
assert resp.context['test_tool_form'].errors['user_external_id'] == [
|
||||
'No subscription found for this period'
|
||||
]
|
||||
|
||||
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 = resp.form.submit().follow()
|
||||
assert 'Computed pricing data' not in resp
|
||||
assert resp.context['test_tool_form'].errors['user_external_id'] == [
|
||||
'No subscription found for this period'
|
||||
]
|
||||
|
||||
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', 'pricing': Decimal('42')}
|
||||
resp = resp.form.submit().follow()
|
||||
assert 'Computed pricing data' in resp
|
||||
assert mock_pricing_data.call_args_list == [
|
||||
mock.call(
|
||||
request=mock.ANY,
|
||||
subscription={'date_start': '2021-09-02', 'date_end': '2021-09-03'},
|
||||
user_external_id='user:1',
|
||||
adult_external_id='adult:1',
|
||||
)
|
||||
]
|
||||
assert '<p>Pricing: 42.00</p>' in resp
|
||||
assert '<pre>{'foo': 'bar', 'pricing': Decimal('42')}</pre>' in resp
|
||||
|
||||
mock_pricing_data.side_effect = PricingError(details={'foo': 'error'})
|
||||
resp = resp.form.submit().follow()
|
||||
assert 'Computed pricing data' in resp
|
||||
assert ''error': <class 'lingo.pricing.models.PricingError'>' in resp
|
||||
assert ''error_details': {'foo': 'error'}' in resp
|
||||
|
||||
billing_date1 = agenda_pricing.billingdates.create(
|
||||
date_start=datetime.date(2021, 9, 1),
|
||||
label='Foo 1',
|
||||
)
|
||||
billing_date2 = agenda_pricing.billingdates.create(
|
||||
date_start=datetime.date(2021, 9, 15),
|
||||
label='Foo 2',
|
||||
)
|
||||
|
||||
# check with billing dates
|
||||
mock_pricing_data.reset_mock()
|
||||
resp = app.get('/manage/pricing/agenda-pricing/%s/' % agenda_pricing.pk)
|
||||
resp.form['agenda'] = agenda.pk
|
||||
resp.form['billing_date'] = billing_date1.pk
|
||||
resp.form['user_external_id'] = 'user:1'
|
||||
resp.form['adult_external_id'] = 'adult:1'
|
||||
resp = resp.form.submit().follow()
|
||||
assert mock_pricing_data.call_args_list == [
|
||||
mock.call(
|
||||
request=mock.ANY,
|
||||
subscription={'date_start': '2021-09-02', 'date_end': '2021-09-03'},
|
||||
user_external_id='user:1',
|
||||
adult_external_id='adult:1',
|
||||
)
|
||||
]
|
||||
|
||||
mock_pricing_data.reset_mock()
|
||||
resp.form['billing_date'] = billing_date2.pk
|
||||
resp = resp.form.submit().follow()
|
||||
assert mock_pricing_data.call_args_list == []
|
||||
|
||||
mock_subscriptions.return_value = [
|
||||
{
|
||||
'date_start': '2021-09-01',
|
||||
'date_end': '2021-09-15',
|
||||
},
|
||||
]
|
||||
mock_pricing_data.reset_mock()
|
||||
resp = resp.form.submit().follow()
|
||||
assert mock_pricing_data.call_args_list == []
|
||||
|
||||
mock_subscriptions.return_value = [
|
||||
{
|
||||
'date_start': '2021-09-15',
|
||||
'date_end': '2021-09-16',
|
||||
},
|
||||
]
|
||||
mock_pricing_data.reset_mock()
|
||||
resp = resp.form.submit().follow()
|
||||
assert mock_pricing_data.call_args_list == [
|
||||
mock.call(
|
||||
request=mock.ANY,
|
||||
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 = resp.form.submit().follow()
|
||||
assert mock_pricing_data.call_args_list == [
|
||||
mock.call(
|
||||
request=mock.ANY,
|
||||
subscription={'date_start': '2021-09-30', 'date_end': '2021-10-01'},
|
||||
user_external_id='user:1',
|
||||
adult_external_id='adult:1',
|
||||
)
|
||||
]
|
||||
|
||||
# check with subscription_required False
|
||||
agenda_pricing.subscription_required = False
|
||||
agenda_pricing.save()
|
||||
mock_pricing_data.reset_mock()
|
||||
mock_subscriptions.reset_mock()
|
||||
resp = app.get('/manage/pricing/agenda-pricing/%s/' % agenda_pricing.pk)
|
||||
assert 'agenda' not in resp.context['test_tool_form'].fields
|
||||
resp.form['billing_date'] = billing_date1.pk
|
||||
resp.form['user_external_id'] = 'user:1'
|
||||
resp.form['adult_external_id'] = 'adult:1'
|
||||
resp = resp.form.submit().follow()
|
||||
assert mock_subscriptions.call_args_list == []
|
||||
assert mock_pricing_data.call_args_list == [
|
||||
mock.call(
|
||||
request=mock.ANY,
|
||||
subscription=None,
|
||||
user_external_id='user:1',
|
||||
adult_external_id='adult:1',
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
@mock.patch('lingo.pricing.forms.get_subscriptions')
|
||||
def test_detail_agenda_pricing_test_tool_for_flat_fee_schedule_subscription_error(
|
||||
mock_subscriptions, app, admin_user
|
||||
):
|
||||
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=True,
|
||||
)
|
||||
agenda_pricing.agendas.add(agenda)
|
||||
|
||||
mock_subscriptions.side_effect = ChronoError('foo bar')
|
||||
|
||||
app = login(app)
|
||||
resp = app.get('/manage/pricing/agenda-pricing/%s/' % agenda_pricing.pk)
|
||||
resp.form['agenda'] = agenda.pk
|
||||
resp.form['user_external_id'] = 'user:1'
|
||||
resp.form['adult_external_id'] = 'adult:1'
|
||||
resp = resp.form.submit().follow()
|
||||
assert resp.context['test_tool_form'].errors['user_external_id'] == ['foo bar']
|
||||
|
||||
|
||||
def test_edit_agenda_pricing_matrix_3_categories(app, admin_user):
|
||||
category1 = CriteriaCategory.objects.create(label='Cat 1')
|
||||
criteria11 = Criteria.objects.create(label='Crit 1-1', slug='crit-1-1', category=category1, order=1)
|
||||
|
|
Loading…
Reference in New Issue