pricing: configuration of criterias and categories (#64746)
This commit is contained in:
parent
81138cf951
commit
a5c5f63c83
|
@ -12,6 +12,9 @@
|
|||
<li><a rel="popup" href="{% url 'chrono-manager-agendas-export' %}" data-autoclose-dialog="true">{% trans 'Export' %}</a></li>
|
||||
<li><a href="{% url 'chrono-manager-events-type-list' %}">{% trans 'Events types' %}</a></li>
|
||||
<li><a href="{% url 'chrono-manager-check-type-list' %}">{% trans 'Check types' %}</a></li>
|
||||
{% if pricing_enabled %}
|
||||
<li><a href="{% url 'chrono-manager-pricing-criteria-list' %}">{% trans 'Pricing' context 'pricing' %}</a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if has_access_to_unavailability_calendars %}
|
||||
<li><a href="{% url 'chrono-manager-unavailability-calendar-list' %}">{% trans 'Unavailability calendars' %}</a></li>
|
||||
|
|
|
@ -26,6 +26,7 @@ from operator import attrgetter
|
|||
|
||||
import requests
|
||||
from dateutil.relativedelta import MO, relativedelta
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db import IntegrityError, transaction
|
||||
|
@ -163,6 +164,7 @@ class HomepageView(ListView):
|
|||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['has_access_to_unavailability_calendars'] = self.has_access_to_unavailability_calendars()
|
||||
context['pricing_enabled'] = settings.CHRONO_ENABLE_PRICING
|
||||
return context
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
# chrono - agendas system
|
||||
# Copyright (C) 2022 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django import forms
|
||||
from django.forms import ValidationError
|
||||
from django.template import Template, TemplateSyntaxError
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from chrono.pricing.models import Criteria
|
||||
|
||||
|
||||
class NewCriteriaForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Criteria
|
||||
fields = ['label', 'condition']
|
||||
|
||||
def clean_condition(self):
|
||||
condition = self.cleaned_data['condition']
|
||||
try:
|
||||
Template('{%% if %s %%}OK{%% endif %%}' % condition)
|
||||
except TemplateSyntaxError:
|
||||
raise ValidationError(_('Invalid syntax.'))
|
||||
|
||||
return condition
|
||||
|
||||
|
||||
class CriteriaForm(NewCriteriaForm):
|
||||
class Meta:
|
||||
model = Criteria
|
||||
fields = ['label', 'slug', 'condition']
|
||||
|
||||
def clean_slug(self):
|
||||
slug = self.cleaned_data['slug']
|
||||
|
||||
if self.instance.category.criterias.filter(slug=slug).exclude(pk=self.instance.pk).exists():
|
||||
raise ValidationError(_('Another criteria exists with the same identifier.'))
|
||||
|
||||
return slug
|
|
@ -0,0 +1,31 @@
|
|||
{% extends "chrono/pricing/manager_criteria_list.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
{% if object.pk %}
|
||||
<a href="{% url 'chrono-manager-pricing-criteria-category-edit' object.pk %}">{{ object }}</a>
|
||||
{% else %}
|
||||
<a href="{% url 'chrono-manager-pricing-criteria-category-add' %}">{% trans "New criteria category" %}</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
{% if object.pk %}
|
||||
<h2>{% trans "Edit criteria category" %}</h2>
|
||||
{% else %}
|
||||
<h2>{% trans "New criteria category" %}</h2>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<div class="buttons">
|
||||
<button class="submit-button">{% trans "Save" %}</button>
|
||||
<a class="cancel" href="{% url 'chrono-manager-pricing-criteria-list' %}">{% trans 'Cancel' %}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -0,0 +1,31 @@
|
|||
{% extends "chrono/pricing/manager_criteria_list.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
{% if form.instance.pk %}
|
||||
<a href="{% url 'chrono-manager-pricing-criteria-edit' form.instance.category_id form.instance.pk %}">{{ form.instance }}</a>
|
||||
{% else %}
|
||||
<a href="{% url 'chrono-manager-pricing-criteria-add' form.instance.category_id %}">{% trans "New criteria" %}</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
{% if form.instance.pk %}
|
||||
<h2>{{ form.instance.category }} - {% trans "Edit criteria" %}</h2>
|
||||
{% else %}
|
||||
<h2>{{ form.instance.category }} - {% trans "New criteria" %}</h2>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<div class="buttons">
|
||||
<button class="submit-button">{% trans "Save" %}</button>
|
||||
<a class="cancel" href="{% url 'chrono-manager-pricing-criteria-list' %}">{% trans 'Cancel' %}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -0,0 +1,50 @@
|
|||
{% extends "chrono/manager_base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a href="{% url 'chrono-manager-pricing-criteria-list' %}">{% trans "Criterias" %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans 'Criterias' %}</h2>
|
||||
<span class="actions">
|
||||
<a rel="popup" href="{% url 'chrono-manager-pricing-criteria-category-add' %}">{% trans 'New criteria category' %}</a>
|
||||
</span>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div class="pk-information">
|
||||
<p>{% trans "Define here pricing criterias used in events agendas." %}</p>
|
||||
</div>
|
||||
{% for object in object_list %}
|
||||
<div class="section criteria-category">
|
||||
<h3>
|
||||
<a rel="popup" href="{% url 'chrono-manager-pricing-criteria-category-edit' object.pk %}">{{ object }} [{{ object.slug }}]</a>
|
||||
<span>
|
||||
<a class="button" href="{# url 'chrono-manager-pricing-criteria-category-export' object.pk #}">{% trans "Export"%}</a>
|
||||
<a class="button" rel="popup" href="{% url 'chrono-manager-pricing-criteria-category-delete' object.pk %}">{% trans "Delete"%}</a>
|
||||
</span>
|
||||
</h3>
|
||||
<div>
|
||||
<ul class="objects-list single-links">
|
||||
{% for criteria in object.criterias.all %}
|
||||
<li>
|
||||
<a rel="popup" href="{% url 'chrono-manager-pricing-criteria-edit' object.pk criteria.pk %}">{{ criteria }}</a>
|
||||
<a class="delete" rel="popup" href="{% url 'chrono-manager-pricing-criteria-delete' object.pk criteria.pk %}">{% trans "delete"%}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
<li><a class="add" rel="popup" href="{% url 'chrono-manager-pricing-criteria-add' object.pk %}">{% trans "Add a criteria" %}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="big-msg-info">
|
||||
{% blocktrans %}
|
||||
This site doesn't have any pricing criteria category yet. Click on the "New category" button in the top
|
||||
right of the page to add a first one.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
|
@ -0,0 +1,53 @@
|
|||
# chrono - agendas system
|
||||
# Copyright (C) 2022 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^criterias/$', views.criteria_list, name='chrono-manager-pricing-criteria-list'),
|
||||
url(
|
||||
r'^criteria/category/add/$',
|
||||
views.criteria_category_add,
|
||||
name='chrono-manager-pricing-criteria-category-add',
|
||||
),
|
||||
url(
|
||||
r'^criteria/category/(?P<pk>\d+)/edit/$',
|
||||
views.criteria_category_edit,
|
||||
name='chrono-manager-pricing-criteria-category-edit',
|
||||
),
|
||||
url(
|
||||
r'^criteria/category/(?P<pk>\d+)/delete/$',
|
||||
views.criteria_category_delete,
|
||||
name='chrono-manager-pricing-criteria-category-delete',
|
||||
),
|
||||
url(
|
||||
r'^criteria/category/(?P<category_pk>\d+)/add/$',
|
||||
views.criteria_add,
|
||||
name='chrono-manager-pricing-criteria-add',
|
||||
),
|
||||
url(
|
||||
r'^criteria/category/(?P<category_pk>\d+)/(?P<pk>\d+)/edit/$',
|
||||
views.criteria_edit,
|
||||
name='chrono-manager-pricing-criteria-edit',
|
||||
),
|
||||
url(
|
||||
r'^criteria/category/(?P<category_pk>\d+)/(?P<pk>\d+)/delete/$',
|
||||
views.criteria_delete,
|
||||
name='chrono-manager-pricing-criteria-delete',
|
||||
),
|
||||
]
|
|
@ -0,0 +1,155 @@
|
|||
# chrono - agendas system
|
||||
# Copyright (C) 2022 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.urls import reverse
|
||||
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
|
||||
|
||||
from chrono.pricing.forms import CriteriaForm, NewCriteriaForm
|
||||
from chrono.pricing.models import Criteria, CriteriaCategory
|
||||
|
||||
|
||||
class CriteriaListView(ListView):
|
||||
template_name = 'chrono/pricing/manager_criteria_list.html'
|
||||
model = CriteriaCategory
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not request.user.is_staff:
|
||||
raise PermissionDenied()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
return CriteriaCategory.objects.prefetch_related('criterias')
|
||||
|
||||
|
||||
criteria_list = CriteriaListView.as_view()
|
||||
|
||||
|
||||
class CriteriaCategoryAddView(CreateView):
|
||||
template_name = 'chrono/pricing/manager_criteria_category_form.html'
|
||||
model = CriteriaCategory
|
||||
fields = ['label']
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not request.user.is_staff:
|
||||
raise PermissionDenied()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('chrono-manager-pricing-criteria-list')
|
||||
|
||||
|
||||
criteria_category_add = CriteriaCategoryAddView.as_view()
|
||||
|
||||
|
||||
class CriteriaCategoryEditView(UpdateView):
|
||||
template_name = 'chrono/pricing/manager_criteria_category_form.html'
|
||||
model = CriteriaCategory
|
||||
fields = ['label', 'slug']
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not request.user.is_staff:
|
||||
raise PermissionDenied()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('chrono-manager-pricing-criteria-list')
|
||||
|
||||
|
||||
criteria_category_edit = CriteriaCategoryEditView.as_view()
|
||||
|
||||
|
||||
class CriteriaCategoryDeleteView(DeleteView):
|
||||
template_name = 'chrono/manager_confirm_delete.html'
|
||||
model = CriteriaCategory
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not request.user.is_staff:
|
||||
raise PermissionDenied()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('chrono-manager-pricing-criteria-list')
|
||||
|
||||
|
||||
criteria_category_delete = CriteriaCategoryDeleteView.as_view()
|
||||
|
||||
|
||||
class CriteriaAddView(CreateView):
|
||||
template_name = 'chrono/pricing/manager_criteria_form.html'
|
||||
model = Criteria
|
||||
form_class = NewCriteriaForm
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.category_pk = kwargs.pop('category_pk')
|
||||
if not request.user.is_staff:
|
||||
raise PermissionDenied()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
if not kwargs.get('instance'):
|
||||
kwargs['instance'] = self.model()
|
||||
kwargs['instance'].category_id = self.category_pk
|
||||
return kwargs
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('chrono-manager-pricing-criteria-list')
|
||||
|
||||
|
||||
criteria_add = CriteriaAddView.as_view()
|
||||
|
||||
|
||||
class CriteriaEditView(UpdateView):
|
||||
template_name = 'chrono/pricing/manager_criteria_form.html'
|
||||
model = Criteria
|
||||
form_class = CriteriaForm
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.category_pk = kwargs.pop('category_pk')
|
||||
if not request.user.is_staff:
|
||||
raise PermissionDenied()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
return Criteria.objects.filter(category=self.category_pk)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('chrono-manager-pricing-criteria-list')
|
||||
|
||||
|
||||
criteria_edit = CriteriaEditView.as_view()
|
||||
|
||||
|
||||
class CriteriaDeleteView(DeleteView):
|
||||
template_name = 'chrono/manager_confirm_delete.html'
|
||||
model = Criteria
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.category_pk = kwargs.pop('category_pk')
|
||||
if not request.user.is_staff:
|
||||
raise PermissionDenied()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
return Criteria.objects.filter(category=self.category_pk)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('chrono-manager-pricing-criteria-list')
|
||||
|
||||
|
||||
criteria_delete = CriteriaDeleteView.as_view()
|
|
@ -22,12 +22,14 @@ from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
|||
|
||||
from .api.urls import urlpatterns as chrono_api_urls
|
||||
from .manager.urls import urlpatterns as chrono_manager_urls
|
||||
from .pricing.urls import urlpatterns as chrono_pricing_urls
|
||||
from .urls_utils import decorated_includes
|
||||
from .views import LoginView, LogoutView, homepage
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', homepage, name='home'),
|
||||
url(r'^manage/', decorated_includes(login_required, include(chrono_manager_urls))),
|
||||
url(r'^manage/pricing/', decorated_includes(login_required, include(chrono_pricing_urls))),
|
||||
url(r'^api/', include(chrono_api_urls)),
|
||||
url(r'^logout/$', LogoutView.as_view(), name='auth_logout'),
|
||||
url(r'^login/$', LoginView.as_view(), name='auth_login'),
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import pytest
|
||||
from django.contrib.auth.models import Group, User
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def simple_user():
|
||||
try:
|
||||
user = User.objects.get(username='user')
|
||||
except User.DoesNotExist:
|
||||
user = User.objects.create_user('user', password='user')
|
||||
return user
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def managers_group():
|
||||
group, _ = Group.objects.get_or_create(name='Managers')
|
||||
return group
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def manager_user(managers_group):
|
||||
try:
|
||||
user = User.objects.get(username='manager')
|
||||
except User.DoesNotExist:
|
||||
user = User.objects.create_user('manager', password='manager')
|
||||
user.groups.set([managers_group])
|
||||
return user
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def admin_user():
|
||||
try:
|
||||
user = User.objects.get(username='admin')
|
||||
except User.DoesNotExist:
|
||||
user = User.objects.create_superuser('admin', email=None, password='admin')
|
||||
return user
|
|
@ -0,0 +1,190 @@
|
|||
import pytest
|
||||
|
||||
from chrono.agendas.models import Agenda
|
||||
from chrono.pricing.models import Criteria, CriteriaCategory
|
||||
from tests.utils import login
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def agenda_with_restrictions(manager_user):
|
||||
agenda = Agenda(label='Foo Bar')
|
||||
agenda.view_role = manager_user.groups.all()[0]
|
||||
agenda.save()
|
||||
return agenda
|
||||
|
||||
|
||||
def test_list_criterias_as_manager(app, manager_user, agenda_with_restrictions):
|
||||
app = login(app, username='manager', password='manager')
|
||||
app.get('/manage/pricing/criterias/', status=403)
|
||||
|
||||
resp = app.get('/manage/')
|
||||
assert 'Pricing' not in resp.text
|
||||
|
||||
|
||||
def test_add_category(settings, app, admin_user):
|
||||
app = login(app)
|
||||
resp = app.get('/manage/')
|
||||
resp = resp.click('Pricing')
|
||||
resp = resp.click('New criteria category')
|
||||
resp.form['label'] = 'QF'
|
||||
resp = resp.form.submit()
|
||||
category = CriteriaCategory.objects.latest('pk')
|
||||
assert resp.location.endswith('/manage/pricing/criterias/')
|
||||
assert category.label == 'QF'
|
||||
assert category.slug == 'qf'
|
||||
|
||||
settings.CHRONO_ENABLE_PRICING = False
|
||||
resp = app.get('/manage/')
|
||||
assert 'Pricing' not in resp.text
|
||||
|
||||
|
||||
def test_add_category_as_manager(app, manager_user):
|
||||
app = login(app, username='manager', password='manager')
|
||||
app.get('/manage/pricing/criteria/category/add/', status=403)
|
||||
|
||||
|
||||
def test_edit_category(app, admin_user):
|
||||
category = CriteriaCategory.objects.create(label='QF')
|
||||
category2 = CriteriaCategory.objects.create(label='Domicile')
|
||||
|
||||
app = login(app)
|
||||
resp = app.get('/manage/pricing/criterias/')
|
||||
resp = resp.click(href='/manage/pricing/criteria/category/%s/edit/' % category.pk)
|
||||
resp.form['label'] = 'QF Foo'
|
||||
resp.form['slug'] = category2.slug
|
||||
resp = resp.form.submit()
|
||||
assert resp.context['form'].errors['slug'] == ['Criteria category with this Identifier already exists.']
|
||||
|
||||
resp.form['slug'] = 'baz2'
|
||||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/pricing/criterias/')
|
||||
category.refresh_from_db()
|
||||
assert category.label == 'QF Foo'
|
||||
assert category.slug == 'baz2'
|
||||
|
||||
|
||||
def test_edit_category_as_manager(app, manager_user):
|
||||
category = CriteriaCategory.objects.create(label='Foo bar')
|
||||
|
||||
app = login(app, username='manager', password='manager')
|
||||
app.get('/manage/pricing/criteria/category/%s/edit/' % category.pk, status=403)
|
||||
|
||||
|
||||
def test_delete_category(app, admin_user):
|
||||
category = CriteriaCategory.objects.create(label='QF')
|
||||
Criteria.objects.create(label='QF 1', category=category)
|
||||
|
||||
app = login(app)
|
||||
resp = app.get('/manage/pricing/criterias/')
|
||||
resp = resp.click(href='/manage/pricing/criteria/category/%s/delete/' % category.pk)
|
||||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/pricing/criterias/')
|
||||
assert CriteriaCategory.objects.exists() is False
|
||||
assert Criteria.objects.exists() is False
|
||||
|
||||
|
||||
def test_delete_category_as_manager(app, manager_user):
|
||||
category = CriteriaCategory.objects.create(label='Foo bar')
|
||||
|
||||
app = login(app, username='manager', password='manager')
|
||||
app.get('/manage/pricing/criteria/category/%s/delete/' % category.pk, status=403)
|
||||
|
||||
|
||||
def test_add_criteria(app, admin_user):
|
||||
category = CriteriaCategory.objects.create(label='QF')
|
||||
|
||||
app = login(app)
|
||||
resp = app.get('/manage/')
|
||||
resp = resp.click('Pricing')
|
||||
resp = resp.click('Add a criteria')
|
||||
resp.form['label'] = 'QF < 1'
|
||||
resp.form['condition'] = 'qf < 1 #'
|
||||
assert 'slug' not in resp.context['form'].fields
|
||||
resp = resp.form.submit()
|
||||
assert resp.context['form'].errors['condition'] == ['Invalid syntax.']
|
||||
resp.form['condition'] = 'qf < 1'
|
||||
resp = resp.form.submit()
|
||||
criteria = Criteria.objects.latest('pk')
|
||||
assert resp.location.endswith('/manage/pricing/criterias/')
|
||||
assert criteria.label == 'QF < 1'
|
||||
assert criteria.category == category
|
||||
assert criteria.slug == 'qf-1'
|
||||
assert criteria.condition == 'qf < 1'
|
||||
assert criteria.order == 1
|
||||
|
||||
resp = app.get('/manage/pricing/criteria/category/%s/add/' % category.pk)
|
||||
resp.form['label'] = 'QF < 1'
|
||||
resp.form['condition'] = 'qf < 1'
|
||||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/pricing/criterias/')
|
||||
criteria = Criteria.objects.latest('pk')
|
||||
assert criteria.label == 'QF < 1'
|
||||
assert criteria.category == category
|
||||
assert criteria.slug == 'qf-1-1'
|
||||
assert criteria.condition == 'qf < 1'
|
||||
assert criteria.order == 2
|
||||
|
||||
|
||||
def test_add_criteria_as_manager(app, manager_user):
|
||||
category = CriteriaCategory.objects.create(label='Foo bar')
|
||||
|
||||
app = login(app, username='manager', password='manager')
|
||||
app.get('/manage/pricing/criteria/category/%s/add/' % category.pk, status=403)
|
||||
|
||||
|
||||
def test_edit_criteria(app, admin_user):
|
||||
category = CriteriaCategory.objects.create(label='QF')
|
||||
criteria = Criteria.objects.create(label='QF 1', category=category)
|
||||
criteria2 = Criteria.objects.create(label='QF 2', category=category)
|
||||
category2 = CriteriaCategory.objects.create(label='Foo')
|
||||
criteria3 = Criteria.objects.create(label='foo-bar', category=category2)
|
||||
|
||||
app = login(app)
|
||||
resp = app.get('/manage/pricing/criterias/')
|
||||
resp = resp.click(href='/manage/pricing/criteria/category/%s/%s/edit/' % (category.pk, criteria.pk))
|
||||
resp.form['label'] = 'QF 1 bis'
|
||||
resp.form['slug'] = criteria2.slug
|
||||
resp.form['condition'] = 'qf <= 1 #'
|
||||
resp = resp.form.submit()
|
||||
assert resp.context['form'].errors['slug'] == ['Another criteria exists with the same identifier.']
|
||||
assert resp.context['form'].errors['condition'] == ['Invalid syntax.']
|
||||
|
||||
resp.form['condition'] = 'qf <= 1'
|
||||
resp.form['slug'] = criteria3.slug
|
||||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/pricing/criterias/')
|
||||
criteria.refresh_from_db()
|
||||
assert criteria.label == 'QF 1 bis'
|
||||
assert criteria.slug == 'foo-bar'
|
||||
assert criteria.condition == 'qf <= 1'
|
||||
|
||||
|
||||
def test_edit_criteria_as_manager(app, manager_user):
|
||||
category = CriteriaCategory.objects.create(label='QF')
|
||||
criteria = Criteria.objects.create(label='QF 1', category=category)
|
||||
|
||||
app = login(app, username='manager', password='manager')
|
||||
app.get('/manage/pricing/criteria/category/%s/%s/edit/' % (category.pk, criteria.pk), status=403)
|
||||
|
||||
|
||||
def test_delete_criteria(app, admin_user):
|
||||
category = CriteriaCategory.objects.create(label='QF')
|
||||
criteria = Criteria.objects.create(label='QF 1', category=category)
|
||||
|
||||
app = login(app)
|
||||
resp = app.get('/manage/pricing/criterias/')
|
||||
resp = resp.click(href='/manage/pricing/criteria/category/%s/%s/delete/' % (category.pk, criteria.pk))
|
||||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/pricing/criterias/')
|
||||
assert CriteriaCategory.objects.exists() is True
|
||||
assert Criteria.objects.exists() is False
|
||||
|
||||
|
||||
def test_delete_criteria_as_manager(app, manager_user):
|
||||
category = CriteriaCategory.objects.create(label='QF')
|
||||
criteria = Criteria.objects.create(label='QF 1', category=category)
|
||||
|
||||
app = login(app, username='manager', password='manager')
|
||||
app.get('/manage/pricing/criteria/category/%s/%s/delete/' % (category.pk, criteria.pk), status=403)
|
Loading…
Reference in New Issue