Compare commits
4 Commits
688d5157c2
...
6448b16220
Author | SHA1 | Date |
---|---|---|
Lauréline Guérin | 6448b16220 | |
Lauréline Guérin | f07f664e0c | |
Lauréline Guérin | 736136afd0 | |
Lauréline Guérin | 4615f17360 |
|
@ -759,6 +759,10 @@ class AbstractJournalLine(models.Model):
|
|||
),
|
||||
'PricingDataError': _('Impossible to determine a pricing for criterias: %(criterias)s'),
|
||||
'PricingDataFormatError': _('Pricing is not a %(wanted)s: %(pricing)s'),
|
||||
'MinPricingDataError': _(
|
||||
'Impossible to determine a minimal pricing for criterias: %(criterias)s'
|
||||
),
|
||||
'MinPricingDataFormatError': _('Minimal pricing is not a %(wanted)s: %(pricing)s'),
|
||||
'PricingReductionRateError': _('Impossible to determine a reduction rate'),
|
||||
'PricingReductionRateFormatError': _('Reduction rate is not a %(wanted)s: %(reduction_rate)s'),
|
||||
'PricingReductionRateValueError': _('Reduction rate bad value: %(reduction_rate)s'),
|
||||
|
|
|
@ -52,10 +52,18 @@ class PricingDataError(PricingError):
|
|||
pass
|
||||
|
||||
|
||||
class MinPricingDataError(PricingError):
|
||||
pass
|
||||
|
||||
|
||||
class PricingDataFormatError(PricingError):
|
||||
pass
|
||||
|
||||
|
||||
class MinPricingDataFormatError(PricingError):
|
||||
pass
|
||||
|
||||
|
||||
class PricingReductionRateError(PricingError):
|
||||
pass
|
||||
|
||||
|
@ -586,7 +594,7 @@ class Pricing(WithApplicationMixin, models.Model):
|
|||
context['payer_external_raw_id'] = payer_external_id.split(':')[1]
|
||||
return self.get_extra_variables(request, context)
|
||||
|
||||
def format_pricing_data(self):
|
||||
def format_pricing_data(self, field='pricing'):
|
||||
# format data to ignore category ordering
|
||||
|
||||
def _format(data):
|
||||
|
@ -604,13 +612,13 @@ class Pricing(WithApplicationMixin, models.Model):
|
|||
|
||||
return {
|
||||
self.format_pricing_data_key(criterias): pricing
|
||||
for criterias, pricing in _format(self.pricing_data)
|
||||
for criterias, pricing in _format(getattr(self, '%s_data' % field))
|
||||
}
|
||||
|
||||
def format_pricing_data_key(self, values):
|
||||
return '||'.join(sorted(values))
|
||||
|
||||
def compute_pricing(self, context):
|
||||
def _compute_pricing(self, context, field):
|
||||
criterias = {}
|
||||
categories = []
|
||||
# for each category
|
||||
|
@ -640,22 +648,32 @@ class Pricing(WithApplicationMixin, models.Model):
|
|||
criterias[category.slug] = default_criterias[0].slug
|
||||
|
||||
# now search for pricing values matching found criterias
|
||||
pricing_data = self.format_pricing_data()
|
||||
pricing_data = self.format_pricing_data(field=field)
|
||||
pricing = pricing_data.get(
|
||||
self.format_pricing_data_key(['%s:%s' % (k, v) for k, v in criterias.items()])
|
||||
)
|
||||
if pricing is None:
|
||||
if field == 'min_pricing':
|
||||
raise MinPricingDataError(details={'criterias': criterias})
|
||||
raise PricingDataError(details={'criterias': criterias})
|
||||
|
||||
try:
|
||||
pricing = decimal.Decimal(pricing)
|
||||
except (decimal.InvalidOperation, ValueError, TypeError):
|
||||
if field == 'min_pricing':
|
||||
raise MinPricingDataFormatError(details={'pricing': pricing, 'wanted': 'decimal'})
|
||||
raise PricingDataFormatError(details={'pricing': pricing, 'wanted': 'decimal'})
|
||||
|
||||
if self.kind == 'effort':
|
||||
return round(pricing, 4), criterias
|
||||
return round(pricing, 2), criterias
|
||||
|
||||
def compute_pricing(self, context):
|
||||
return self._compute_pricing(context, 'pricing')
|
||||
|
||||
def compute_min_pricing(self, context):
|
||||
return self._compute_pricing(context, 'min_pricing')
|
||||
|
||||
def _compute_template(self, request, original_context, user_external_id, payer_external_id, template):
|
||||
context = RequestContext(request)
|
||||
context.push(original_context)
|
||||
|
@ -699,14 +717,14 @@ class Pricing(WithApplicationMixin, models.Model):
|
|||
|
||||
new_pricing = round(pricing * (100 - reduction_rate) / 100, 2)
|
||||
adjusted_pricing = new_pricing
|
||||
if self.min_pricing is not None:
|
||||
adjusted_pricing = max(adjusted_pricing, self.min_pricing)
|
||||
min_pricing, dummy = self.compute_min_pricing(context=context)
|
||||
adjusted_pricing = max(adjusted_pricing, min_pricing)
|
||||
|
||||
return adjusted_pricing, {
|
||||
'computed_pricing': pricing,
|
||||
'reduction_rate': reduction_rate,
|
||||
'reduced_pricing': new_pricing,
|
||||
'min_pricing': self.min_pricing,
|
||||
'min_pricing': min_pricing,
|
||||
'bounded_pricing': adjusted_pricing,
|
||||
}
|
||||
|
||||
|
@ -854,9 +872,9 @@ class Pricing(WithApplicationMixin, models.Model):
|
|||
}
|
||||
)
|
||||
|
||||
def iter_pricing_matrix(self):
|
||||
def _iter_pricing_matrix(self, field):
|
||||
categories = self.categories.all().order_by('pricingcriteriacategory__order')[:3]
|
||||
pricing_data = self.format_pricing_data()
|
||||
pricing_data = self.format_pricing_data(field)
|
||||
|
||||
if not categories:
|
||||
return
|
||||
|
@ -877,6 +895,12 @@ class Pricing(WithApplicationMixin, models.Model):
|
|||
pricing_data=pricing_data,
|
||||
)
|
||||
|
||||
def iter_pricing_matrix(self):
|
||||
return self._iter_pricing_matrix('pricing')
|
||||
|
||||
def iter_min_pricing_matrix(self):
|
||||
return self._iter_pricing_matrix('min_pricing')
|
||||
|
||||
def get_pricing_matrix(self, main_criteria, categories, pricing_data):
|
||||
matrix = PricingMatrix(
|
||||
criteria=main_criteria,
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
<div class="pk-tabs">
|
||||
<div class="pk-tabs--tab-list" role="tablist">
|
||||
<button aria-controls="panel-matrix" aria-selected="true" id="tab-matrix" role="tab" tabindex="0">{% trans "Pricings" context 'amount' %}</button>
|
||||
{% if object.kind != 'basic' %}
|
||||
{% if object.kind == 'effort' %}
|
||||
<button aria-controls="panel-pricing-options" aria-selected="false" id="tab-pricing-options" role="tab" tabindex="-1">{% trans "Pricing options" %}</button>
|
||||
{% elif object.kind == 'reduction' %}
|
||||
<button aria-controls="panel-min-matrix" aria-selected="false" id="tab-min-matrix" role="tab" tabindex="-1">{% trans "Minimal pricings" %}</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="pk-tabs--container">
|
||||
|
@ -69,20 +71,59 @@
|
|||
{% endwith %}
|
||||
</div>
|
||||
|
||||
{% if object.kind != 'basic' %}
|
||||
{% if object.kind == 'effort' %}
|
||||
<div aria-labelledby="tab-pricing-options" hidden="" id="panel-pricing-options" role="tabpanel" tabindex="0">
|
||||
<ul>
|
||||
<li>{% trans "Minimal pricing:" %} {{ object.min_pricing|default_if_none:"" }}</li>
|
||||
</ul>
|
||||
{% if object.kind == 'effort' %}
|
||||
<ul>
|
||||
<li>{% trans "Maximal pricing:" %} {{ object.max_pricing|default_if_none:"" }}</li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
<ul>
|
||||
<li>{% trans "Maximal pricing:" %} {{ object.max_pricing|default_if_none:"" }}</li>
|
||||
</ul>
|
||||
<div class="panel--buttons">
|
||||
<a class="pk-button" rel="popup" href="{% url 'lingo-manager-pricing-pricingoptions-edit' object.pk %}">{% trans "Edit pricing options" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% elif object.kind == 'reduction' %}
|
||||
<div aria-labelledby="tab-min-matrix" hidden="" id="panel-min-matrix" role="tabpanel" tabindex="0">
|
||||
{% with iter_matrix=object.iter_min_pricing_matrix|list %}
|
||||
{% for matrix in iter_matrix %}
|
||||
<div class="section">
|
||||
{% if matrix.criteria %}<h3>{{ matrix.criteria.label }}</h3>{% endif %}
|
||||
<table class="main pricing-min-matrix-{{ matrix.criteria.slug }}">
|
||||
{% if matrix.rows.0.cells.0.criteria %}
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
{% for cell in matrix.rows.0.cells %}<th scope="col">{{ cell.criteria.label }}</th>{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
{% endif %}
|
||||
<tbody>
|
||||
{% for row in matrix.rows %}
|
||||
<tr class="pricing-row-{{ row.criteria.slug }}">
|
||||
<th scope="row">{{ row.criteria.label }}</th>
|
||||
{% for cell in row.cells %}
|
||||
<td class="pricing-cell-{{ cell.criteria.slug }}">{% spaceless %}
|
||||
{{ cell.value|floatformat:"2"|default_if_none:"" }}
|
||||
{% endspaceless %}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="panel--buttons">
|
||||
<a class="pk-button" href="{% if matrix.criteria %}{% url 'lingo-manager-pricing-min-matrix-slug-edit' object.pk matrix.criteria.slug %}{% else %}{% url 'lingo-manager-pricing-min-matrix-edit' object.pk %}{% endif %}">{% trans "Edit minimal pricing" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="big-msg-info">
|
||||
{% blocktrans trimmed %}
|
||||
This pricing is misconfigured.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
|
|
@ -4,57 +4,18 @@
|
|||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
{% if matrix.criteria %}
|
||||
<a href="{% url 'lingo-manager-pricing-matrix-slug-edit' object.pk matrix.criteria.slug %}">{% trans "Edit pricing" %}</a>
|
||||
<a href="{% url 'lingo-manager-pricing-matrix-slug-edit' object.pk matrix.criteria.slug %}">{% trans "Edit pricing" context 'matrix' %}</a>
|
||||
{% else %}
|
||||
<a href="{% url 'lingo-manager-pricing-matrix-edit' object.pk %}">{% trans "Edit pricing" %}</a>
|
||||
<a href="{% url 'lingo-manager-pricing-matrix-edit' object.pk %}">{% trans "Edit pricing" context 'matrix' %}</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans "Edit pricing" %}</h2>
|
||||
<h2>{% trans "Edit pricing" context 'matrix' %}</h2>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="section">
|
||||
{% if matrix.criteria %}<h3>{{ matrix.criteria.label }}</h3>{% endif %}
|
||||
<div>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.management_form }}
|
||||
<table class="main">
|
||||
{% if matrix.rows.0.cells.0.criteria %}
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
{% for cell in matrix.rows.0.cells %}
|
||||
<th>{{ cell.criteria.label }}</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
{% endif %}
|
||||
<tbody>
|
||||
{% for sub_form in form %}
|
||||
{% with row=matrix.rows|get:forloop.counter0 %}
|
||||
<tr>
|
||||
<th>{{ row.criteria.label }}</th>
|
||||
{% for field in sub_form %}
|
||||
<td>
|
||||
{{ field.errors.as_ul }}
|
||||
{{ field }}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="buttons">
|
||||
<button class="submit-button">{% trans "Save" %}</button>
|
||||
<a class="cancel" href="{% url 'lingo-manager-pricing-detail' object.pk %}">{% trans 'Cancel' %}</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'lingo/pricing/manager_pricing_matrix_form_fragment.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
{% load i18n %}
|
||||
<div class="section">
|
||||
{% if matrix.criteria %}<h3>{{ matrix.criteria.label }}</h3>{% endif %}
|
||||
<div>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.management_form }}
|
||||
<table class="main">
|
||||
{% if matrix.rows.0.cells.0.criteria %}
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
{% for cell in matrix.rows.0.cells %}
|
||||
<th>{{ cell.criteria.label }}</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
{% endif %}
|
||||
<tbody>
|
||||
{% for sub_form in form %}
|
||||
{% with row=matrix.rows|get:forloop.counter0 %}
|
||||
<tr>
|
||||
<th>{{ row.criteria.label }}</th>
|
||||
{% for field in sub_form %}
|
||||
<td>
|
||||
{{ field.errors.as_ul }}
|
||||
{{ field }}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="buttons">
|
||||
<button class="submit-button">{% trans "Save" %}</button>
|
||||
<a class="cancel" href="{% url 'lingo-manager-pricing-detail' object.pk %}">{% trans 'Cancel' %}</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,22 @@
|
|||
{% extends "lingo/pricing/manager_pricing_detail.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
{% if matrix.criteria %}
|
||||
<a href="{% url 'lingo-manager-pricing-min-matrix-slug-edit' object.pk matrix.criteria.slug %}">{% trans "Edit min pricing" %}</a>
|
||||
{% else %}
|
||||
<a href="{% url 'lingo-manager-pricing-min-matrix-edit' object.pk %}">{% trans "Edit min pricing" %}</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans "Edit min pricing" %}</h2>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'lingo/pricing/manager_pricing_matrix_form_fragment.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% endblock %}
|
|
@ -211,6 +211,16 @@ urlpatterns = [
|
|||
views.pricing_matrix_edit,
|
||||
name='lingo-manager-pricing-matrix-slug-edit',
|
||||
),
|
||||
path(
|
||||
'<int:pk>/matrix/edit/min/',
|
||||
views.pricing_min_matrix_edit,
|
||||
name='lingo-manager-pricing-min-matrix-edit',
|
||||
),
|
||||
re_path(
|
||||
r'^(?P<pk>\d+)/matrix/(?P<slug>[-_a-zA-Z0-9]+)/edit/min/$',
|
||||
views.pricing_min_matrix_edit,
|
||||
name='lingo-manager-pricing-min-matrix-slug-edit',
|
||||
),
|
||||
path('check-types/', views.check_type_list, name='lingo-manager-check-type-list'),
|
||||
path(
|
||||
'check-type/group/add/',
|
||||
|
|
|
@ -733,7 +733,7 @@ class PricingPricingOptionsEditView(UpdateView):
|
|||
form_class = PricingPricingOptionsForm
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().exclude(kind='basic')
|
||||
return super().get_queryset().filter(kind='effort')
|
||||
|
||||
def get_success_url(self):
|
||||
return '%s#open:pricing-options' % reverse('lingo-manager-pricing-detail', args=[self.object.pk])
|
||||
|
@ -931,10 +931,14 @@ pricing_billing_date_delete = PricingBillingDateDeleteView.as_view()
|
|||
|
||||
class PricingMatrixEdit(FormView):
|
||||
template_name = 'lingo/pricing/manager_pricing_matrix_form.html'
|
||||
field = 'pricing'
|
||||
|
||||
def get_pricing(self, request, *args, **kwargs):
|
||||
self.object = get_object_or_404(Pricing, pk=kwargs['pk'])
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.object = get_object_or_404(Pricing, pk=kwargs['pk'])
|
||||
matrix_list = list(self.object.iter_pricing_matrix())
|
||||
self.get_pricing(request, *args, **kwargs)
|
||||
matrix_list = list(getattr(self.object, 'iter_%s_matrix' % self.field)())
|
||||
if not matrix_list:
|
||||
raise Http404
|
||||
self.matrix = None
|
||||
|
@ -986,16 +990,18 @@ class PricingMatrixEdit(FormView):
|
|||
value = sub_data['crit_%s' % j]
|
||||
key = cell.criteria.identifier if cell.criteria else None
|
||||
matrix_pricing_data[key][row.criteria.identifier] = float(value)
|
||||
pricing_data = getattr(self.object, '%s_data' % self.field)
|
||||
if self.matrix.criteria:
|
||||
# full pricing model with 3 categories
|
||||
self.object.pricing_data = self.object.pricing_data or {}
|
||||
self.object.pricing_data[self.matrix.criteria.identifier] = matrix_pricing_data
|
||||
pricing_data = pricing_data or {}
|
||||
pricing_data[self.matrix.criteria.identifier] = matrix_pricing_data
|
||||
elif list(matrix_pricing_data.keys()) == [None]:
|
||||
# only one category
|
||||
self.object.pricing_data = matrix_pricing_data[None]
|
||||
pricing_data = matrix_pricing_data[None]
|
||||
else:
|
||||
# 2 categories
|
||||
self.object.pricing_data = matrix_pricing_data
|
||||
pricing_data = matrix_pricing_data
|
||||
setattr(self.object, '%s_data' % self.field, pricing_data)
|
||||
self.object.save()
|
||||
return self.form_valid(form)
|
||||
else:
|
||||
|
@ -1008,6 +1014,20 @@ class PricingMatrixEdit(FormView):
|
|||
pricing_matrix_edit = PricingMatrixEdit.as_view()
|
||||
|
||||
|
||||
class PricingMinMatrixEdit(PricingMatrixEdit):
|
||||
template_name = 'lingo/pricing/manager_pricing_min_matrix_form.html'
|
||||
field = 'min_pricing'
|
||||
|
||||
def get_pricing(self, request, *args, **kwargs):
|
||||
self.object = get_object_or_404(Pricing, pk=kwargs['pk'], kind='reduction')
|
||||
|
||||
def get_success_url(self):
|
||||
return '%s#open:min-matrix' % (reverse('lingo-manager-pricing-detail', args=[self.object.pk]),)
|
||||
|
||||
|
||||
pricing_min_matrix_edit = PricingMinMatrixEdit.as_view()
|
||||
|
||||
|
||||
class CheckTypeListView(WithApplicationsMixin, ListView):
|
||||
template_name = 'lingo/pricing/manager_check_type_list.html'
|
||||
model = CheckTypeGroup
|
||||
|
|
|
@ -2538,6 +2538,8 @@ def test_journal_pool_lines(app, admin_user, draft):
|
|||
('MultipleDefaultCriteriaCondition', {'category': 'cat-foo'}),
|
||||
('PricingDataError', {'criterias': {'qf': 'qf-1', 'foo': 'bar'}}),
|
||||
('PricingDataFormatError', {'pricing': 'foobar', 'wanted': 'decimal'}),
|
||||
('MinPricingDataError', {'criterias': {'qf': 'qf-1', 'foo': 'bar'}}),
|
||||
('MinPricingDataFormatError', {'pricing': 'foobar', 'wanted': 'decimal'}),
|
||||
('PricingReductionRateError', {}),
|
||||
('PricingReductionRateFormatError', {'reduction_rate': 'foo', 'wanted': 'decimal'}),
|
||||
('PricingReductionRateValueError', {'reduction_rate': 42}),
|
||||
|
@ -2663,7 +2665,7 @@ def test_journal_pool_lines(app, admin_user, draft):
|
|||
resp = app.get(
|
||||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk)
|
||||
)
|
||||
assert len(resp.pyquery('td.status')) == 30
|
||||
assert len(resp.pyquery('td.status')) == 32
|
||||
assert format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[0].pk).text()) == 'Success'
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[0].pk).text().strip()
|
||||
|
@ -2716,219 +2718,237 @@ def test_journal_pool_lines(app, admin_user, draft):
|
|||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[6].pk).text())
|
||||
== 'Error (Impossible to determine a reduction rate) ignore - mark as fixed'
|
||||
== 'Error (Impossible to determine a minimal pricing for criterias: qf-1 (category: qf), bar (category: foo)) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[6].pk).text().strip()
|
||||
== "{'error': 'PricingReductionRateError', 'error_details': {}} "
|
||||
== "{'error': 'MinPricingDataError', 'error_details': {'criterias': {'foo': 'bar', 'qf': 'qf-1'}}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[7].pk).text())
|
||||
== 'Error (Reduction rate is not a decimal: foo) ignore - mark as fixed'
|
||||
== 'Error (Minimal pricing is not a decimal: foobar) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[7].pk).text().strip()
|
||||
== "{'error': 'PricingReductionRateFormatError', 'error_details': {'reduction_rate': 'foo', 'wanted': 'decimal'}} "
|
||||
== "{'error': 'MinPricingDataFormatError', 'error_details': {'pricing': 'foobar', 'wanted': 'decimal'}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[8].pk).text())
|
||||
== 'Error (Reduction rate bad value: 42) ignore - mark as fixed'
|
||||
== 'Error (Impossible to determine a reduction rate) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[8].pk).text().strip()
|
||||
== "{'error': 'PricingReductionRateValueError', 'error_details': {'reduction_rate': 42}} "
|
||||
== "{'error': 'PricingReductionRateError', 'error_details': {}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[9].pk).text())
|
||||
== 'Error (Impossible to determine an effort rate target) ignore - mark as fixed'
|
||||
== 'Error (Reduction rate is not a decimal: foo) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[9].pk).text().strip()
|
||||
== "{'error': 'PricingEffortRateTargetError', 'error_details': {}} "
|
||||
== "{'error': 'PricingReductionRateFormatError', 'error_details': {'reduction_rate': 'foo', 'wanted': 'decimal'}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[10].pk).text())
|
||||
== 'Error (Effort rate target is not a decimal: foo) ignore - mark as fixed'
|
||||
== 'Error (Reduction rate bad value: 42) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[10].pk).text().strip()
|
||||
== "{'error': 'PricingEffortRateTargetFormatError', 'error_details': {'effort_rate_target': 'foo', 'wanted': 'decimal'}} "
|
||||
== "{'error': 'PricingReductionRateValueError', 'error_details': {'reduction_rate': 42}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[11].pk).text())
|
||||
== 'Error (Effort rate target bad value: 42) ignore - mark as fixed'
|
||||
== 'Error (Impossible to determine an effort rate target) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[11].pk).text().strip()
|
||||
== "{'error': 'PricingEffortRateTargetValueError', 'error_details': {'effort_rate_target': 42}} "
|
||||
== "{'error': 'PricingEffortRateTargetError', 'error_details': {}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[12].pk).text())
|
||||
== 'Error (Impossible to determine an accounting code) ignore - mark as fixed'
|
||||
== 'Error (Effort rate target is not a decimal: foo) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[12].pk).text().strip()
|
||||
== "{'error': 'PricingAccountingCodeError', 'error_details': {}} "
|
||||
== "{'error': 'PricingEffortRateTargetFormatError', 'error_details': {'effort_rate_target': 'foo', 'wanted': 'decimal'}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[13].pk).text())
|
||||
== 'Error (Unknown check status: unknown) ignore - mark as fixed'
|
||||
== 'Error (Effort rate target bad value: 42) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[13].pk).text().strip()
|
||||
== "{'error': 'PricingUnknownCheckStatusError', 'error_details': {'status': 'unknown'}} "
|
||||
== "{'error': 'PricingEffortRateTargetValueError', 'error_details': {'effort_rate_target': 42}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[14].pk).text())
|
||||
== 'Error (Event is not checked) ignore - mark as fixed'
|
||||
== 'Error (Impossible to determine an accounting code) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[14].pk).text().strip()
|
||||
== "{'error': 'PricingEventNotCheckedError', 'error_details': {}} "
|
||||
== "{'error': 'PricingAccountingCodeError', 'error_details': {}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[15].pk).text())
|
||||
== 'Error (Booking is not checked) ignore - mark as fixed'
|
||||
== 'Error (Unknown check status: unknown) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[15].pk).text().strip()
|
||||
== "{'error': 'PricingBookingNotCheckedError', 'error_details': {}} "
|
||||
== "{'error': 'PricingUnknownCheckStatusError', 'error_details': {'status': 'unknown'}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[16].pk).text())
|
||||
== 'Error (Multiple booking found) ignore - mark as fixed'
|
||||
== 'Error (Event is not checked) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[16].pk).text().strip()
|
||||
== "{'error': 'PricingMultipleBookingError', 'error_details': {}} "
|
||||
== "{'error': 'PricingEventNotCheckedError', 'error_details': {}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[17].pk).text())
|
||||
== 'Error (Check type error: not found) ignore - mark as fixed'
|
||||
== 'Error (Booking is not checked) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[17].pk).text().strip()
|
||||
== "{'error': 'PricingBookingCheckTypeError', 'error_details': {'reason': 'not-found'}} "
|
||||
== "{'error': 'PricingBookingNotCheckedError', 'error_details': {}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[18].pk).text())
|
||||
== 'Error (Check type error: pricing not configured (group: foo-bar, check type: foo-reason)) ignore - mark as fixed'
|
||||
== 'Error (Multiple booking found) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[18].pk).text().strip()
|
||||
== "{'error': 'PricingMultipleBookingError', 'error_details': {}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[19].pk).text())
|
||||
== 'Error (Check type error: not found) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[19].pk).text().strip()
|
||||
== "{'error': 'PricingBookingCheckTypeError', 'error_details': {'reason': 'not-found'}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[20].pk).text())
|
||||
== 'Error (Check type error: pricing not configured (group: foo-bar, check type: foo-reason)) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[20].pk).text().strip()
|
||||
== "{'error': 'PricingBookingCheckTypeError', 'error_details': {'check_type': 'foo-reason', "
|
||||
"'check_type_group': 'foo-bar', 'reason': 'not-configured'}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[19].pk).text())
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[21].pk).text())
|
||||
== 'Error (Check type error: wrong kind (group: foo-bar, check type: foo-reason)) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[19].pk).text().strip()
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[21].pk).text().strip()
|
||||
== "{'error': 'PricingBookingCheckTypeError', 'error_details': {'check_type': 'foo-reason', "
|
||||
"'check_type_group': 'foo-bar', 'reason': 'wrong-kind'}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[20].pk).text())
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[22].pk).text())
|
||||
== 'Error (Impossible to determine payer: template is empty) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[20].pk).text().strip()
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[22].pk).text().strip()
|
||||
== "{'error': 'PayerError', 'error_details': {'reason': 'empty-template'}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[21].pk).text())
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[23].pk).text())
|
||||
== 'Error (Impossible to determine payer: result is empty) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[21].pk).text().strip()
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[23].pk).text().strip()
|
||||
== "{'error': 'PayerError', 'error_details': {'reason': 'empty-result'}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[22].pk).text())
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[24].pk).text())
|
||||
== 'Error (Impossible to determine payer: syntax error) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[22].pk).text().strip()
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[24].pk).text().strip()
|
||||
== "{'error': 'PayerError', 'error_details': {'reason': 'syntax-error'}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[23].pk).text())
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[25].pk).text())
|
||||
== 'Error (Impossible to determine payer: variable error) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[23].pk).text().strip()
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[25].pk).text().strip()
|
||||
== "{'error': 'PayerError', 'error_details': {'reason': 'variable-error'}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[24].pk).text())
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[26].pk).text())
|
||||
== 'Error (Impossible to determine payer: card model is not configured) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[24].pk).text().strip()
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[26].pk).text().strip()
|
||||
== "{'error': 'PayerError', 'error_details': {'reason': 'missing-card-model'}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[25].pk).text())
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[27].pk).text())
|
||||
== 'Error (Impossible to determine payer: payer is not configured on regie) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[25].pk).text().strip()
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[27].pk).text().strip()
|
||||
== "{'error': 'PayerError', 'error_details': {'reason': 'missing-payer'}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[26].pk).text())
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[28].pk).text())
|
||||
== 'Error (Impossible to get payer foo: mapping not defined) ignore - mark as fixed'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[26].pk).text().strip()
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[28].pk).text().strip()
|
||||
== "{'error': 'PayerDataError', 'error_details': {'key': 'foo', 'reason': 'not-defined'}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[27].pk).text())
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[29].pk).text())
|
||||
== 'Fixed (Impossible to get payer foo: result is empty) reset'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[27].pk).text().strip()
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[29].pk).text().strip()
|
||||
== "{'error': 'PayerDataError', 'error_details': {'key': 'foo', 'reason': 'empty-result'}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[28].pk).text())
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[30].pk).text())
|
||||
== 'Ignored (Impossible to get payer foo: result is not a boolean) reset'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[28].pk).text().strip()
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[30].pk).text().strip()
|
||||
== "{'error': 'PayerDataError', 'error_details': {'key': 'foo', 'reason': 'not-a-boolean'}} "
|
||||
"{'agenda': 'agenda-a', 'primary_event': 'event-aa', 'slug': 'event-aa--date'} {}"
|
||||
)
|
||||
assert (
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[29].pk).text())
|
||||
format_status(resp.pyquery('tr[data-line-id="%s"] td.status' % lines[31].pk).text())
|
||||
== 'Success (Injected)'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[29].pk).text().strip()
|
||||
resp.pyquery('tr[data-details-for-line-id="%s"] td pre' % lines[31].pk).text().strip()
|
||||
== "{'foo': 'bar'} {} {}"
|
||||
)
|
||||
|
||||
|
@ -2964,12 +2984,12 @@ def test_journal_pool_lines(app, admin_user, draft):
|
|||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'payer_external_id': 'payer:2'},
|
||||
)
|
||||
assert len(resp.pyquery('tr td.status')) == 29
|
||||
assert len(resp.pyquery('tr td.status')) == 31
|
||||
resp = app.get(
|
||||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'payer_first_name': 'first'},
|
||||
)
|
||||
assert len(resp.pyquery('tr td.status')) == 30
|
||||
assert len(resp.pyquery('tr td.status')) == 32
|
||||
resp = app.get(
|
||||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'payer_first_name': 'first1'},
|
||||
|
@ -2979,7 +2999,7 @@ def test_journal_pool_lines(app, admin_user, draft):
|
|||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'payer_last_name': 'last'},
|
||||
)
|
||||
assert len(resp.pyquery('tr td.status')) == 30
|
||||
assert len(resp.pyquery('tr td.status')) == 32
|
||||
resp = app.get(
|
||||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'payer_last_name': 'last1'},
|
||||
|
@ -2994,12 +3014,12 @@ def test_journal_pool_lines(app, admin_user, draft):
|
|||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'payer_direct_debit': True},
|
||||
)
|
||||
assert len(resp.pyquery('tr td.status')) == 29
|
||||
assert len(resp.pyquery('tr td.status')) == 31
|
||||
resp = app.get(
|
||||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'user_external_id': 'user:1'},
|
||||
)
|
||||
assert len(resp.pyquery('tr td.status')) == 29
|
||||
assert len(resp.pyquery('tr td.status')) == 31
|
||||
resp = app.get(
|
||||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'user_external_id': 'user:2'},
|
||||
|
@ -3009,27 +3029,27 @@ def test_journal_pool_lines(app, admin_user, draft):
|
|||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'user_first_name': 'first'},
|
||||
)
|
||||
assert len(resp.pyquery('tr td.status')) == 30
|
||||
assert len(resp.pyquery('tr td.status')) == 32
|
||||
resp = app.get(
|
||||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'user_first_name': 'first1'},
|
||||
)
|
||||
assert len(resp.pyquery('tr td.status')) == 29
|
||||
assert len(resp.pyquery('tr td.status')) == 31
|
||||
resp = app.get(
|
||||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'user_last_name': 'last'},
|
||||
)
|
||||
assert len(resp.pyquery('tr td.status')) == 30
|
||||
assert len(resp.pyquery('tr td.status')) == 32
|
||||
resp = app.get(
|
||||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'user_last_name': 'last1'},
|
||||
)
|
||||
assert len(resp.pyquery('tr td.status')) == 29
|
||||
assert len(resp.pyquery('tr td.status')) == 31
|
||||
resp = app.get(
|
||||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'agenda': 'agenda-a'},
|
||||
)
|
||||
assert len(resp.pyquery('tr td.status')) == 28
|
||||
assert len(resp.pyquery('tr td.status')) == 30
|
||||
resp = app.get(
|
||||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'agenda': 'agenda-b'},
|
||||
|
@ -3044,7 +3064,7 @@ def test_journal_pool_lines(app, admin_user, draft):
|
|||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'event': 'agenda-a@event-aa'},
|
||||
)
|
||||
assert len(resp.pyquery('tr td.status')) == 27
|
||||
assert len(resp.pyquery('tr td.status')) == 29
|
||||
resp = app.get(
|
||||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'event': 'agenda-b@event-b'},
|
||||
|
@ -3079,12 +3099,12 @@ def test_journal_pool_lines(app, admin_user, draft):
|
|||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'status': 'error'},
|
||||
)
|
||||
assert len(resp.pyquery('tr td.status')) == 27
|
||||
assert len(resp.pyquery('tr td.status')) == 29
|
||||
resp = app.get(
|
||||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'status': 'error_todo'},
|
||||
)
|
||||
assert len(resp.pyquery('tr td.status')) == 25
|
||||
assert len(resp.pyquery('tr td.status')) == 27
|
||||
resp = app.get(
|
||||
'/manage/invoicing/regie/%s/campaign/%s/pool/%s/journal/' % (regie.pk, campaign.pk, pool.pk),
|
||||
params={'status': 'error_ignored'},
|
||||
|
|
|
@ -381,26 +381,8 @@ def test_edit_pricing_pricingoptions(app, admin_user):
|
|||
pricing.kind = 'reduction'
|
||||
pricing.save()
|
||||
resp = app.get('/manage/pricing/%s/' % pricing.pk)
|
||||
assert 'Pricing options' in resp
|
||||
resp = resp.click(href='/manage/pricing/%s/pricing-options/' % pricing.pk)
|
||||
assert 'min_pricing' in resp.context['form'].fields
|
||||
assert 'max_pricing' not in resp.context['form'].fields
|
||||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/pricing/%s/#open:pricing-options' % pricing.pk)
|
||||
pricing.refresh_from_db()
|
||||
assert pricing.min_pricing is None
|
||||
|
||||
resp = app.get('/manage/pricing/%s/pricing-options/' % pricing.pk)
|
||||
resp.form['min_pricing'] = 0
|
||||
resp = resp.form.submit()
|
||||
pricing.refresh_from_db()
|
||||
assert pricing.min_pricing == 0
|
||||
|
||||
resp = app.get('/manage/pricing/%s/pricing-options/' % pricing.pk)
|
||||
resp.form['min_pricing'] = 10
|
||||
resp = resp.form.submit()
|
||||
pricing.refresh_from_db()
|
||||
assert pricing.min_pricing == 10
|
||||
assert 'Pricing options' not in resp
|
||||
app.get('/manage/pricing/%s/pricing-options/' % pricing.pk, status=404)
|
||||
|
||||
pricing.kind = 'effort'
|
||||
pricing.save()
|
||||
|
@ -1105,6 +1087,114 @@ def test_detail_pricing_3_categories(app, admin_user):
|
|||
== '223.0000'
|
||||
)
|
||||
|
||||
pricing.kind = 'reduction'
|
||||
pricing.min_pricing_data = {
|
||||
'cat-1:crit-1-1': {
|
||||
'cat-2:crit-2-1': {
|
||||
'cat-3:crit-3-1': 1.11,
|
||||
'cat-3:crit-3-3': 'not-a-decimal',
|
||||
'cat-3:crit-3-4': 1.14,
|
||||
},
|
||||
'cat-2:crit-2-3': {
|
||||
'cat-3:crit-3-2': 1.32,
|
||||
},
|
||||
},
|
||||
'cat-1:crit-1-2': {
|
||||
'cat-2:crit-2-2': {
|
||||
'cat-3:crit-3-3': 2.23,
|
||||
},
|
||||
},
|
||||
}
|
||||
pricing.save()
|
||||
resp = app.get('/manage/pricing/%s/' % pricing.pk)
|
||||
ths = resp.pyquery.find('table.pricing-min-matrix-crit-1-1 thead th')
|
||||
assert len(ths) == 4
|
||||
assert ths[0].text is None
|
||||
assert ths[1].text == 'Crit 2-1'
|
||||
assert ths[2].text == 'Crit 2-2'
|
||||
assert ths[3].text == 'Crit 2-3'
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-min-matrix-crit-1-1 tr.pricing-row-crit-3-1 th')[0].text
|
||||
== 'Crit 3-1'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-min-matrix-crit-1-1 tr.pricing-row-crit-3-2 th')[0].text
|
||||
== 'Crit 3-2'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-min-matrix-crit-1-1 tr.pricing-row-crit-3-3 th')[0].text
|
||||
== 'Crit 3-3'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-min-matrix-crit-1-1 tr.pricing-row-crit-3-4 th')[0].text
|
||||
== 'Crit 3-4'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery.find(
|
||||
'table.pricing-min-matrix-crit-1-1 tr.pricing-row-crit-3-1 td.pricing-cell-crit-2-1'
|
||||
)[0].text
|
||||
== '1.11'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery.find(
|
||||
'table.pricing-min-matrix-crit-1-1 tr.pricing-row-crit-3-2 td.pricing-cell-crit-2-1'
|
||||
)[0].text
|
||||
is None
|
||||
) # not defined
|
||||
assert (
|
||||
resp.pyquery.find(
|
||||
'table.pricing-min-matrix-crit-1-1 tr.pricing-row-crit-3-3 td.pricing-cell-crit-2-1'
|
||||
)[0].text
|
||||
is None
|
||||
) # wrong value
|
||||
assert (
|
||||
resp.pyquery.find(
|
||||
'table.pricing-min-matrix-crit-1-1 tr.pricing-row-crit-3-4 td.pricing-cell-crit-2-1'
|
||||
)[0].text
|
||||
== '1.14'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery.find(
|
||||
'table.pricing-min-matrix-crit-1-1 tr.pricing-row-crit-3-2 td.pricing-cell-crit-2-3'
|
||||
)[0].text
|
||||
== '1.32'
|
||||
)
|
||||
assert '<h3>Crit 1-2</h3>' in resp
|
||||
ths = resp.pyquery.find('table.pricing-min-matrix-crit-1-2 thead th')
|
||||
assert len(ths) == 4
|
||||
assert ths[0].text is None
|
||||
assert ths[1].text == 'Crit 2-1'
|
||||
assert ths[2].text == 'Crit 2-2'
|
||||
assert ths[3].text == 'Crit 2-3'
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-min-matrix-crit-1-2 tr.pricing-row-crit-3-1 th')[0].text
|
||||
== 'Crit 3-1'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-min-matrix-crit-1-2 tr.pricing-row-crit-3-2 th')[0].text
|
||||
== 'Crit 3-2'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-min-matrix-crit-1-2 tr.pricing-row-crit-3-3 th')[0].text
|
||||
== 'Crit 3-3'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-min-matrix-crit-1-2 tr.pricing-row-crit-3-4 th')[0].text
|
||||
== 'Crit 3-4'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery.find(
|
||||
'table.pricing-min-matrix-crit-1-2 tr.pricing-row-crit-3-2 td.pricing-cell-crit-2-2'
|
||||
)[0].text
|
||||
is None
|
||||
) # not defined
|
||||
assert (
|
||||
resp.pyquery.find(
|
||||
'table.pricing-min-matrix-crit-1-2 tr.pricing-row-crit-3-3 td.pricing-cell-crit-2-2'
|
||||
)[0].text
|
||||
== '2.23'
|
||||
)
|
||||
|
||||
|
||||
def test_detail_pricing_2_categories(app, admin_user):
|
||||
category2 = CriteriaCategory.objects.create(label='Cat 2')
|
||||
|
@ -1139,31 +1229,96 @@ def test_detail_pricing_2_categories(app, admin_user):
|
|||
app = login(app)
|
||||
resp = app.get('/manage/pricing/%s/' % pricing.pk)
|
||||
assert len(resp.pyquery.find('div.section.prixing-matrix h3')) == 0
|
||||
ths = resp.pyquery.find('table thead th')
|
||||
ths = resp.pyquery.find('table.pricing-matrix- thead th')
|
||||
assert len(ths) == 4
|
||||
assert ths[0].text is None
|
||||
assert ths[1].text == 'Crit 2-1'
|
||||
assert ths[2].text == 'Crit 2-2'
|
||||
assert ths[3].text == 'Crit 2-3'
|
||||
assert resp.pyquery.find('table tr.pricing-row-crit-3-1 th')[0].text == 'Crit 3-1'
|
||||
assert resp.pyquery.find('table tr.pricing-row-crit-3-2 th')[0].text == 'Crit 3-2'
|
||||
assert resp.pyquery.find('table tr.pricing-row-crit-3-3 th')[0].text == 'Crit 3-3'
|
||||
assert resp.pyquery.find('table tr.pricing-row-crit-3-4 th')[0].text == 'Crit 3-4'
|
||||
assert resp.pyquery.find('table tr.pricing-row-crit-3-1 td.pricing-cell-crit-2-1')[0].text == '111.00'
|
||||
assert resp.pyquery.find('table.pricing-matrix- tr.pricing-row-crit-3-1 th')[0].text == 'Crit 3-1'
|
||||
assert resp.pyquery.find('table.pricing-matrix- tr.pricing-row-crit-3-2 th')[0].text == 'Crit 3-2'
|
||||
assert resp.pyquery.find('table.pricing-matrix- tr.pricing-row-crit-3-3 th')[0].text == 'Crit 3-3'
|
||||
assert resp.pyquery.find('table.pricing-matrix- tr.pricing-row-crit-3-4 th')[0].text == 'Crit 3-4'
|
||||
assert (
|
||||
resp.pyquery.find('table tr.pricing-row-crit-3-2 td.pricing-cell-crit-2-1')[0].text is None
|
||||
resp.pyquery.find('table.pricing-matrix- tr.pricing-row-crit-3-1 td.pricing-cell-crit-2-1')[0].text
|
||||
== '111.00'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-matrix- tr.pricing-row-crit-3-2 td.pricing-cell-crit-2-1')[0].text
|
||||
is None
|
||||
) # not defined
|
||||
assert (
|
||||
resp.pyquery.find('table tr.pricing-row-crit-3-3 td.pricing-cell-crit-2-1')[0].text is None
|
||||
resp.pyquery.find('table.pricing-matrix- tr.pricing-row-crit-3-3 td.pricing-cell-crit-2-1')[0].text
|
||||
is None
|
||||
) # wrong value
|
||||
assert resp.pyquery.find('table tr.pricing-row-crit-3-4 td.pricing-cell-crit-2-1')[0].text == '114.00'
|
||||
assert resp.pyquery.find('table tr.pricing-row-crit-3-2 td.pricing-cell-crit-2-3')[0].text == '132.00'
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-matrix- tr.pricing-row-crit-3-4 td.pricing-cell-crit-2-1')[0].text
|
||||
== '114.00'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-matrix- tr.pricing-row-crit-3-2 td.pricing-cell-crit-2-3')[0].text
|
||||
== '132.00'
|
||||
)
|
||||
|
||||
pricing.kind = 'effort'
|
||||
pricing.save()
|
||||
resp = app.get('/manage/pricing/%s/' % pricing.pk)
|
||||
assert resp.pyquery.find('table tr.pricing-row-crit-3-2 td.pricing-cell-crit-2-3')[0].text == '132.0000'
|
||||
|
||||
pricing.kind = 'reduction'
|
||||
pricing.min_pricing_data = {
|
||||
'cat-2:crit-2-1': {
|
||||
'cat-3:crit-3-1': 1.11,
|
||||
'cat-3:crit-3-3': 'not-a-decimal',
|
||||
'cat-3:crit-3-4': 1.14,
|
||||
},
|
||||
'cat-2:crit-2-3': {
|
||||
'cat-3:crit-3-2': 1.32,
|
||||
},
|
||||
}
|
||||
pricing.save()
|
||||
resp = app.get('/manage/pricing/%s/' % pricing.pk)
|
||||
ths = resp.pyquery.find('table.pricing-min-matrix- thead th')
|
||||
assert len(ths) == 4
|
||||
assert ths[0].text is None
|
||||
assert ths[1].text == 'Crit 2-1'
|
||||
assert ths[2].text == 'Crit 2-2'
|
||||
assert ths[3].text == 'Crit 2-3'
|
||||
assert resp.pyquery.find('table.pricing-min-matrix- tr.pricing-row-crit-3-1 th')[0].text == 'Crit 3-1'
|
||||
assert resp.pyquery.find('table.pricing-min-matrix- tr.pricing-row-crit-3-2 th')[0].text == 'Crit 3-2'
|
||||
assert resp.pyquery.find('table.pricing-min-matrix- tr.pricing-row-crit-3-3 th')[0].text == 'Crit 3-3'
|
||||
assert resp.pyquery.find('table.pricing-min-matrix- tr.pricing-row-crit-3-4 th')[0].text == 'Crit 3-4'
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-min-matrix- tr.pricing-row-crit-3-1 td.pricing-cell-crit-2-1')[
|
||||
0
|
||||
].text
|
||||
== '1.11'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-min-matrix- tr.pricing-row-crit-3-2 td.pricing-cell-crit-2-1')[
|
||||
0
|
||||
].text
|
||||
is None
|
||||
) # not defined
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-min-matrix- tr.pricing-row-crit-3-3 td.pricing-cell-crit-2-1')[
|
||||
0
|
||||
].text
|
||||
is None
|
||||
) # wrong value
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-min-matrix- tr.pricing-row-crit-3-4 td.pricing-cell-crit-2-1')[
|
||||
0
|
||||
].text
|
||||
== '1.14'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-min-matrix- tr.pricing-row-crit-3-2 td.pricing-cell-crit-2-3')[
|
||||
0
|
||||
].text
|
||||
== '1.32'
|
||||
)
|
||||
|
||||
|
||||
def test_detail_pricing_1_category(app, admin_user):
|
||||
category3 = CriteriaCategory.objects.create(label='Cat 3')
|
||||
|
@ -1188,21 +1343,48 @@ def test_detail_pricing_1_category(app, admin_user):
|
|||
app = login(app)
|
||||
resp = app.get('/manage/pricing/%s/' % pricing.pk)
|
||||
assert len(resp.pyquery.find('div.section.prixing-matrix h3')) == 0
|
||||
ths = resp.pyquery.find('table thead')
|
||||
ths = resp.pyquery.find('table.pricing-matrix- thead')
|
||||
assert len(ths) == 0
|
||||
assert resp.pyquery.find('table tr.pricing-row-crit-3-1 th')[0].text == 'Crit 3-1'
|
||||
assert resp.pyquery.find('table tr.pricing-row-crit-3-2 th')[0].text == 'Crit 3-2'
|
||||
assert resp.pyquery.find('table tr.pricing-row-crit-3-3 th')[0].text == 'Crit 3-3'
|
||||
assert resp.pyquery.find('table tr.pricing-row-crit-3-4 th')[0].text == 'Crit 3-4'
|
||||
assert resp.pyquery.find('table tr.pricing-row-crit-3-1 td')[0].text == '111.00'
|
||||
assert resp.pyquery.find('table tr.pricing-row-crit-3-2 td')[0].text is None # not defined
|
||||
assert resp.pyquery.find('table tr.pricing-row-crit-3-3 td')[0].text is None # wrong value
|
||||
assert resp.pyquery.find('table tr.pricing-row-crit-3-4 td')[0].text == '114.00'
|
||||
assert resp.pyquery.find('table.pricing-matrix- tr.pricing-row-crit-3-1 th')[0].text == 'Crit 3-1'
|
||||
assert resp.pyquery.find('table.pricing-matrix- tr.pricing-row-crit-3-2 th')[0].text == 'Crit 3-2'
|
||||
assert resp.pyquery.find('table.pricing-matrix- tr.pricing-row-crit-3-3 th')[0].text == 'Crit 3-3'
|
||||
assert resp.pyquery.find('table.pricing-matrix- tr.pricing-row-crit-3-4 th')[0].text == 'Crit 3-4'
|
||||
assert resp.pyquery.find('table.pricing-matrix- tr.pricing-row-crit-3-1 td')[0].text == '111.00'
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-matrix- tr.pricing-row-crit-3-2 td')[0].text is None
|
||||
) # not defined
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-matrix- tr.pricing-row-crit-3-3 td')[0].text is None
|
||||
) # wrong value
|
||||
assert resp.pyquery.find('table.pricing-matrix- tr.pricing-row-crit-3-4 td')[0].text == '114.00'
|
||||
|
||||
pricing.kind = 'effort'
|
||||
pricing.save()
|
||||
resp = app.get('/manage/pricing/%s/' % pricing.pk)
|
||||
assert resp.pyquery.find('table tr.pricing-row-crit-3-4 td')[0].text == '114.0000'
|
||||
assert resp.pyquery.find('table.pricing-matrix- tr.pricing-row-crit-3-4 td')[0].text == '114.0000'
|
||||
|
||||
pricing.kind = 'reduction'
|
||||
pricing.min_pricing_data = {
|
||||
'cat-3:crit-3-1': 1.11,
|
||||
'cat-3:crit-3-3': 'not-a-decimal',
|
||||
'cat-3:crit-3-4': 1.14,
|
||||
}
|
||||
pricing.save()
|
||||
resp = app.get('/manage/pricing/%s/' % pricing.pk)
|
||||
ths = resp.pyquery.find('table.pricing-min-matrix- thead')
|
||||
assert len(ths) == 0
|
||||
assert resp.pyquery.find('table.pricing-min-matrix- tr.pricing-row-crit-3-1 th')[0].text == 'Crit 3-1'
|
||||
assert resp.pyquery.find('table.pricing-min-matrix- tr.pricing-row-crit-3-2 th')[0].text == 'Crit 3-2'
|
||||
assert resp.pyquery.find('table.pricing-min-matrix- tr.pricing-row-crit-3-3 th')[0].text == 'Crit 3-3'
|
||||
assert resp.pyquery.find('table.pricing-min-matrix- tr.pricing-row-crit-3-4 th')[0].text == 'Crit 3-4'
|
||||
assert resp.pyquery.find('table.pricing-min-matrix- tr.pricing-row-crit-3-1 td')[0].text == '1.11'
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-min-matrix- tr.pricing-row-crit-3-2 td')[0].text is None
|
||||
) # not defined
|
||||
assert (
|
||||
resp.pyquery.find('table.pricing-min-matrix- tr.pricing-row-crit-3-3 td')[0].text is None
|
||||
) # wrong value
|
||||
assert resp.pyquery.find('table.pricing-min-matrix- tr.pricing-row-crit-3-4 td')[0].text == '1.14'
|
||||
|
||||
|
||||
@mock.patch('lingo.pricing.forms.get_event')
|
||||
|
@ -1256,31 +1438,17 @@ def test_detail_pricing_test_tool_for_event(mock_pricing_data_event, mock_event,
|
|||
)
|
||||
]
|
||||
|
||||
# XXX Compat: html entities are slightly different under django 2 and django 3
|
||||
# the following code ensure tests pass under both versions.
|
||||
# The output looks exactly the same to an end user.
|
||||
assert '<p>Pricing: 42.00</p>' in resp
|
||||
django2_match = (
|
||||
'<pre>{'foo': 'bar', 'pricing': Decimal('42')}</pre>' in resp
|
||||
)
|
||||
django3_match = (
|
||||
assert (
|
||||
'<pre>{'foo': 'bar', 'pricing': Decimal('42')}</pre>' in resp
|
||||
)
|
||||
assert django2_match or django3_match
|
||||
|
||||
mock_pricing_data_event.side_effect = PricingError(details={'foo': 'error'})
|
||||
resp = resp.form.submit().follow()
|
||||
assert 'Computed pricing data' in resp
|
||||
|
||||
django2_match = ''error': <class 'lingo.pricing.models.PricingError'>' in resp
|
||||
django3_match = ''error': <class 'lingo.pricing.models.PricingError'>' in resp
|
||||
|
||||
assert django2_match or django3_match
|
||||
|
||||
django2_match = ''error_details': {'foo': 'error'}' in resp
|
||||
django3_match = ''error_details': {'foo': 'error'}' in resp
|
||||
|
||||
assert django2_match or django3_match
|
||||
assert ''error': <class 'lingo.pricing.models.PricingError'>' in resp
|
||||
assert ''error_details': {'foo': 'error'}' in resp
|
||||
|
||||
# check recurring event
|
||||
mock_pricing_data_event.reset_mock()
|
||||
|
@ -1432,28 +1600,16 @@ def test_detail_pricing_test_tool_for_flat_fee_schedule(mock_pricing_data, app,
|
|||
)
|
||||
]
|
||||
assert '<p>Pricing: 42.00</p>' in resp
|
||||
django2_match = (
|
||||
'<pre>{'foo': 'bar', 'pricing': Decimal('42')}</pre>' in resp
|
||||
)
|
||||
django3_match = (
|
||||
assert (
|
||||
'<pre>{'foo': 'bar', 'pricing': Decimal('42')}</pre>' in resp
|
||||
)
|
||||
|
||||
assert django2_match or django3_match
|
||||
|
||||
mock_pricing_data.side_effect = PricingError(details={'foo': 'error'})
|
||||
resp = resp.form.submit().follow()
|
||||
assert 'Computed pricing data' in resp
|
||||
|
||||
django2_match = ''error': <class 'lingo.pricing.models.PricingError'>' in resp
|
||||
django3_match = ''error': <class 'lingo.pricing.models.PricingError'>' in resp
|
||||
|
||||
assert django2_match or django3_match
|
||||
|
||||
django2_match = ''error_details': {'foo': 'error'}' in resp
|
||||
django3_match = ''error_details': {'foo': 'error'}' in resp
|
||||
|
||||
assert django2_match or django3_match
|
||||
assert ''error': <class 'lingo.pricing.models.PricingError'>' in resp
|
||||
assert ''error_details': {'foo': 'error'}' in resp
|
||||
|
||||
billing_date1 = pricing.billingdates.create(
|
||||
date_start=datetime.date(2021, 9, 1),
|
||||
|
@ -1630,6 +1786,11 @@ def test_edit_pricing_matrix_3_categories(app, admin_user):
|
|||
)
|
||||
app.get('/manage/pricing/%s/matrix/edit/' % pricing.pk, status=404)
|
||||
|
||||
app.get(
|
||||
'/manage/pricing/%s/matrix/%s/edit/min/' % (pricing.pk, criteria11.slug),
|
||||
status=404,
|
||||
)
|
||||
|
||||
pricing.kind = 'effort'
|
||||
pricing.save()
|
||||
resp = app.get('/manage/pricing/%s/matrix/%s/edit/' % (pricing.pk, criteria11.slug))
|
||||
|
@ -1637,6 +1798,104 @@ def test_edit_pricing_matrix_3_categories(app, admin_user):
|
|||
resp = resp.form.submit()
|
||||
pricing.refresh_from_db()
|
||||
assert pricing.pricing_data['cat-1:crit-1-1']['cat-2:crit-2-1']['cat-3:crit-3-1'] == 111.9999
|
||||
app.get(
|
||||
'/manage/pricing/%s/matrix/%s/edit/min/' % (pricing.pk, criteria11.slug),
|
||||
status=404,
|
||||
)
|
||||
|
||||
pricing.kind = 'reduction'
|
||||
pricing.min_pricing_data = {
|
||||
'cat-1:crit-1-1': {
|
||||
'cat-2:crit-2-1': {
|
||||
'cat-3:crit-3-1': 1.11,
|
||||
'cat-3:crit-3-3': 'not-a-decimal',
|
||||
'cat-3:crit-3-4': 1.14,
|
||||
},
|
||||
'cat-2:crit-2-3': {
|
||||
'cat-3:crit-3-2': 1.32,
|
||||
},
|
||||
},
|
||||
'cat-1:crit-1-2': {
|
||||
'cat-2:crit-2-2': {
|
||||
'cat-3:crit-3-3': 2.23,
|
||||
},
|
||||
},
|
||||
}
|
||||
pricing.save()
|
||||
resp = app.get('/manage/pricing/%s/' % pricing.pk)
|
||||
resp = resp.click(href='/manage/pricing/%s/matrix/%s/edit/min/' % (pricing.pk, criteria11.slug))
|
||||
assert resp.form['form-0-crit_0'].value == '1.11'
|
||||
assert resp.form['form-0-crit_1'].value == ''
|
||||
assert resp.form['form-0-crit_2'].value == ''
|
||||
assert resp.form['form-1-crit_0'].value == ''
|
||||
assert resp.form['form-1-crit_1'].value == ''
|
||||
assert resp.form['form-1-crit_2'].value == '1.32'
|
||||
assert resp.form['form-2-crit_0'].value == ''
|
||||
assert resp.form['form-2-crit_1'].value == ''
|
||||
assert resp.form['form-2-crit_2'].value == ''
|
||||
assert resp.form['form-3-crit_0'].value == '1.14'
|
||||
assert resp.form['form-3-crit_1'].value == ''
|
||||
assert resp.form['form-3-crit_2'].value == ''
|
||||
resp.form['form-0-crit_1'] = '1.21'
|
||||
resp.form['form-0-crit_2'] = '1.31'
|
||||
resp.form['form-1-crit_0'] = '1.12'
|
||||
resp.form['form-1-crit_1'] = '1.22'
|
||||
resp.form['form-1-crit_2'] = '1.32'
|
||||
resp.form['form-2-crit_0'] = '1.13'
|
||||
resp.form['form-2-crit_1'] = '1.23'
|
||||
resp.form['form-2-crit_2'] = '1.33'
|
||||
resp.form['form-3-crit_0'] = '9.14'
|
||||
resp.form['form-3-crit_1'] = '1.24'
|
||||
resp.form['form-3-crit_2'] = '1.34'
|
||||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/pricing/%s/#open:min-matrix' % pricing.pk)
|
||||
pricing.refresh_from_db()
|
||||
assert pricing.min_pricing_data == {
|
||||
'cat-1:crit-1-1': {
|
||||
'cat-2:crit-2-1': {
|
||||
'cat-3:crit-3-1': 1.11,
|
||||
'cat-3:crit-3-2': 1.12,
|
||||
'cat-3:crit-3-3': 1.13,
|
||||
'cat-3:crit-3-4': 9.14,
|
||||
},
|
||||
'cat-2:crit-2-2': {
|
||||
'cat-3:crit-3-1': 1.21,
|
||||
'cat-3:crit-3-2': 1.22,
|
||||
'cat-3:crit-3-3': 1.23,
|
||||
'cat-3:crit-3-4': 1.24,
|
||||
},
|
||||
'cat-2:crit-2-3': {
|
||||
'cat-3:crit-3-1': 1.31,
|
||||
'cat-3:crit-3-2': 1.32,
|
||||
'cat-3:crit-3-3': 1.33,
|
||||
'cat-3:crit-3-4': 1.34,
|
||||
},
|
||||
},
|
||||
'cat-1:crit-1-2': {
|
||||
'cat-2:crit-2-2': {
|
||||
'cat-3:crit-3-3': 2.23,
|
||||
},
|
||||
},
|
||||
}
|
||||
app.get(
|
||||
'/manage/pricing/%s/matrix/%s/edit/min/' % (pricing.pk, criteria12.slug),
|
||||
status=200,
|
||||
)
|
||||
|
||||
app.get('/manage/pricing/%s/matrix/%s/edit/min/' % (0, criteria11.slug), status=404)
|
||||
app.get(
|
||||
'/manage/pricing/%s/matrix/%s/edit/min/' % (pricing.pk, 'unknown'),
|
||||
status=404,
|
||||
)
|
||||
app.get(
|
||||
'/manage/pricing/%s/matrix/%s/edit/min/' % (pricing.pk, criteria21.slug),
|
||||
status=404,
|
||||
)
|
||||
app.get(
|
||||
'/manage/pricing/%s/matrix/%s/edit/min/' % (pricing.pk, criteria31.slug),
|
||||
status=404,
|
||||
)
|
||||
app.get('/manage/pricing/%s/matrix/edit/min/' % pricing.pk, status=404)
|
||||
|
||||
|
||||
def test_edit_pricing_matrix_2_categories(app, admin_user):
|
||||
|
@ -1729,6 +1988,11 @@ def test_edit_pricing_matrix_2_categories(app, admin_user):
|
|||
status=404,
|
||||
)
|
||||
|
||||
app.get(
|
||||
'/manage/pricing/%s/matrix/edit/min/' % pricing.pk,
|
||||
status=404,
|
||||
)
|
||||
|
||||
pricing.kind = 'effort'
|
||||
pricing.save()
|
||||
resp = app.get('/manage/pricing/%s/matrix/edit/' % pricing.pk)
|
||||
|
@ -1736,6 +2000,81 @@ def test_edit_pricing_matrix_2_categories(app, admin_user):
|
|||
resp = resp.form.submit()
|
||||
pricing.refresh_from_db()
|
||||
assert pricing.pricing_data['cat-2:crit-2-1']['cat-3:crit-3-1'] == 111.9999
|
||||
app.get(
|
||||
'/manage/pricing/%s/matrix/edit/min/' % pricing.pk,
|
||||
status=404,
|
||||
)
|
||||
|
||||
pricing.kind = 'reduction'
|
||||
pricing.min_pricing_data = {
|
||||
'cat-2:crit-2-1': {
|
||||
'cat-3:crit-3-1': 1.11,
|
||||
'cat-3:crit-3-3': 'not-a-decimal',
|
||||
'cat-3:crit-3-4': 1.14,
|
||||
},
|
||||
'cat-2:crit-2-3': {
|
||||
'cat-3:crit-3-2': 1.32,
|
||||
},
|
||||
}
|
||||
pricing.save()
|
||||
resp = app.get('/manage/pricing/%s/' % pricing.pk)
|
||||
resp = resp.click(href='/manage/pricing/%s/matrix/edit/min/' % pricing.pk)
|
||||
assert resp.form['form-0-crit_0'].value == '1.11'
|
||||
assert resp.form['form-0-crit_1'].value == ''
|
||||
assert resp.form['form-0-crit_2'].value == ''
|
||||
assert resp.form['form-1-crit_0'].value == ''
|
||||
assert resp.form['form-1-crit_1'].value == ''
|
||||
assert resp.form['form-1-crit_2'].value == '1.32'
|
||||
assert resp.form['form-2-crit_0'].value == ''
|
||||
assert resp.form['form-2-crit_1'].value == ''
|
||||
assert resp.form['form-2-crit_2'].value == ''
|
||||
assert resp.form['form-3-crit_0'].value == '1.14'
|
||||
assert resp.form['form-3-crit_1'].value == ''
|
||||
assert resp.form['form-3-crit_2'].value == ''
|
||||
resp.form['form-0-crit_1'] = '1.21'
|
||||
resp.form['form-0-crit_2'] = '1.31'
|
||||
resp.form['form-1-crit_0'] = '1.12'
|
||||
resp.form['form-1-crit_1'] = '1.22'
|
||||
resp.form['form-1-crit_2'] = '1.32'
|
||||
resp.form['form-2-crit_0'] = '1.13'
|
||||
resp.form['form-2-crit_1'] = '1.23'
|
||||
resp.form['form-2-crit_2'] = '1.33'
|
||||
resp.form['form-3-crit_0'] = '9.14'
|
||||
resp.form['form-3-crit_1'] = '1.24'
|
||||
resp.form['form-3-crit_2'] = '1.34'
|
||||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/pricing/%s/#open:min-matrix' % pricing.pk)
|
||||
pricing.refresh_from_db()
|
||||
assert pricing.min_pricing_data == {
|
||||
'cat-2:crit-2-1': {
|
||||
'cat-3:crit-3-1': 1.11,
|
||||
'cat-3:crit-3-2': 1.12,
|
||||
'cat-3:crit-3-3': 1.13,
|
||||
'cat-3:crit-3-4': 9.14,
|
||||
},
|
||||
'cat-2:crit-2-2': {
|
||||
'cat-3:crit-3-1': 1.21,
|
||||
'cat-3:crit-3-2': 1.22,
|
||||
'cat-3:crit-3-3': 1.23,
|
||||
'cat-3:crit-3-4': 1.24,
|
||||
},
|
||||
'cat-2:crit-2-3': {
|
||||
'cat-3:crit-3-1': 1.31,
|
||||
'cat-3:crit-3-2': 1.32,
|
||||
'cat-3:crit-3-3': 1.33,
|
||||
'cat-3:crit-3-4': 1.34,
|
||||
},
|
||||
}
|
||||
|
||||
app.get('/manage/pricing/%s/matrix/edit/min/' % 0, status=404)
|
||||
app.get(
|
||||
'/manage/pricing/%s/matrix/%s/edit/min/' % (pricing.pk, criteria21.slug),
|
||||
status=404,
|
||||
)
|
||||
app.get(
|
||||
'/manage/pricing/%s/matrix/%s/edit/min/' % (pricing.pk, criteria31.slug),
|
||||
status=404,
|
||||
)
|
||||
|
||||
|
||||
def test_edit_pricing_matrix_1_category(app, admin_user):
|
||||
|
@ -1784,6 +2123,8 @@ def test_edit_pricing_matrix_1_category(app, admin_user):
|
|||
status=404,
|
||||
)
|
||||
|
||||
app.get('/manage/pricing/%s/matrix/edit/min/' % pricing.pk, status=404)
|
||||
|
||||
pricing.kind = 'effort'
|
||||
pricing.save()
|
||||
resp = app.get('/manage/pricing/%s/matrix/edit/' % pricing.pk)
|
||||
|
@ -1791,6 +2132,39 @@ def test_edit_pricing_matrix_1_category(app, admin_user):
|
|||
resp = resp.form.submit()
|
||||
pricing.refresh_from_db()
|
||||
assert pricing.pricing_data['cat-3:crit-3-1'] == 111.9999
|
||||
app.get('/manage/pricing/%s/matrix/edit/min/' % pricing.pk, status=404)
|
||||
|
||||
pricing.kind = 'reduction'
|
||||
pricing.min_pricing_data = {
|
||||
'cat-3:crit-3-1': 1.11,
|
||||
'cat-3:crit-3-3': 'not-a-decimal',
|
||||
'cat-3:crit-3-4': 1.14,
|
||||
}
|
||||
pricing.save()
|
||||
resp = app.get('/manage/pricing/%s/' % pricing.pk)
|
||||
resp = resp.click(href='/manage/pricing/%s/matrix/edit/min/' % pricing.pk)
|
||||
assert resp.form['form-0-crit_0'].value == '1.11'
|
||||
assert resp.form['form-1-crit_0'].value == ''
|
||||
assert resp.form['form-2-crit_0'].value == ''
|
||||
assert resp.form['form-3-crit_0'].value == '1.14'
|
||||
resp.form['form-1-crit_0'] = '1.12'
|
||||
resp.form['form-2-crit_0'] = '1.13'
|
||||
resp.form['form-3-crit_0'] = '9.14'
|
||||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/pricing/%s/#open:min-matrix' % pricing.pk)
|
||||
pricing.refresh_from_db()
|
||||
assert pricing.min_pricing_data == {
|
||||
'cat-3:crit-3-1': 1.11,
|
||||
'cat-3:crit-3-2': 1.12,
|
||||
'cat-3:crit-3-3': 1.13,
|
||||
'cat-3:crit-3-4': 9.14,
|
||||
}
|
||||
|
||||
app.get('/manage/pricing/%s/matrix/edit/min/' % 0, status=404)
|
||||
app.get(
|
||||
'/manage/pricing/%s/matrix/%s/edit/min/' % (pricing.pk, criteria31.slug),
|
||||
status=404,
|
||||
)
|
||||
|
||||
|
||||
def test_edit_pricing_matrix_empty(app, admin_user):
|
||||
|
|
|
@ -14,6 +14,8 @@ from lingo.pricing.models import (
|
|||
Criteria,
|
||||
CriteriaCategory,
|
||||
CriteriaConditionNotFound,
|
||||
MinPricingDataError,
|
||||
MinPricingDataFormatError,
|
||||
MultipleDefaultCriteriaCondition,
|
||||
Pricing,
|
||||
PricingAccountingCodeError,
|
||||
|
@ -25,6 +27,7 @@ from lingo.pricing.models import (
|
|||
PricingEffortRateTargetError,
|
||||
PricingEffortRateTargetFormatError,
|
||||
PricingEffortRateTargetValueError,
|
||||
PricingError,
|
||||
PricingEventNotCheckedError,
|
||||
PricingMatrix,
|
||||
PricingMatrixCell,
|
||||
|
@ -512,7 +515,8 @@ def test_compute_condition(condition, context, result):
|
|||
assert criteria.compute_condition(context) == result
|
||||
|
||||
|
||||
def test_compute_pricing():
|
||||
@pytest.mark.parametrize('field', ['pricing', 'min_pricing'])
|
||||
def test_compute_pricing(field):
|
||||
agenda = Agenda.objects.create(label='Foo bar')
|
||||
category = CriteriaCategory.objects.create(label='QF', slug='qf')
|
||||
pricing = Pricing.objects.create(
|
||||
|
@ -521,9 +525,10 @@ def test_compute_pricing():
|
|||
)
|
||||
pricing.categories.add(category, through_defaults={'order': 1})
|
||||
pricing.agendas.add(agenda)
|
||||
compute_method = getattr(pricing, 'compute_%s' % field)
|
||||
# no criteria defined on pricing
|
||||
with pytest.raises(CriteriaConditionNotFound) as e:
|
||||
pricing.compute_pricing(context={'qf': 2})
|
||||
compute_method(context={'qf': 2})
|
||||
assert e.value.details == {'category': 'qf'}
|
||||
|
||||
# conditions are not set
|
||||
|
@ -532,7 +537,7 @@ def test_compute_pricing():
|
|||
pricing.criterias.add(criteria1)
|
||||
pricing.criterias.add(criteria2)
|
||||
with pytest.raises(CriteriaConditionNotFound) as e:
|
||||
pricing.compute_pricing(context={'qf': 2})
|
||||
compute_method(context={'qf': 2})
|
||||
assert e.value.details == {'category': 'qf'}
|
||||
|
||||
# conditions set, but no match
|
||||
|
@ -541,16 +546,19 @@ def test_compute_pricing():
|
|||
criteria2.condition = 'False'
|
||||
criteria2.save()
|
||||
with pytest.raises(CriteriaConditionNotFound) as e:
|
||||
pricing.compute_pricing(context={'qf': 2})
|
||||
compute_method(context={'qf': 2})
|
||||
assert e.value.details == {'category': 'qf'}
|
||||
|
||||
# but with a default criteria, there is a match, but pricing.pricing_data is not defined
|
||||
# but with a default criteria, there is a match, but pricing.(min_)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:
|
||||
pricing.compute_pricing(context={'qf': 2})
|
||||
error_class = PricingDataError
|
||||
if field == 'min_pricing':
|
||||
error_class = MinPricingDataError
|
||||
with pytest.raises(error_class) as e:
|
||||
compute_method(context={'qf': 2})
|
||||
assert e.value.details == {'criterias': {'qf': 'else-1'}}
|
||||
# with more than one default criteria, fail
|
||||
default_criteria2 = Criteria.objects.create(
|
||||
|
@ -558,55 +566,83 @@ def test_compute_pricing():
|
|||
)
|
||||
pricing.criterias.add(default_criteria2)
|
||||
with pytest.raises(MultipleDefaultCriteriaCondition) as e:
|
||||
pricing.compute_pricing(context={'qf': 2})
|
||||
compute_method(context={'qf': 2})
|
||||
assert e.value.details == {'category': 'qf'}
|
||||
Criteria.objects.filter(default=True).delete() # remove default criterias
|
||||
|
||||
# criteria found, but pricing.pricing_data is not defined
|
||||
# criteria found, but pricing.(min_)pricing_data is not defined
|
||||
criteria1.condition = 'qf < 1'
|
||||
criteria1.save()
|
||||
criteria2.condition = 'qf >= 1'
|
||||
criteria2.save()
|
||||
with pytest.raises(PricingDataError) as e:
|
||||
pricing.compute_pricing(context={'qf': 2})
|
||||
error_class = PricingDataError
|
||||
if field == 'min_pricing':
|
||||
error_class = MinPricingDataError
|
||||
with pytest.raises(error_class) as e:
|
||||
compute_method(context={'qf': 2})
|
||||
assert e.value.details == {'criterias': {'qf': 'qf-1'}}
|
||||
|
||||
# criteria not found in pricing_data
|
||||
pricing.pricing_data = {
|
||||
'qf:qf-0': 42,
|
||||
}
|
||||
# criteria not found in (min_)pricing_data
|
||||
setattr(
|
||||
pricing,
|
||||
'%s_data' % field,
|
||||
{
|
||||
'qf:qf-0': 42,
|
||||
},
|
||||
)
|
||||
pricing.save()
|
||||
with pytest.raises(PricingDataError) as e:
|
||||
pricing.compute_pricing(context={'qf': 2})
|
||||
error_class = PricingDataError
|
||||
if field == 'min_pricing':
|
||||
error_class = MinPricingDataError
|
||||
with pytest.raises(error_class) as e:
|
||||
compute_method(context={'qf': 2})
|
||||
assert e.value.details == {'criterias': {'qf': 'qf-1'}}
|
||||
|
||||
# criteria found, but value is wrong
|
||||
for value in ['foo', ['foo']]:
|
||||
pricing.pricing_data = {
|
||||
'qf:qf-0': 42,
|
||||
'qf:qf-1': value,
|
||||
}
|
||||
setattr(
|
||||
pricing,
|
||||
'%s_data' % field,
|
||||
{
|
||||
'qf:qf-0': 42,
|
||||
'qf:qf-1': value,
|
||||
},
|
||||
)
|
||||
pricing.save()
|
||||
with pytest.raises(PricingDataFormatError) as e:
|
||||
pricing.compute_pricing(context={'qf': 2})
|
||||
error_class = PricingDataFormatError
|
||||
if field == 'min_pricing':
|
||||
error_class = MinPricingDataFormatError
|
||||
with pytest.raises(error_class) as e:
|
||||
compute_method(context={'qf': 2})
|
||||
assert e.value.details == {'pricing': value, 'wanted': 'decimal'}
|
||||
for value in [[], {}]:
|
||||
pricing.pricing_data = {
|
||||
'qf:qf-0': 42,
|
||||
'qf:qf-1': value,
|
||||
}
|
||||
setattr(
|
||||
pricing,
|
||||
'%s_data' % field,
|
||||
{
|
||||
'qf:qf-0': 42,
|
||||
'qf:qf-1': value,
|
||||
},
|
||||
)
|
||||
pricing.save()
|
||||
with pytest.raises(PricingDataError) as e:
|
||||
pricing.compute_pricing(context={'qf': 2})
|
||||
error_class = PricingDataError
|
||||
if field == 'min_pricing':
|
||||
error_class = MinPricingDataError
|
||||
with pytest.raises(error_class) as e:
|
||||
compute_method(context={'qf': 2})
|
||||
assert e.value.details == {'criterias': {'qf': 'qf-1'}}
|
||||
|
||||
# correct value (decimal)
|
||||
pricing.pricing_data = {
|
||||
'qf:qf-0': 42,
|
||||
'qf:qf-1': 52,
|
||||
}
|
||||
setattr(
|
||||
pricing,
|
||||
'%s_data' % field,
|
||||
{
|
||||
'qf:qf-0': 42,
|
||||
'qf:qf-1': 52,
|
||||
},
|
||||
)
|
||||
pricing.save()
|
||||
assert pricing.compute_pricing(context={'qf': 2}) == (52, {'qf': 'qf-1'})
|
||||
assert compute_method(context={'qf': 2}) == (52, {'qf': 'qf-1'})
|
||||
|
||||
# more complexe pricing model
|
||||
category2 = CriteriaCategory.objects.create(label='Domicile', slug='domicile')
|
||||
|
@ -621,30 +657,34 @@ def test_compute_pricing():
|
|||
pricing.criterias.add(criteria2)
|
||||
|
||||
# correct definition
|
||||
pricing.pricing_data = {
|
||||
'domicile:dom-0': {
|
||||
'qf:qf-0': 3,
|
||||
'qf:qf-1': 5,
|
||||
setattr(
|
||||
pricing,
|
||||
'%s_data' % field,
|
||||
{
|
||||
'domicile:dom-0': {
|
||||
'qf:qf-0': 3,
|
||||
'qf:qf-1': 5,
|
||||
},
|
||||
'domicile:else': {
|
||||
'qf:qf-0': 7,
|
||||
'qf:qf-1': 10,
|
||||
},
|
||||
},
|
||||
'domicile:else': {
|
||||
'qf:qf-0': 7,
|
||||
'qf:qf-1': 10,
|
||||
},
|
||||
}
|
||||
)
|
||||
pricing.save()
|
||||
assert pricing.compute_pricing(context={'qf': 2, 'domicile': 'commune'}) == (
|
||||
assert compute_method(context={'qf': 2, 'domicile': 'commune'}) == (
|
||||
5,
|
||||
{'domicile': 'dom-0', 'qf': 'qf-1'},
|
||||
)
|
||||
assert pricing.compute_pricing(context={'qf': 0, 'domicile': 'commune'}) == (
|
||||
assert compute_method(context={'qf': 0, 'domicile': 'commune'}) == (
|
||||
3,
|
||||
{'domicile': 'dom-0', 'qf': 'qf-0'},
|
||||
)
|
||||
assert pricing.compute_pricing(context={'qf': 2, 'domicile': 'ext'}) == (
|
||||
assert compute_method(context={'qf': 2, 'domicile': 'ext'}) == (
|
||||
10,
|
||||
{'domicile': 'else', 'qf': 'qf-1'},
|
||||
)
|
||||
assert pricing.compute_pricing(context={'qf': 0, 'domicile': 'ext'}) == (
|
||||
assert compute_method(context={'qf': 0, 'domicile': 'ext'}) == (
|
||||
7,
|
||||
{'domicile': 'else', 'qf': 'qf-0'},
|
||||
)
|
||||
|
@ -652,19 +692,19 @@ def test_compute_pricing():
|
|||
# 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 pricing.compute_pricing(context={'qf': 2, 'domicile': 'commune'}) == (
|
||||
assert compute_method(context={'qf': 2, 'domicile': 'commune'}) == (
|
||||
5,
|
||||
{'domicile': 'dom-0', 'qf': 'qf-1'},
|
||||
)
|
||||
assert pricing.compute_pricing(context={'qf': 0, 'domicile': 'commune'}) == (
|
||||
assert compute_method(context={'qf': 0, 'domicile': 'commune'}) == (
|
||||
3,
|
||||
{'domicile': 'dom-0', 'qf': 'qf-0'},
|
||||
)
|
||||
assert pricing.compute_pricing(context={'qf': 2, 'domicile': 'ext'}) == (
|
||||
assert compute_method(context={'qf': 2, 'domicile': 'ext'}) == (
|
||||
10,
|
||||
{'domicile': 'else', 'qf': 'qf-1'},
|
||||
)
|
||||
assert pricing.compute_pricing(context={'qf': 0, 'domicile': 'ext'}) == (
|
||||
assert compute_method(context={'qf': 0, 'domicile': 'ext'}) == (
|
||||
7,
|
||||
{'domicile': 'else', 'qf': 'qf-0'},
|
||||
)
|
||||
|
@ -769,7 +809,8 @@ def test_compute_reduction_rate(mock_send, context, nocache):
|
|||
assert 'filter-bar=35&' in mock_send.call_args_list[0][0][0].url
|
||||
|
||||
|
||||
def test_apply_reduction_rate(context):
|
||||
@mock.patch('lingo.pricing.models.Pricing.compute_min_pricing')
|
||||
def test_apply_reduction_rate(mock_compute, context):
|
||||
pricing = Pricing.objects.create(
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
|
@ -786,7 +827,7 @@ def test_apply_reduction_rate(context):
|
|||
payer_external_id='parent:35',
|
||||
) == (42, {})
|
||||
|
||||
pricing.kind = 'reduction'
|
||||
pricing.kind = 'effort'
|
||||
pricing.save()
|
||||
assert pricing.apply_reduction_rate(
|
||||
pricing=42,
|
||||
|
@ -807,8 +848,7 @@ def test_apply_reduction_rate(context):
|
|||
payer_external_id='parent:35',
|
||||
) == (42, {})
|
||||
|
||||
# template with correct value
|
||||
pricing.kind = 'reduction'
|
||||
pricing.kind = 'effort'
|
||||
pricing.reduction_rate = '{{ foo }}'
|
||||
pricing.save()
|
||||
assert pricing.apply_reduction_rate(
|
||||
|
@ -817,38 +857,25 @@ def test_apply_reduction_rate(context):
|
|||
context={'foo': '50'},
|
||||
user_external_id='child:42',
|
||||
payer_external_id='parent:35',
|
||||
) == (
|
||||
21,
|
||||
{
|
||||
'computed_pricing': 42,
|
||||
'reduction_rate': 50,
|
||||
'reduced_pricing': 21,
|
||||
'min_pricing': None,
|
||||
'bounded_pricing': 21,
|
||||
},
|
||||
)
|
||||
) == (42, {})
|
||||
|
||||
# with a min value
|
||||
pricing.min_pricing = 22
|
||||
pricing.save()
|
||||
assert pricing.apply_reduction_rate(
|
||||
pricing=42,
|
||||
request=context['request'],
|
||||
context={'foo': '50'},
|
||||
user_external_id='child:42',
|
||||
payer_external_id='parent:35',
|
||||
) == (
|
||||
22,
|
||||
{
|
||||
'computed_pricing': 42,
|
||||
'reduction_rate': 50,
|
||||
'reduced_pricing': 21,
|
||||
'min_pricing': 22,
|
||||
'bounded_pricing': 22,
|
||||
},
|
||||
)
|
||||
pricing.min_pricing = 21
|
||||
# template with correct value
|
||||
mock_compute.side_effect = PricingDataError
|
||||
pricing.kind = 'reduction'
|
||||
pricing.reduction_rate = '{{ foo }}'
|
||||
pricing.save()
|
||||
with pytest.raises(PricingError):
|
||||
pricing.apply_reduction_rate(
|
||||
pricing=42,
|
||||
request=context['request'],
|
||||
context={'foo': '50'},
|
||||
user_external_id='child:42',
|
||||
payer_external_id='parent:35',
|
||||
)
|
||||
assert mock_compute.call_args_list == [mock.call(context={'foo': '50'})]
|
||||
|
||||
mock_compute.side_effect = None
|
||||
mock_compute.return_value = (21, 'criterias')
|
||||
assert pricing.apply_reduction_rate(
|
||||
pricing=42,
|
||||
request=context['request'],
|
||||
|
@ -1184,34 +1211,39 @@ def test_compute_accounting_code(mock_send, context, nocache):
|
|||
assert 'filter-bar=35&' in mock_send.call_args_list[0][0][0].url
|
||||
|
||||
|
||||
def test_format_pricing_data():
|
||||
@pytest.mark.parametrize('field', ['pricing', 'min_pricing'])
|
||||
def test_format_pricing_data(field):
|
||||
agenda = Agenda.objects.create(label='Foo bar')
|
||||
pricing = Pricing.objects.create(
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
pricing.agendas.add(agenda)
|
||||
assert pricing.format_pricing_data() == {}
|
||||
assert pricing.format_pricing_data(field=field) == {}
|
||||
|
||||
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,
|
||||
setattr(
|
||||
pricing,
|
||||
'%s_data' % field,
|
||||
{
|
||||
'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-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,
|
||||
},
|
||||
},
|
||||
},
|
||||
'cat-1:crit-1-2': {
|
||||
'cat-2:crit-2-2': {
|
||||
'cat-3:crit-3-3': 223,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
pricing.save()
|
||||
assert pricing.format_pricing_data() == {
|
||||
assert pricing.format_pricing_data(field=field) == {
|
||||
'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,
|
||||
|
@ -1219,23 +1251,23 @@ def test_format_pricing_data():
|
|||
'cat-1:crit-1-2||cat-2:crit-2-2||cat-3:crit-3-3': 223,
|
||||
}
|
||||
|
||||
pricing.pricing_data = {'foo': 42}
|
||||
setattr(pricing, '%s_data' % field, {'foo': 42})
|
||||
pricing.save()
|
||||
assert pricing.format_pricing_data() == {'foo': 42}
|
||||
assert pricing.format_pricing_data(field=field) == {'foo': 42}
|
||||
|
||||
# wrong data
|
||||
pricing.pricing_data = 'foo'
|
||||
setattr(pricing, '%s_data' % field, 'foo')
|
||||
pricing.save()
|
||||
assert pricing.format_pricing_data() == {'': 'foo'}
|
||||
pricing.pricing_data = []
|
||||
assert pricing.format_pricing_data(field=field) == {'': 'foo'}
|
||||
setattr(pricing, '%s_data' % field, [])
|
||||
pricing.save()
|
||||
assert pricing.format_pricing_data() == {}
|
||||
pricing.pricing_data = ['foo']
|
||||
assert pricing.format_pricing_data(field=field) == {}
|
||||
setattr(pricing, '%s_data' % field, ['foo'])
|
||||
pricing.save()
|
||||
assert pricing.format_pricing_data() == {'': ['foo']}
|
||||
pricing.pricing_data = {'foo': []}
|
||||
assert pricing.format_pricing_data(field=field) == {'': ['foo']}
|
||||
setattr(pricing, '%s_data' % field, {'foo': []})
|
||||
pricing.save()
|
||||
assert pricing.format_pricing_data() == {}
|
||||
assert pricing.format_pricing_data(field=field) == {}
|
||||
|
||||
|
||||
def test_get_booking_modifier_unknown_check_status():
|
||||
|
@ -1740,7 +1772,8 @@ def test_aggregate_pricing_data(modifier, pricing_amount):
|
|||
}
|
||||
|
||||
|
||||
def test_pricing_iter_pricing_matrix_3_categories():
|
||||
@pytest.mark.parametrize('field', ['pricing', 'min_pricing'])
|
||||
def test_pricing_iter_pricing_matrix_3_categories(field):
|
||||
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)
|
||||
|
@ -1761,13 +1794,14 @@ def test_pricing_iter_pricing_matrix_3_categories():
|
|||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
iter_method = getattr(pricing, 'iter_%s_matrix' % field)
|
||||
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))
|
||||
pricing.agendas.add(agenda)
|
||||
assert list(pricing.iter_pricing_matrix()) == [
|
||||
assert list(iter_method()) == [
|
||||
PricingMatrix(
|
||||
criteria=criteria11,
|
||||
rows=[
|
||||
|
@ -1845,28 +1879,32 @@ def test_pricing_iter_pricing_matrix_3_categories():
|
|||
]
|
||||
|
||||
# some data defined
|
||||
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,
|
||||
setattr(
|
||||
pricing,
|
||||
'%s_data' % field,
|
||||
{
|
||||
'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-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,
|
||||
},
|
||||
},
|
||||
},
|
||||
'cat-1:crit-1-2': {
|
||||
'cat-2:crit-2-2': {
|
||||
'cat-3:crit-3-3': 223,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
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(pricing.iter_pricing_matrix()) == [
|
||||
assert list(iter_method()) == [
|
||||
PricingMatrix(
|
||||
criteria=criteria21,
|
||||
rows=[
|
||||
|
@ -1969,7 +2007,8 @@ def test_pricing_iter_pricing_matrix_3_categories():
|
|||
]
|
||||
|
||||
|
||||
def test_pricing_iter_pricing_matrix_2_categories():
|
||||
@pytest.mark.parametrize('field', ['pricing', 'min_pricing'])
|
||||
def test_pricing_iter_pricing_matrix_2_categories(field):
|
||||
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)
|
||||
|
@ -1986,12 +2025,13 @@ def test_pricing_iter_pricing_matrix_2_categories():
|
|||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
iter_method = getattr(pricing, 'iter_%s_matrix' % field)
|
||||
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))
|
||||
pricing.agendas.add(agenda)
|
||||
|
||||
assert list(pricing.iter_pricing_matrix()) == [
|
||||
assert list(iter_method()) == [
|
||||
PricingMatrix(
|
||||
criteria=None,
|
||||
rows=[
|
||||
|
@ -2032,18 +2072,22 @@ def test_pricing_iter_pricing_matrix_2_categories():
|
|||
]
|
||||
|
||||
# some data defined
|
||||
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,
|
||||
setattr(
|
||||
pricing,
|
||||
'%s_data' % field,
|
||||
{
|
||||
'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,
|
||||
},
|
||||
},
|
||||
'cat-2:crit-2-3': {
|
||||
'cat-3:crit-3-2': 32,
|
||||
},
|
||||
}
|
||||
)
|
||||
pricing.save()
|
||||
assert list(pricing.iter_pricing_matrix()) == [
|
||||
assert list(iter_method()) == [
|
||||
PricingMatrix(
|
||||
criteria=None,
|
||||
rows=[
|
||||
|
@ -2084,7 +2128,8 @@ def test_pricing_iter_pricing_matrix_2_categories():
|
|||
]
|
||||
|
||||
|
||||
def test_pricing_iter_pricing_matrix_1_category():
|
||||
@pytest.mark.parametrize('field', ['pricing', 'min_pricing'])
|
||||
def test_pricing_iter_pricing_matrix_1_category(field):
|
||||
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)
|
||||
|
@ -2097,11 +2142,12 @@ def test_pricing_iter_pricing_matrix_1_category():
|
|||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
iter_method = getattr(pricing, 'iter_%s_matrix' % field)
|
||||
pricing.categories.add(category3, through_defaults={'order': 3})
|
||||
pricing.criterias.set(Criteria.objects.exclude(pk=not_used.pk))
|
||||
pricing.agendas.add(agenda)
|
||||
|
||||
assert list(pricing.iter_pricing_matrix()) == [
|
||||
assert list(iter_method()) == [
|
||||
PricingMatrix(
|
||||
criteria=None,
|
||||
rows=[
|
||||
|
@ -2134,13 +2180,17 @@ def test_pricing_iter_pricing_matrix_1_category():
|
|||
]
|
||||
|
||||
# some data defined
|
||||
pricing.pricing_data = {
|
||||
'cat-3:crit-3-1': 1,
|
||||
'cat-3:crit-3-3': 'not-a-decimal',
|
||||
'cat-3:crit-3-4': 4,
|
||||
}
|
||||
setattr(
|
||||
pricing,
|
||||
'%s_data' % field,
|
||||
{
|
||||
'cat-3:crit-3-1': 1,
|
||||
'cat-3:crit-3-3': 'not-a-decimal',
|
||||
'cat-3:crit-3-4': 4,
|
||||
},
|
||||
)
|
||||
pricing.save()
|
||||
assert list(pricing.iter_pricing_matrix()) == [
|
||||
assert list(iter_method()) == [
|
||||
PricingMatrix(
|
||||
criteria=None,
|
||||
rows=[
|
||||
|
@ -2173,12 +2223,14 @@ def test_pricing_iter_pricing_matrix_1_category():
|
|||
]
|
||||
|
||||
|
||||
def test_pricing_iter_pricing_matrix_empty():
|
||||
@pytest.mark.parametrize('field', ['pricing', 'min_pricing'])
|
||||
def test_pricing_iter_pricing_matrix_empty(field):
|
||||
agenda = Agenda.objects.create(label='Foo bar')
|
||||
pricing = Pricing.objects.create(
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
iter_method = getattr(pricing, 'iter_%s_matrix' % field)
|
||||
pricing.agendas.add(agenda)
|
||||
|
||||
assert list(pricing.iter_pricing_matrix()) == []
|
||||
assert list(iter_method()) == []
|
||||
|
|
Loading…
Reference in New Issue