pricing: variable configuration (#64903)
This commit is contained in:
parent
4976df546a
commit
1cd72eeebc
|
@ -49,6 +49,20 @@ $(function() {
|
|||
})
|
||||
}
|
||||
|
||||
$(document).on('click', '#add-pricing-variable-form', function() {
|
||||
if (typeof property_forms === "undefined") {var property_forms = $('.pricing-variable-form');}
|
||||
if (typeof total_forms === "undefined") {var total_form = $('#id_form-TOTAL_FORMS');}
|
||||
if (typeof form_num === "undefined") {var form_num = property_forms.length - 1;}
|
||||
var new_form = $(property_forms[0]).clone();
|
||||
var form_regex = RegExp(`form-(\\d){1}-`,'g');
|
||||
form_num++;
|
||||
new_form.html(new_form.html().replace(form_regex, `form-${form_num}-`));
|
||||
new_form.appendTo('#pricing-variable-forms tbody');
|
||||
$('#id_form-' + form_num + '-key').val('');
|
||||
$('#id_form-' + form_num + '-value').val('');
|
||||
total_form.val(form_num + 1);
|
||||
})
|
||||
|
||||
$('.sortable').sortable({
|
||||
handle: '.handle',
|
||||
items: '.sortable-item',
|
||||
|
|
|
@ -51,6 +51,16 @@ class CriteriaForm(NewCriteriaForm):
|
|||
return slug
|
||||
|
||||
|
||||
class PricingVariableForm(forms.Form):
|
||||
key = forms.CharField(label=_('Variable name'), required=False)
|
||||
value = forms.CharField(
|
||||
label=_('Value template'), widget=forms.TextInput(attrs={'size': 60}), required=False
|
||||
)
|
||||
|
||||
|
||||
PricingVariableFormSet = forms.formset_factory(PricingVariableForm)
|
||||
|
||||
|
||||
class PricingCriteriaCategoryAddForm(forms.Form):
|
||||
category = forms.ModelChoiceField(
|
||||
label=_('Criteria category to add'), queryset=CriteriaCategory.objects.none(), required=True
|
||||
|
|
|
@ -202,6 +202,9 @@ class Pricing(models.Model):
|
|||
result[key] = template.render(context)
|
||||
return result
|
||||
|
||||
def get_extra_variables_keys(self):
|
||||
return sorted((self.extra_variables or {}).keys())
|
||||
|
||||
|
||||
class PricingCriteriaCategory(models.Model):
|
||||
pricing = models.ForeignKey(Pricing, on_delete=models.CASCADE)
|
||||
|
|
|
@ -21,6 +21,20 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="section">
|
||||
<h3>{% trans "Variables" %}</h3>
|
||||
|
||||
<div>
|
||||
{% if object.extra_variables %}
|
||||
<p>
|
||||
<label>{% trans 'Extra variables:' %}</label>
|
||||
{% for key in object.get_extra_variables_keys %}<i>{{ key }}</i>{% if not forloop.last %}, {% endif %}{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
<a class="pk-button" rel="popup" href="{% url 'chrono-manager-pricing-variable-edit' pk=object.pk %}">{% trans 'Define variables' %}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>{% trans "Criterias" %}</h3>
|
||||
{% with criterias=object.criterias.all categories=object.categories.all %}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
{% extends "chrono/pricing/manager_pricing_detail.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a href="{% url 'chrono-manager-pricing-variable-edit' object.pk %}">{% trans "Variable definition" %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans "Variable definition" %}</h2>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.management_form }}
|
||||
<table id="pricing-variable-forms">
|
||||
<thead>
|
||||
<tr>
|
||||
{% for field in form.0 %}
|
||||
<th class="column-{{ field.name }}{% if field.required %} required{% endif %}">{{ field.label }}</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for sub_form in form %}
|
||||
<tr class='pricing-variable-form'>
|
||||
{% for field in sub_form %}
|
||||
<td class="field-{{ field.name }}">
|
||||
{{ field.errors.as_ul }}
|
||||
{{ field }}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<button id="add-pricing-variable-form" type="button">{% trans "Add another" %}</button>
|
||||
<div class="buttons">
|
||||
<button class="submit-button">{% trans "Save" %}</button>
|
||||
<a class="cancel" href="{% url 'chrono-manager-pricing-detail' object.pk %}">{% trans 'Cancel' %}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -40,6 +40,11 @@ urlpatterns = [
|
|||
views.pricing_delete,
|
||||
name='chrono-manager-pricing-delete',
|
||||
),
|
||||
url(
|
||||
r'^(?P<pk>\d+)/variable/$',
|
||||
views.pricing_variable_edit,
|
||||
name='chrono-manager-pricing-variable-edit',
|
||||
),
|
||||
url(
|
||||
r'^(?P<pk>\d+)/category/add/$',
|
||||
views.pricing_criteria_category_add,
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
import datetime
|
||||
import json
|
||||
from operator import itemgetter
|
||||
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db.models import Prefetch
|
||||
|
@ -29,6 +30,7 @@ from chrono.pricing.forms import (
|
|||
NewCriteriaForm,
|
||||
PricingCriteriaCategoryAddForm,
|
||||
PricingCriteriaCategoryEditForm,
|
||||
PricingVariableFormSet,
|
||||
)
|
||||
from chrono.pricing.models import Criteria, CriteriaCategory, Pricing, PricingCriteriaCategory
|
||||
|
||||
|
@ -136,6 +138,43 @@ class PricingDeleteView(DeleteView):
|
|||
pricing_delete = PricingDeleteView.as_view()
|
||||
|
||||
|
||||
class PricingVariableEdit(FormView):
|
||||
template_name = 'chrono/pricing/manager_pricing_variable_form.html'
|
||||
model = Pricing
|
||||
form_class = PricingVariableFormSet
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.object = get_object_or_404(Pricing, pk=kwargs['pk'])
|
||||
if not request.user.is_staff:
|
||||
raise PermissionDenied()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs['object'] = self.object
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
def get_initial(self):
|
||||
return sorted(
|
||||
({'key': k, 'value': v} for k, v in self.object.extra_variables.items()),
|
||||
key=itemgetter('key'),
|
||||
)
|
||||
|
||||
def form_valid(self, form):
|
||||
self.object.extra_variables = {}
|
||||
for sub_data in form.cleaned_data:
|
||||
if not sub_data.get('key'):
|
||||
continue
|
||||
self.object.extra_variables[sub_data['key']] = sub_data['value']
|
||||
self.object.save()
|
||||
return HttpResponseRedirect(self.get_success_url())
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('chrono-manager-pricing-detail', args=[self.object.pk])
|
||||
|
||||
|
||||
pricing_variable_edit = PricingVariableEdit.as_view()
|
||||
|
||||
|
||||
class PricingCriteriaCategoryAddView(FormView):
|
||||
template_name = 'chrono/pricing/manager_pricing_criteria_category_form.html'
|
||||
model = Pricing
|
||||
|
|
|
@ -111,6 +111,65 @@ def test_delete_pricing_as_manager(app, manager_user):
|
|||
app.get('/manage/pricing/%s/delete/' % pricing.pk, status=403)
|
||||
|
||||
|
||||
def test_pricing_edit_extra_variables(app, admin_user):
|
||||
pricing = Pricing.objects.create(label='Model')
|
||||
assert pricing.extra_variables == {}
|
||||
|
||||
app = login(app)
|
||||
resp = app.get('/manage/pricing/%s/' % pricing.id)
|
||||
assert '<label>Extra variables:</label>' not in resp.text
|
||||
resp = resp.click(href='/manage/pricing/%s/variable/' % pricing.id)
|
||||
resp.form['form-0-key'] = 'foo'
|
||||
resp.form['form-0-value'] = 'bar'
|
||||
resp = resp.form.submit().follow()
|
||||
pricing.refresh_from_db()
|
||||
assert pricing.extra_variables == {'foo': 'bar'}
|
||||
assert '<label>Extra variables:</label>' in resp.text
|
||||
assert '<i>foo</i>' in resp
|
||||
|
||||
resp = resp.click(href='/manage/pricing/%s/variable/' % pricing.id)
|
||||
assert resp.form['form-TOTAL_FORMS'].value == '2'
|
||||
assert resp.form['form-0-key'].value == 'foo'
|
||||
assert resp.form['form-0-value'].value == 'bar'
|
||||
assert resp.form['form-1-key'].value == ''
|
||||
assert resp.form['form-1-value'].value == ''
|
||||
resp.form['form-0-value'] = 'bar-bis'
|
||||
resp.form['form-1-key'] = 'blah'
|
||||
resp.form['form-1-value'] = 'baz'
|
||||
resp = resp.form.submit().follow()
|
||||
pricing.refresh_from_db()
|
||||
assert pricing.extra_variables == {
|
||||
'foo': 'bar-bis',
|
||||
'blah': 'baz',
|
||||
}
|
||||
assert '<i>blah</i>, <i>foo</i>' in resp
|
||||
|
||||
resp = resp.click(href='/manage/pricing/%s/variable/' % pricing.id)
|
||||
assert resp.form['form-TOTAL_FORMS'].value == '3'
|
||||
assert resp.form['form-0-key'].value == 'blah'
|
||||
assert resp.form['form-0-value'].value == 'baz'
|
||||
assert resp.form['form-1-key'].value == 'foo'
|
||||
assert resp.form['form-1-value'].value == 'bar-bis'
|
||||
assert resp.form['form-2-key'].value == ''
|
||||
assert resp.form['form-2-value'].value == ''
|
||||
resp.form['form-1-key'] = 'foo'
|
||||
resp.form['form-1-value'] = 'bar'
|
||||
resp.form['form-0-key'] = ''
|
||||
resp = resp.form.submit().follow()
|
||||
pricing.refresh_from_db()
|
||||
assert pricing.extra_variables == {
|
||||
'foo': 'bar',
|
||||
}
|
||||
assert '<i>foo</i>' in resp
|
||||
|
||||
|
||||
def test_pricing_edit_extra_variables_as_manager(app, manager_user):
|
||||
pricing = Pricing.objects.create(label='Model')
|
||||
|
||||
app = login(app, username='manager', password='manager')
|
||||
app.get('/manage/pricing/%s/variable/' % pricing.pk, status=403)
|
||||
|
||||
|
||||
def test_pricing_add_category(app, admin_user):
|
||||
pricing = Pricing.objects.create(label='Model')
|
||||
category1 = CriteriaCategory.objects.create(label='Cat 1')
|
||||
|
|
Loading…
Reference in New Issue