This commit is contained in:
parent
4a81e4207c
commit
26200949cc
|
@ -33,6 +33,7 @@ Depends: python3-django-mellon,
|
|||
python3-hobo,
|
||||
python3-lingo (= ${binary:Version}),
|
||||
python3-psycopg2,
|
||||
python3-sorl-thumbnail,
|
||||
python3-uwsgidecorators,
|
||||
uwsgi,
|
||||
uwsgi-plugin-python3,
|
||||
|
|
|
@ -21,10 +21,11 @@ from django.db import models
|
|||
from django.utils.text import slugify
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from lingo.export_import.models import WithApplicationMixin
|
||||
from lingo.utils.misc import LingoImportError, clean_import_data, generate_slug
|
||||
|
||||
|
||||
class Agenda(models.Model):
|
||||
class Agenda(WithApplicationMixin, models.Model):
|
||||
label = models.CharField(_('Label'), max_length=150)
|
||||
slug = models.SlugField(_('Identifier'), max_length=160, unique=True)
|
||||
category_label = models.CharField(_('Category label'), max_length=150, null=True)
|
||||
|
@ -125,7 +126,7 @@ class Agenda(models.Model):
|
|||
return _('Events')
|
||||
|
||||
|
||||
class CheckTypeGroup(models.Model):
|
||||
class CheckTypeGroup(WithApplicationMixin, models.Model):
|
||||
slug = models.SlugField(_('Identifier'), max_length=160, unique=True)
|
||||
label = models.CharField(_('Label'), max_length=150)
|
||||
unexpected_presence = models.ForeignKey(
|
||||
|
|
|
@ -21,6 +21,14 @@ from django.contrib.contenttypes.models import ContentType
|
|||
from django.db import models
|
||||
|
||||
|
||||
class WithApplicationMixin:
|
||||
@property
|
||||
def applications(self):
|
||||
if getattr(self, '_applications', None) is None:
|
||||
Application.load_for_object(self)
|
||||
return self._applications
|
||||
|
||||
|
||||
class Application(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
slug = models.SlugField(max_length=100, unique=True)
|
||||
|
@ -71,34 +79,23 @@ class Application(models.Model):
|
|||
@classmethod
|
||||
def populate_objects(cls, object_class, objects):
|
||||
content_type = ContentType.objects.get_for_model(object_class)
|
||||
elements = ApplicationElement.objects.filter(content_type=content_type)
|
||||
elements = ApplicationElement.objects.filter(
|
||||
content_type=content_type, application__visible=True
|
||||
).prefetch_related('application')
|
||||
elements_by_objects = collections.defaultdict(list)
|
||||
for element in elements:
|
||||
elements_by_objects[element.content_object].append(element)
|
||||
applications_by_ids = {
|
||||
a.pk: a for a in cls.objects.filter(pk__in=elements.values('application'), visible=True)
|
||||
}
|
||||
elements_by_objects[element.object_id].append(element)
|
||||
for obj in objects:
|
||||
applications = []
|
||||
elements = elements_by_objects.get(obj) or []
|
||||
for element in elements:
|
||||
application = applications_by_ids.get(element.application_id)
|
||||
if application:
|
||||
applications.append(application)
|
||||
applications = [element.application for element in elements_by_objects.get(obj.pk) or []]
|
||||
obj._applications = sorted(applications, key=lambda a: a.name)
|
||||
|
||||
@classmethod
|
||||
def load_for_object(cls, obj):
|
||||
content_type = ContentType.objects.get_for_model(obj.__class__)
|
||||
elements = ApplicationElement.objects.filter(content_type=content_type, object_id=obj.pk)
|
||||
applications_by_ids = {
|
||||
a.pk: a for a in cls.objects.filter(pk__in=elements.values('application'), visible=True)
|
||||
}
|
||||
applications = []
|
||||
for element in elements:
|
||||
application = applications_by_ids.get(element.application_id)
|
||||
if application:
|
||||
applications.append(application)
|
||||
elements = ApplicationElement.objects.filter(
|
||||
content_type=content_type, object_id=obj.pk, application__visible=True
|
||||
).prefetch_related('application')
|
||||
applications = [element.application for element in elements]
|
||||
obj._applications = sorted(applications, key=lambda a: a.name)
|
||||
|
||||
def get_objects_for_object_class(self, object_class):
|
||||
|
@ -106,6 +103,12 @@ class Application(models.Model):
|
|||
elements = ApplicationElement.objects.filter(content_type=content_type, application=self)
|
||||
return object_class.objects.filter(pk__in=elements.values('object_id'))
|
||||
|
||||
@classmethod
|
||||
def get_orphan_objects_for_object_class(cls, object_class):
|
||||
content_type = ContentType.objects.get_for_model(object_class)
|
||||
elements = ApplicationElement.objects.filter(content_type=content_type, application__visible=True)
|
||||
return object_class.objects.exclude(pk__in=elements.values('object_id'))
|
||||
|
||||
|
||||
class ApplicationElement(models.Model):
|
||||
application = models.ForeignKey(Application, on_delete=models.CASCADE)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
{% load thumbnail %}
|
||||
{% if application %}
|
||||
<h2>
|
||||
{% thumbnail application.icon '64x64' format='PNG' as im %}
|
||||
<img src="{{ im.url }}" alt="" class="application-logo" />
|
||||
{% endthumbnail %}
|
||||
{{ application }}
|
||||
</h2>
|
||||
{% elif no_application %}
|
||||
<h2>{{ title_no_application }}</h2>
|
||||
{% else %}
|
||||
<h2>{{ title_object_list }}</h2>
|
||||
{% endif %}
|
|
@ -0,0 +1,5 @@
|
|||
{% if application %}
|
||||
<a href="{{ object_list_url }}?application={{ application.slug }}">{{ application }}</a>
|
||||
{% elif no_application %}
|
||||
<a href="{{ object_list_url }}?no-application">{{ title_no_application }}</a>
|
||||
{% endif %}
|
|
@ -0,0 +1,12 @@
|
|||
{% load i18n thumbnail %}
|
||||
{% if object.applications %}
|
||||
<h3>{% trans "Applications" %}</h3>
|
||||
{% for application in object.applications %}
|
||||
<a class="button button-paragraph" href="{{ object_list_url }}?application={{ application.slug }}">
|
||||
{% thumbnail application.icon '16x16' format='PNG' as im %}
|
||||
<img src="{{ im.url }}" alt="" class="application-icon" width="16" />
|
||||
{% endthumbnail %}
|
||||
{{ application }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
|
@ -0,0 +1,8 @@
|
|||
{% load thumbnail %}
|
||||
{% if not application and not no_application %}
|
||||
{% for application in object.applications %}
|
||||
{% thumbnail application.icon '16x16' format='PNG' as im %}
|
||||
<img src="{{ im.url }}" alt="" class="application-icon" width="16" />
|
||||
{% endthumbnail %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
|
@ -0,0 +1,15 @@
|
|||
{% load i18n thumbnail %}
|
||||
{% if applications %}
|
||||
<h3>{% trans "Applications" %}</h3>
|
||||
{% for application in applications %}
|
||||
<a class="button button-paragraph" href="?application={{ application.slug }}">
|
||||
{% thumbnail application.icon '16x16' format='PNG' as im %}
|
||||
<img src="{{ im.url }}" alt="" class="application-icon" width="16" />
|
||||
{% endthumbnail %}
|
||||
{{ application }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
<a class="button button-paragraph" href="?no-application">
|
||||
{{ title_no_application }}
|
||||
</a>
|
||||
{% endif %}
|
|
@ -0,0 +1,47 @@
|
|||
# lingo - payment and billing system
|
||||
# Copyright (C) 2022-2024 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.shortcuts import get_object_or_404
|
||||
|
||||
from lingo.export_import.models import Application
|
||||
|
||||
|
||||
class WithApplicationsMixin:
|
||||
def with_applications_dispatch(self, request):
|
||||
self.application = None
|
||||
self.no_application = False
|
||||
if 'application' in self.request.GET:
|
||||
self.application = get_object_or_404(
|
||||
Application, slug=self.request.GET['application'], visible=True
|
||||
)
|
||||
elif 'no-application' in self.request.GET:
|
||||
self.no_application = True
|
||||
|
||||
def with_applications_context_data(self, context):
|
||||
if self.application:
|
||||
context['application'] = self.application
|
||||
elif not self.no_application:
|
||||
Application.populate_objects(self.model, self.object_list)
|
||||
context['applications'] = Application.select_for_object_class(self.model)
|
||||
context['no_application'] = self.no_application
|
||||
return context
|
||||
|
||||
def with_applications_queryset(self):
|
||||
if self.application:
|
||||
return self.application.get_objects_for_object_class(self.model)
|
||||
if self.no_application:
|
||||
return Application.get_orphan_objects_for_object_class(self.model)
|
||||
return super().get_queryset()
|
|
@ -40,6 +40,7 @@ from django.utils.translation import gettext_lazy as _
|
|||
|
||||
from lingo.agendas.chrono import ChronoError, lock_events_check
|
||||
from lingo.agendas.models import Agenda
|
||||
from lingo.export_import.models import WithApplicationMixin
|
||||
from lingo.utils.fields import RichTextField
|
||||
from lingo.utils.misc import LingoImportError, clean_import_data, generate_slug
|
||||
from lingo.utils.wcs import (
|
||||
|
@ -74,7 +75,7 @@ class PayerDataError(InvoicingError):
|
|||
pass
|
||||
|
||||
|
||||
class Payer(models.Model):
|
||||
class Payer(WithApplicationMixin, models.Model):
|
||||
label = models.CharField(_('Label'), max_length=150)
|
||||
slug = models.SlugField(_('Identifier'), max_length=160, unique=True)
|
||||
description = models.TextField(_('Description'), null=True, blank=True)
|
||||
|
@ -296,7 +297,7 @@ INVOICE_MODELS = [
|
|||
]
|
||||
|
||||
|
||||
class Regie(models.Model):
|
||||
class Regie(WithApplicationMixin, models.Model):
|
||||
label = models.CharField(_('Label'), max_length=150)
|
||||
slug = models.SlugField(_('Identifier'), max_length=160, unique=True)
|
||||
description = models.TextField(
|
||||
|
|
|
@ -93,5 +93,8 @@
|
|||
<a class="button button-paragraph" href="{% url 'lingo-manager-invoicing-payer-edit' pk=payer.pk %}" rel="popup">{% trans "Edit" %}</a>
|
||||
<a class="button button-paragraph" href="{% url 'lingo-manager-invoicing-payer-export' pk=payer.pk %}">{% trans 'Export' %}</a>
|
||||
|
||||
{% url 'lingo-manager-invoicing-payer-list' as object_list_url %}
|
||||
{% include 'lingo/includes/application_detail_fragment.html' %}
|
||||
|
||||
</aside>
|
||||
{% endblock %}
|
||||
|
|
|
@ -4,12 +4,15 @@
|
|||
{% block page-title-extra-label %}{% trans "Payers" %}{% endblock %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a href="{% url 'lingo-manager-invoicing-payer-list' %}">{% trans "Payers" %}</a>
|
||||
<a href="{% url 'lingo-manager-homepage' %}">{% trans "Payments" context 'lingo title' %}</a>
|
||||
<a href="{% url 'lingo-manager-invoicing-regie-list' %}">{% trans "Regies" %}</a>
|
||||
{% url 'lingo-manager-invoicing-payer-list' as object_list_url %}
|
||||
<a href="{{ object_list_url }}">{% trans "Payers" %}</a>
|
||||
{% include 'lingo/includes/application_breadcrumb_fragment.html' with title_no_application=_('Payers outside applications') %}
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans 'Payers' %}</h2>
|
||||
{% include 'lingo/includes/application_appbar_fragment.html' with title_no_application=_('Payers outside applications') title_object_list=_('Payers') %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
@ -19,6 +22,7 @@
|
|||
{% for payer in object_list %}
|
||||
<li>
|
||||
<a href="{% url 'lingo-manager-invoicing-payer-detail' pk=payer.pk %}">
|
||||
{% include 'lingo/includes/application_icon_fragment.html' with object=payer %}
|
||||
{{ payer.label }}
|
||||
<span class="extra-info"> [{% trans "identifier:" %} {{ payer.slug }}]</span>
|
||||
</a>
|
||||
|
@ -26,8 +30,7 @@
|
|||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% else %}
|
||||
|
||||
{% elif not no_application %}
|
||||
<div class="big-msg-info">
|
||||
{% blocktrans %}
|
||||
This site doesn't have any payer yet. Click on the "New" button in the top
|
||||
|
@ -38,10 +41,14 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
<aside id="sidebar">
|
||||
{% if not application and not no_application %}
|
||||
<aside id="sidebar">
|
||||
|
||||
<h3>{% trans "Actions" %}</h3>
|
||||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-invoicing-payer-add' %}">{% trans 'New payer' %}</a>
|
||||
<h3>{% trans "Actions" %}</h3>
|
||||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-invoicing-payer-add' %}">{% trans 'New payer' %}</a>
|
||||
|
||||
</aside>
|
||||
{% include 'lingo/includes/application_list_fragment.html' with title_no_application=_('Payers outside applications') %}
|
||||
|
||||
</aside>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -54,5 +54,8 @@
|
|||
<a class="button button-paragraph" href="{% url 'lingo-manager-invoicing-regie-refund-list' regie_pk=regie.pk %}">{% trans 'Refunds' %}</a>
|
||||
<a class="button button-paragraph" href="{% url 'lingo-manager-invoicing-non-invoiced-line-list' regie_pk=regie.pk %}">{% trans 'Non invoiced lines' %}</a>
|
||||
|
||||
{% url 'lingo-manager-invoicing-regie-list' as object_list_url %}
|
||||
{% include 'lingo/includes/application_detail_fragment.html' %}
|
||||
|
||||
</aside>
|
||||
{% endblock %}
|
||||
|
|
|
@ -5,11 +5,13 @@
|
|||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a href="{% url 'lingo-manager-invoicing-regie-list' %}">{% trans "Regies" %}</a>
|
||||
{% url 'lingo-manager-invoicing-regie-list' as object_list_url %}
|
||||
<a href="{{ object_list_url }}">{% trans "Regies" %}</a>
|
||||
{% include 'lingo/includes/application_breadcrumb_fragment.html' with title_no_application=_('Regies outside applications') %}
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans 'Regies' %}</h2>
|
||||
{% include 'lingo/includes/application_appbar_fragment.html' with title_no_application=_('Regies outside applications') title_object_list=_('Regies') %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
@ -19,6 +21,7 @@
|
|||
{% for regie in object_list %}
|
||||
<li>
|
||||
<a href="{% url 'lingo-manager-invoicing-regie-detail' pk=regie.pk %}">
|
||||
{% include 'lingo/includes/application_icon_fragment.html' with object=regie %}
|
||||
{{ regie.label }}
|
||||
<span class="extra-info"> [{% trans "identifier:" %} {{ regie.slug }}]</span>
|
||||
</a>
|
||||
|
@ -26,8 +29,7 @@
|
|||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% else %}
|
||||
|
||||
{% elif not no_application %}
|
||||
<div class="big-msg-info">
|
||||
{% blocktrans %}
|
||||
This site doesn't have any regie yet. Click on the "New" button in the top
|
||||
|
@ -38,16 +40,20 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
<aside id="sidebar">
|
||||
{% if not application and not no_application %}
|
||||
<aside id="sidebar">
|
||||
|
||||
<h3>{% trans "Actions" %}</h3>
|
||||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-invoicing-regie-add' %}">{% trans 'New regie' %}</a>
|
||||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-invoicing-config-import' %}">{% trans 'Import site' %}</a>
|
||||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-invoicing-config-export' %}" data-autoclose-dialog="true">{% trans 'Export site' %}</a>
|
||||
<h3>{% trans "Actions" %}</h3>
|
||||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-invoicing-regie-add' %}">{% trans 'New regie' %}</a>
|
||||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-invoicing-config-import' %}">{% trans 'Import site' %}</a>
|
||||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-invoicing-config-export' %}" data-autoclose-dialog="true">{% trans 'Export site' %}</a>
|
||||
|
||||
<h3>{% trans "Navigation" %}</h3>
|
||||
<a class="button button-paragraph" href="{% url 'lingo-manager-invoicing-appearance-settings' %}">{% trans "Appearance Settings" %}</a>
|
||||
<a class="button button-paragraph" href="{% url 'lingo-manager-invoicing-payer-list' %}">{% trans "Payers" %}</a>
|
||||
<h3>{% trans "Navigation" %}</h3>
|
||||
<a class="button button-paragraph" href="{% url 'lingo-manager-invoicing-appearance-settings' %}">{% trans "Appearance Settings" %}</a>
|
||||
<a class="button button-paragraph" href="{% url 'lingo-manager-invoicing-payer-list' %}">{% trans "Payers" %}</a>
|
||||
|
||||
</aside>
|
||||
{% include 'lingo/includes/application_list_fragment.html' with title_no_application=_('Regies outside applications') %}
|
||||
|
||||
</aside>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -21,14 +21,26 @@ from django.http import HttpResponse
|
|||
from django.urls import reverse
|
||||
from django.views.generic import CreateView, DeleteView, DetailView, ListView, UpdateView
|
||||
|
||||
from lingo.export_import.views import WithApplicationsMixin
|
||||
from lingo.invoicing.forms import NewPayerForm, PayerForm, PayerMappingForm
|
||||
from lingo.invoicing.models import Payer
|
||||
|
||||
|
||||
class PayersListView(ListView):
|
||||
class PayersListView(WithApplicationsMixin, ListView):
|
||||
template_name = 'lingo/invoicing/manager_payer_list.html'
|
||||
model = Payer
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.with_applications_dispatch(request)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
return self.with_applications_queryset()
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
return self.with_applications_context_data(context)
|
||||
|
||||
|
||||
payers_list = PayersListView.as_view()
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ from django.utils.translation import gettext_lazy as _
|
|||
from django.views.generic import CreateView, DeleteView, DetailView, ListView, UpdateView
|
||||
|
||||
from lingo.agendas.models import Agenda
|
||||
from lingo.export_import.views import WithApplicationsMixin
|
||||
from lingo.invoicing.forms import (
|
||||
PaymentTypeForm,
|
||||
RegieCreditFilterSet,
|
||||
|
@ -69,10 +70,21 @@ def import_regies(data):
|
|||
return results
|
||||
|
||||
|
||||
class RegiesListView(ListView):
|
||||
class RegiesListView(WithApplicationsMixin, ListView):
|
||||
template_name = 'lingo/invoicing/manager_regie_list.html'
|
||||
model = Regie
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.with_applications_dispatch(request)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
return self.with_applications_queryset()
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
return self.with_applications_context_data(context)
|
||||
|
||||
|
||||
regies_list = RegiesListView.as_view()
|
||||
|
||||
|
|
|
@ -170,3 +170,7 @@ span.invoice-colour {
|
|||
border-radius: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.application-logo, .application-icon {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ from django.utils.text import slugify
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from lingo.agendas.models import Agenda, CheckType
|
||||
from lingo.export_import.models import WithApplicationMixin
|
||||
from lingo.utils.misc import LingoImportError, clean_import_data, generate_slug
|
||||
from lingo.utils.wcs import get_wcs_dependencies_from_template
|
||||
|
||||
|
@ -99,7 +100,7 @@ class PricingBookingCheckTypeError(PricingError):
|
|||
pass
|
||||
|
||||
|
||||
class CriteriaCategory(models.Model):
|
||||
class CriteriaCategory(WithApplicationMixin, models.Model):
|
||||
label = models.CharField(_('Label'), max_length=150)
|
||||
slug = models.SlugField(_('Identifier'), max_length=160, unique=True)
|
||||
|
||||
|
@ -261,7 +262,7 @@ class PricingMatrix:
|
|||
rows: list[PricingMatrixRow]
|
||||
|
||||
|
||||
class Pricing(models.Model):
|
||||
class Pricing(WithApplicationMixin, models.Model):
|
||||
label = models.CharField(_('Label'), max_length=150, null=True)
|
||||
slug = models.SlugField(_('Identifier'), max_length=160, null=True)
|
||||
|
||||
|
|
|
@ -116,5 +116,8 @@
|
|||
<a class="button button-paragraph" href="{{ chrono_url }}">{% trans "Agenda options" %}</a>
|
||||
{% endif %}{% endwith %}
|
||||
|
||||
{% url 'lingo-manager-agenda-list' as object_list_url %}
|
||||
{% include 'lingo/includes/application_detail_fragment.html' %}
|
||||
|
||||
</aside>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
{% extends "lingo/pricing/manager_pricing_list.html" %}
|
||||
{% load i18n %}
|
||||
{% load i18n thumbnail %}
|
||||
|
||||
{% block page-title-extra-label %}{% trans "Agendas" %} | {{ block.super }}{% endblock %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a href="{% url 'lingo-manager-agenda-list' %}">{% trans 'Agendas' %}</a>
|
||||
<a href="{% url 'lingo-manager-homepage' %}">{% trans "Payments" context 'lingo title' %}</a>
|
||||
<a href="{% url 'lingo-manager-pricing-list' %}">{% trans "Pricings" %}</a>
|
||||
{% url 'lingo-manager-agenda-list' as object_list_url %}
|
||||
<a href="{{ object_list_url }}">{% trans "Agendas" %}</a>
|
||||
{% include 'lingo/includes/application_breadcrumb_fragment.html' with title_no_application=_('Agendas outside applications') %}
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans 'Agendas' %}</h2>
|
||||
{% include 'lingo/includes/application_appbar_fragment.html' with title_no_application=_('Agendas outside applications') title_object_list=_('Agendas') %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
@ -21,14 +24,17 @@
|
|||
<ul class="objects-list single-links">
|
||||
{% for object in group.list %}
|
||||
<li>
|
||||
<a href="{% url 'lingo-manager-agenda-detail' object.pk %}">{{ object.label }} <span class="identifier">[{% trans "identifier:" %} {{ object.slug }}, {% trans "kind:" %} {{ object.get_real_kind_display }}]</a>
|
||||
{% with chrono_url=object.get_chrono_url %}{% if chrono_url %}<a href="{{ chrono_url }}" class="link-action-icon link">{% trans "view" %}</a>{% endif %}{% endwith %}
|
||||
</li>
|
||||
<a href="{% url 'lingo-manager-agenda-detail' object.pk %}">
|
||||
{% include 'lingo/includes/application_icon_fragment.html' %}
|
||||
{{ object.label }} <span class="identifier">[{% trans "identifier:" %} {{ object.slug }}, {% trans "kind:" %} {{ object.get_real_kind_display }}]</span>
|
||||
</a>
|
||||
{% with chrono_url=object.get_chrono_url %}{% if chrono_url %}<a href="{{ chrono_url }}" class="link-action-icon link">{% trans "view" %}</a>{% endif %}{% endwith %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% elif not no_application %}
|
||||
<div class="big-msg-info">
|
||||
{% blocktrans trimmed %}
|
||||
This site doesn't have any agenda yet. Click on the "Refresh agendas" button in the top
|
||||
|
@ -39,10 +45,14 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
<aside id="sidebar">
|
||||
{% if not application and not no_application %}
|
||||
<aside id="sidebar">
|
||||
|
||||
<h3>{% trans "Actions" %}</h3>
|
||||
<a class="button button-paragraph" href="{% url 'lingo-manager-agenda-sync' %}">{% trans 'Refresh agendas' %}</a>
|
||||
<h3>{% trans "Actions" %}</h3>
|
||||
<a class="button button-paragraph" href="{% url 'lingo-manager-agenda-sync' %}">{% trans 'Refresh agendas' %}</a>
|
||||
|
||||
</aside>
|
||||
{% include 'lingo/includes/application_list_fragment.html' with title_no_application=_('Agendas outside applications') %}
|
||||
|
||||
</aside>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -4,22 +4,30 @@
|
|||
{% block page-title-extra-label %}{% trans "Check types" %} | {{ block.super }}{% endblock %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a href="{% url 'lingo-manager-check-type-list' %}">{% trans "Check types" %}</a>
|
||||
<a href="{% url 'lingo-manager-homepage' %}">{% trans "Payments" context 'lingo title' %}</a>
|
||||
<a href="{% url 'lingo-manager-pricing-list' %}">{% trans "Pricings" %}</a>
|
||||
{% url 'lingo-manager-check-type-list' as object_list_url %}
|
||||
<a href="{{ object_list_url }}">{% trans "Check types" %}</a>
|
||||
{% include 'lingo/includes/application_breadcrumb_fragment.html' with title_no_application=_('Check types outside applications') %}
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans 'Check types' %}</h2>
|
||||
{% include 'lingo/includes/application_appbar_fragment.html' with title_no_application=_('Check types outside applications') title_object_list=_('Check types') %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="pk-information">
|
||||
<p>{% trans "Define here check types used in events agendas to check bookings." %}</p>
|
||||
</div>
|
||||
{% if not application and not no_application %}
|
||||
<div class="pk-information">
|
||||
<p>{% trans "Define here check types used in events agendas to check bookings." %}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% for object in object_list %}
|
||||
<div class="section check-type-group">
|
||||
<h3>
|
||||
<a rel="popup" href="{% url 'lingo-manager-check-type-group-edit' object.pk %}">{{ object }}</a>
|
||||
<a rel="popup" href="{% url 'lingo-manager-check-type-group-edit' object.pk %}">
|
||||
{% include 'lingo/includes/application_icon_fragment.html' %}
|
||||
{{ object }}
|
||||
</a>
|
||||
<span>
|
||||
<a class="button" href="{% url 'lingo-manager-check-type-group-export' object.pk %}">{% trans "Export"%}</a>
|
||||
<a class="button" rel="popup" href="{% url 'lingo-manager-check-type-group-delete' object.pk %}">{% trans "Delete"%}</a>
|
||||
|
@ -49,20 +57,26 @@
|
|||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="big-msg-info">
|
||||
{% blocktrans trimmed %}
|
||||
This site doesn't have any check type group yet. Click on the "New group" button in the top
|
||||
right of the page to add a first one.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% if not no_application %}
|
||||
<div class="big-msg-info">
|
||||
{% blocktrans trimmed %}
|
||||
This site doesn't have any check type group yet. Click on the "New group" button in the top
|
||||
right of the page to add a first one.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
<aside id="sidebar">
|
||||
{% if not application and not no_application %}
|
||||
<aside id="sidebar">
|
||||
|
||||
<h3>{% trans "Actions" %}</h3>
|
||||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-check-type-group-add' %}">{% trans 'New group' %}</a>
|
||||
<h3>{% trans "Actions" %}</h3>
|
||||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-check-type-group-add' %}">{% trans 'New group' %}</a>
|
||||
|
||||
</aside>
|
||||
{% include 'lingo/includes/application_list_fragment.html' with title_no_application=_('Check types outside applications') %}
|
||||
|
||||
</aside>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -4,30 +4,40 @@
|
|||
{% block page-title-extra-label %}{% trans "Criterias" %} | {{ block.super }}{% endblock %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a href="{% url 'lingo-manager-pricing-criteria-list' %}">{% trans "Criterias" %}</a>
|
||||
<a href="{% url 'lingo-manager-homepage' %}">{% trans "Payments" context 'lingo title' %}</a>
|
||||
<a href="{% url 'lingo-manager-pricing-list' %}">{% trans "Pricings" %}</a>
|
||||
{% url 'lingo-manager-pricing-criteria-list' as object_list_url %}
|
||||
<a href="{{ object_list_url }}">{% trans "Criterias" %}</a>
|
||||
{% include 'lingo/includes/application_breadcrumb_fragment.html' with title_no_application=_('Criterias outside applications') %}
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans 'Criterias' %}</h2>
|
||||
{% include 'lingo/includes/application_appbar_fragment.html' with title_no_application=_('Criterias outside applications') title_object_list=_('Criterias') %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div class="pk-information">
|
||||
<p>{% trans "Define here pricing criterias used in pricings." %}</p>
|
||||
</div>
|
||||
{% if not application and not no_application %}
|
||||
<div class="pk-information">
|
||||
<p>{% trans "Define here pricing criterias used in pricings." %}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if object_list %}
|
||||
<p class="hint">
|
||||
{% blocktrans trimmed %}
|
||||
Use drag and drop with the ⣿ handles to reorder criterias inside a category.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
{% if not application and not no_application %}
|
||||
<p class="hint">
|
||||
{% blocktrans trimmed %}
|
||||
Use drag and drop with the ⣿ handles to reorder criterias inside a category.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% for object in object_list %}
|
||||
<div class="section criteria-category">
|
||||
<h3>
|
||||
<a rel="popup" href="{% url 'lingo-manager-pricing-criteria-category-edit' object.pk %}">{{ object }} [{{ object.slug }}]</a>
|
||||
<a rel="popup" href="{% url 'lingo-manager-pricing-criteria-category-edit' object.pk %}">
|
||||
{% include 'lingo/includes/application_icon_fragment.html' %}
|
||||
{{ object }} [{{ object.slug }}]
|
||||
</a>
|
||||
<span>
|
||||
<a class="button" href="{% url 'lingo-manager-pricing-criteria-category-export' object.pk %}">{% trans "Export"%}</a>
|
||||
<a class="button" rel="popup" href="{% url 'lingo-manager-pricing-criteria-category-delete' object.pk %}">{% trans "Delete"%}</a>
|
||||
|
@ -37,7 +47,7 @@
|
|||
<ul class="objects-list single-links sortable" data-order-url="{% url 'lingo-manager-pricing-criteria-order' object.pk %}">
|
||||
{% for criteria in object.criterias.all %}
|
||||
<li{% if not criteria.default %} class="sortable-item" data-item-id="{{ criteria.pk }}"{% endif %}>
|
||||
{% if not criteria.default %}<span class="handle">⣿</span>{% endif %}
|
||||
{% if not criteria.default and not application and not no_application %}<span class="handle">⣿</span>{% endif %}
|
||||
<a rel="popup" href="{% url 'lingo-manager-pricing-criteria-edit' object.pk criteria.pk %}">{{ criteria }}{% if criteria.default %} <span class="extra-info">- {% trans "default" %}</span>{% endif %}</a>
|
||||
<a class="delete" rel="popup" href="{% url 'lingo-manager-pricing-criteria-delete' object.pk criteria.pk %}">{% trans "delete"%}</a>
|
||||
</li>
|
||||
|
@ -47,20 +57,26 @@
|
|||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="big-msg-info">
|
||||
{% blocktrans trimmed %}
|
||||
This site doesn't have any pricing category yet. Click on the "New category" button in the top
|
||||
right of the page to add a first one.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% if not no_application %}
|
||||
<div class="big-msg-info">
|
||||
{% blocktrans trimmed %}
|
||||
This site doesn't have any pricing category yet. Click on the "New category" button in the top
|
||||
right of the page to add a first one.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
<aside id="sidebar">
|
||||
{% if not application and not no_application %}
|
||||
<aside id="sidebar">
|
||||
|
||||
<h3>{% trans "Actions" %}</h3>
|
||||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-pricing-criteria-category-add' %}">{% trans 'New category' %}</a>
|
||||
<h3>{% trans "Actions" %}</h3>
|
||||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-pricing-criteria-category-add' %}">{% trans 'New category' %}</a>
|
||||
|
||||
</aside>
|
||||
{% include 'lingo/includes/application_list_fragment.html' with title_no_application=_('Criterias outside applications') %}
|
||||
|
||||
</aside>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -283,5 +283,8 @@
|
|||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-pricing-edit' object.pk %}">{% trans 'Options' %}</a>
|
||||
<a class="button button-paragraph" href="{% url 'lingo-manager-pricing-export' pk=object.pk %}">{% trans 'Export' %}</a>
|
||||
|
||||
{% url 'lingo-manager-pricing-list' as object_list_url %}
|
||||
{% include 'lingo/includes/application_detail_fragment.html' %}
|
||||
|
||||
</aside>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,21 +1,25 @@
|
|||
{% extends "lingo/manager_homepage.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block page-title-extra-label %}{% trans "Pricings" context 'agenda pricing' %}{% endblock %}
|
||||
{% block page-title-extra-label %}{% trans "Pricings" %}{% endblock %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a href="{% url 'lingo-manager-pricing-list' %}">{% trans "Pricings" context 'agenda pricing' %}</a>
|
||||
{% url 'lingo-manager-pricing-list' as object_list_url %}
|
||||
<a href="{{ object_list_url }}">{% trans "Pricings" %}</a>
|
||||
{% include 'lingo/includes/application_breadcrumb_fragment.html' with title_no_application=_('Pricings outside applications') %}
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans 'Pricings' context 'agenda pricing' %}</h2>
|
||||
{% include 'lingo/includes/application_appbar_fragment.html' with title_no_application=_('Pricings outside applications') title_object_list=_('Pricings') %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="pk-information">
|
||||
<p>{% trans "Define here pricings to attach to events agendas." %}</p>
|
||||
</div>
|
||||
{% if not application and not no_application %}
|
||||
<div class="pk-information">
|
||||
<p>{% trans "Define here pricings to attach to events agendas." %}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if object_list %}
|
||||
<div>
|
||||
<h3>{% trans "Pricings" context 'agenda pricing' %}</h3>
|
||||
|
@ -23,6 +27,7 @@
|
|||
{% for object in object_list %}{% if not object.flat_fee_schedule %}
|
||||
<li>
|
||||
<a href="{% url 'lingo-manager-pricing-detail' pk=object.pk %}">
|
||||
{% include 'lingo/includes/application_icon_fragment.html' %}
|
||||
{{ object }}
|
||||
- {% blocktrans trimmed with start=object.date_start|date:'d/m/Y' end=object.date_end|date:'d/m/Y' %}From {{ start }} to {{ end }}{% endblocktrans %})
|
||||
<span class="extra-info"> [{% trans "identifier:" %} {{ object.slug }}]</span>
|
||||
|
@ -35,6 +40,7 @@
|
|||
{% for object in object_list %}{% if object.flat_fee_schedule %}
|
||||
<li>
|
||||
<a href="{% url 'lingo-manager-pricing-detail' pk=object.pk %}">
|
||||
{% include 'lingo/includes/application_icon_fragment.html' %}
|
||||
{{ object }}
|
||||
- {% blocktrans trimmed with start=object.date_start|date:'d/m/Y' end=object.date_end|date:'d/m/Y' %}From {{ start }} to {{ end }}{% endblocktrans %})
|
||||
<span class="extra-info"> [{% trans "identifier:" %} {{ object.slug }}]</span>
|
||||
|
@ -43,7 +49,7 @@
|
|||
{% endif %}{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% else %}
|
||||
{% elif not no_application %}
|
||||
<div class="big-msg-info">
|
||||
{% blocktrans trimmed %}
|
||||
This site doesn't have any pricing yet. Click on the "New pricing" button in the top
|
||||
|
@ -54,17 +60,21 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
<aside id="sidebar">
|
||||
{% if not application and not no_application %}
|
||||
<aside id="sidebar">
|
||||
|
||||
<h3>{% trans "Actions" %}</h3>
|
||||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-pricing-add' %}">{% trans 'New pricing' %}</a>
|
||||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-pricing-config-import' %}">{% trans 'Import site' %}</a>
|
||||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-pricing-config-export' %}" data-autoclose-dialog="true">{% trans 'Export site' %}</a>
|
||||
<h3>{% trans "Actions" %}</h3>
|
||||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-pricing-add' %}">{% trans 'New pricing' %}</a>
|
||||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-pricing-config-import' %}">{% trans 'Import site' %}</a>
|
||||
<a class="button button-paragraph" rel="popup" href="{% url 'lingo-manager-pricing-config-export' %}" data-autoclose-dialog="true">{% trans 'Export site' %}</a>
|
||||
|
||||
<h3>{% trans "Navigation" %}</h3>
|
||||
<a class="button button-paragraph" href="{% url 'lingo-manager-pricing-criteria-list' %}">{% trans "Criterias" %}</a>
|
||||
<a class="button button-paragraph" href="{% url 'lingo-manager-agenda-list' %}">{% trans "Agendas" %}</a>
|
||||
<a class="button button-paragraph" href="{% url 'lingo-manager-check-type-list' %}">{% trans "Check types" %}</a>
|
||||
<h3>{% trans "Navigation" %}</h3>
|
||||
<a class="button button-paragraph" href="{% url 'lingo-manager-pricing-criteria-list' %}">{% trans "Criterias" %}</a>
|
||||
<a class="button button-paragraph" href="{% url 'lingo-manager-agenda-list' %}">{% trans "Agendas" %}</a>
|
||||
<a class="button button-paragraph" href="{% url 'lingo-manager-check-type-list' %}">{% trans "Check types" %}</a>
|
||||
|
||||
</aside>
|
||||
{% include 'lingo/includes/application_list_fragment.html' with title_no_application=_('Pricings outside applications') %}
|
||||
|
||||
</aside>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -41,6 +41,7 @@ from django.views.generic.detail import SingleObjectMixin
|
|||
from lingo.agendas.chrono import refresh_agendas
|
||||
from lingo.agendas.models import Agenda, CheckType, CheckTypeGroup
|
||||
from lingo.agendas.views import AgendaMixin
|
||||
from lingo.export_import.views import WithApplicationsMixin
|
||||
from lingo.pricing.forms import (
|
||||
CheckTypeForm,
|
||||
CheckTypeGroupUnexpectedPresenceForm,
|
||||
|
@ -221,12 +222,21 @@ class ConfigImportView(FormView):
|
|||
config_import = ConfigImportView.as_view()
|
||||
|
||||
|
||||
class CriteriaListView(ListView):
|
||||
class CriteriaListView(WithApplicationsMixin, ListView):
|
||||
template_name = 'lingo/pricing/manager_criteria_list.html'
|
||||
model = CriteriaCategory
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.with_applications_dispatch(request)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
return CriteriaCategory.objects.prefetch_related('criterias')
|
||||
queryset = self.with_applications_queryset()
|
||||
return queryset.prefetch_related('criterias')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
return self.with_applications_context_data(context)
|
||||
|
||||
|
||||
criteria_list = CriteriaListView.as_view()
|
||||
|
@ -368,14 +378,22 @@ class CriteriaDeleteView(DeleteView):
|
|||
criteria_delete = CriteriaDeleteView.as_view()
|
||||
|
||||
|
||||
class AgendaListView(ListView):
|
||||
class AgendaListView(WithApplicationsMixin, ListView):
|
||||
template_name = 'lingo/pricing/manager_agenda_list.html'
|
||||
model = Agenda
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.with_applications_dispatch(request)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super().get_queryset()
|
||||
queryset = self.with_applications_queryset()
|
||||
return queryset.order_by('category_label', 'label')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
return self.with_applications_context_data(context)
|
||||
|
||||
|
||||
agenda_list = AgendaListView.as_view()
|
||||
|
||||
|
@ -467,12 +485,21 @@ class AgendaInvoicingSettingsView(AgendaMixin, UpdateView):
|
|||
agenda_invoicing_settings = AgendaInvoicingSettingsView.as_view()
|
||||
|
||||
|
||||
class PricingListView(ListView):
|
||||
class PricingListView(WithApplicationsMixin, ListView):
|
||||
template_name = 'lingo/pricing/manager_pricing_list.html'
|
||||
model = Pricing
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.with_applications_dispatch(request)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
return Pricing.objects.all().order_by('flat_fee_schedule', 'date_start', 'date_end')
|
||||
queryset = self.with_applications_queryset()
|
||||
return queryset.order_by('flat_fee_schedule', 'date_start', 'date_end')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
return self.with_applications_context_data(context)
|
||||
|
||||
|
||||
pricing_list = PricingListView.as_view()
|
||||
|
@ -965,12 +992,21 @@ class PricingMatrixEdit(FormView):
|
|||
pricing_matrix_edit = PricingMatrixEdit.as_view()
|
||||
|
||||
|
||||
class CheckTypeListView(ListView):
|
||||
class CheckTypeListView(WithApplicationsMixin, ListView):
|
||||
template_name = 'lingo/pricing/manager_check_type_list.html'
|
||||
model = CheckTypeGroup
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.with_applications_dispatch(request)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
return CheckTypeGroup.objects.prefetch_related('check_types')
|
||||
queryset = self.with_applications_queryset()
|
||||
return queryset.prefetch_related('check_types')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
return self.with_applications_context_data(context)
|
||||
|
||||
|
||||
check_type_list = CheckTypeListView.as_view()
|
||||
|
|
|
@ -57,6 +57,7 @@ INSTALLED_APPS = (
|
|||
'gadjo',
|
||||
'rest_framework',
|
||||
'django_filters',
|
||||
'sorl.thumbnail',
|
||||
'lingo.agendas',
|
||||
'lingo.api',
|
||||
'lingo.basket',
|
||||
|
@ -231,6 +232,10 @@ CKEDITOR_CONFIGS = {
|
|||
|
||||
BASKET_EXPIRY_DELAY = 60 # 1 hour by default
|
||||
|
||||
# from solr.thumbnail -- https://sorl-thumbnail.readthedocs.io/en/latest/reference/settings.html
|
||||
THUMBNAIL_PRESERVE_FORMAT = True
|
||||
THUMBNAIL_FORCE_OVERWRITE = False
|
||||
|
||||
local_settings_file = os.environ.get(
|
||||
'LINGO_SETTINGS_FILE', os.path.join(os.path.dirname(__file__), 'local_settings.py')
|
||||
)
|
||||
|
|
1
setup.py
1
setup.py
|
@ -168,6 +168,7 @@ setup(
|
|||
'djangorestframework>=3.3, <3.15',
|
||||
'django-filter',
|
||||
'weasyprint',
|
||||
'sorl-thumbnail',
|
||||
],
|
||||
zip_safe=False,
|
||||
cmdclass={
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 558 B |
|
@ -0,0 +1,538 @@
|
|||
import datetime
|
||||
import os
|
||||
|
||||
import pytest
|
||||
from django.core.files import File
|
||||
from pyquery import PyQuery
|
||||
|
||||
from lingo.agendas.models import Agenda, CheckTypeGroup
|
||||
from lingo.export_import.models import Application, ApplicationElement
|
||||
from lingo.invoicing.models import Payer, Regie
|
||||
from lingo.pricing.models import CriteriaCategory, Pricing
|
||||
from tests.utils import login
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
TESTS_DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def application_with_icon():
|
||||
application = Application.objects.create(
|
||||
name='App 1',
|
||||
slug='app-1',
|
||||
version_number='1',
|
||||
)
|
||||
with open(os.path.join(TESTS_DATA_DIR, 'black.jpeg'), mode='rb') as fd:
|
||||
application.icon.save('black.jpeg', File(fd), save=True)
|
||||
return application
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def application_without_icon():
|
||||
application = Application.objects.create(
|
||||
name='App 2',
|
||||
slug='app-2',
|
||||
version_number='1',
|
||||
)
|
||||
return application
|
||||
|
||||
|
||||
@pytest.mark.parametrize('icon', [True, False])
|
||||
def test_agenda(app, admin_user, application_with_icon, application_without_icon, icon):
|
||||
if icon:
|
||||
application = application_with_icon
|
||||
else:
|
||||
application = application_without_icon
|
||||
|
||||
agenda1 = Agenda.objects.create(label='Agenda 1')
|
||||
agenda2 = Agenda.objects.create(label='Agenda 2')
|
||||
ApplicationElement.objects.create(content_object=agenda2, application=application)
|
||||
agenda3 = Agenda.objects.create(label='Agenda 3')
|
||||
ApplicationElement.objects.create(content_object=agenda3, application=application)
|
||||
|
||||
app = login(app)
|
||||
|
||||
resp = app.get('/manage/pricing/agendas/')
|
||||
assert len(resp.pyquery('ul.objects-list li')) == 3
|
||||
assert (
|
||||
resp.pyquery('ul.objects-list li:nth-child(1)').text()
|
||||
== 'Agenda 1 [identifier: agenda-1, kind: Events] view'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('ul.objects-list li:nth-child(2)').text()
|
||||
== 'Agenda 2 [identifier: agenda-2, kind: Events] view'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('ul.objects-list li:nth-child(3)').text()
|
||||
== 'Agenda 3 [identifier: agenda-3, kind: Events] view'
|
||||
)
|
||||
if icon:
|
||||
assert len(resp.pyquery('ul.objects-list img')) == 2
|
||||
assert len(resp.pyquery('ul.objects-list li:nth-child(1) img')) == 0
|
||||
assert len(resp.pyquery('ul.objects-list li:nth-child(2) img.application-icon')) == 1
|
||||
assert len(resp.pyquery('ul.objects-list li:nth-child(3) img.application-icon')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('ul.objects-list img')) == 0
|
||||
assert resp.pyquery('h3:contains("Applications") + .button-paragraph').text() == application.name
|
||||
if icon:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img.application-icon')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img')) == 0
|
||||
assert 'Agendas outside applications' in resp
|
||||
|
||||
# check application view
|
||||
resp = resp.click(application.name)
|
||||
assert resp.pyquery('h2').text() == application.name
|
||||
if icon:
|
||||
assert len(resp.pyquery('h2 img.application-logo')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('h2 img')) == 0
|
||||
assert len(resp.pyquery('ul.objects-list li')) == 2
|
||||
assert (
|
||||
resp.pyquery('ul.objects-list li:nth-child(1)').text()
|
||||
== 'Agenda 2 [identifier: agenda-2, kind: Events] view'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('ul.objects-list li:nth-child(2)').text()
|
||||
== 'Agenda 3 [identifier: agenda-3, kind: Events] view'
|
||||
)
|
||||
assert len(resp.pyquery('ul.objects-list li img')) == 0
|
||||
|
||||
# check elements outside applications
|
||||
resp = app.get('/manage/pricing/agendas/')
|
||||
resp = resp.click('Agendas outside applications')
|
||||
assert resp.pyquery('h2').text() == 'Agendas outside applications'
|
||||
assert len(resp.pyquery('ul.objects-list li')) == 1
|
||||
assert (
|
||||
resp.pyquery('ul.objects-list li:nth-child(1)').text()
|
||||
== 'Agenda 1 [identifier: agenda-1, kind: Events] view'
|
||||
)
|
||||
|
||||
# check detail page
|
||||
resp = app.get('/manage/pricing/agenda/%s/' % agenda1.pk)
|
||||
assert len(resp.pyquery('h3:contains("Applications")')) == 0
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph')) == 0
|
||||
resp = app.get('/manage/pricing/agenda/%s/' % agenda2.pk)
|
||||
assert resp.pyquery('h3:contains("Applications") + .button-paragraph').text() == application.name
|
||||
if icon:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img.application-icon')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img')) == 0
|
||||
|
||||
# check visible flag
|
||||
application.visible = False
|
||||
application.save()
|
||||
resp = app.get('/manage/pricing/agendas/')
|
||||
assert len(resp.pyquery('h3:contains("Applications")')) == 0
|
||||
assert len(resp.pyquery('ul.objects-list img')) == 0
|
||||
app.get('/manage/pricing/agendas/?application=%s' % application.slug, status=404)
|
||||
resp = app.get('/manage/pricing/agenda/%s/' % agenda2.pk)
|
||||
assert len(resp.pyquery('h3:contains("Applications")')) == 0
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph')) == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize('icon', [True, False])
|
||||
def test_check_type(app, admin_user, application_with_icon, application_without_icon, icon):
|
||||
if icon:
|
||||
application = application_with_icon
|
||||
else:
|
||||
application = application_without_icon
|
||||
|
||||
CheckTypeGroup.objects.create(label='CheckTypeGroup 1')
|
||||
check_type_group2 = CheckTypeGroup.objects.create(label='CheckTypeGroup 2')
|
||||
ApplicationElement.objects.create(content_object=check_type_group2, application=application)
|
||||
check_type_group3 = CheckTypeGroup.objects.create(label='CheckTypeGroup 3')
|
||||
ApplicationElement.objects.create(content_object=check_type_group3, application=application)
|
||||
|
||||
app = login(app)
|
||||
|
||||
resp = app.get('/manage/pricing/check-types/')
|
||||
assert len(resp.pyquery('.section')) == 3
|
||||
assert len(resp.pyquery('.section h3')) == 3
|
||||
assert PyQuery(resp.pyquery('.section')[0]).find('h3').text() == 'CheckTypeGroup 1 Export Delete'
|
||||
assert PyQuery(resp.pyquery('.section')[1]).find('h3').text() == 'CheckTypeGroup 2 Export Delete'
|
||||
assert PyQuery(resp.pyquery('.section')[2]).find('h3').text() == 'CheckTypeGroup 3 Export Delete'
|
||||
if icon:
|
||||
assert len(resp.pyquery('h3 img')) == 2
|
||||
assert len(PyQuery(resp.pyquery('.section')[0]).find('h3 img')) == 0
|
||||
assert len(PyQuery(resp.pyquery('.section')[1]).find('h3 img.application-icon')) == 1
|
||||
assert len(PyQuery(resp.pyquery('.section')[2]).find('h3 img.application-icon')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('h3 img')) == 0
|
||||
assert resp.pyquery('h3:contains("Applications") + .button-paragraph').text() == application.name
|
||||
if icon:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img.application-icon')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img')) == 0
|
||||
assert 'Check types outside applications' in resp
|
||||
|
||||
# check application view
|
||||
resp = resp.click(application.name)
|
||||
assert resp.pyquery('h2').text() == application.name
|
||||
if icon:
|
||||
assert len(resp.pyquery('h2 img.application-logo')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('h2 img')) == 0
|
||||
assert len(resp.pyquery('.section')) == 2
|
||||
assert len(resp.pyquery('.section h3')) == 2
|
||||
assert PyQuery(resp.pyquery('.section')[0]).find('h3').text() == 'CheckTypeGroup 2 Export Delete'
|
||||
assert PyQuery(resp.pyquery('.section')[1]).find('h3').text() == 'CheckTypeGroup 3 Export Delete'
|
||||
assert len(resp.pyquery('h3 img')) == 0
|
||||
|
||||
# check elements outside applications
|
||||
resp = app.get('/manage/pricing/check-types/')
|
||||
resp = resp.click('Check types outside applications')
|
||||
assert resp.pyquery('h2').text() == 'Check types outside applications'
|
||||
assert len(resp.pyquery('.section')) == 1
|
||||
assert len(resp.pyquery('.section h3')) == 1
|
||||
assert PyQuery(resp.pyquery('.section')[0]).find('h3').text() == 'CheckTypeGroup 1 Export Delete'
|
||||
|
||||
# check visible flag
|
||||
application.visible = False
|
||||
application.save()
|
||||
resp = app.get('/manage/pricing/check-types/')
|
||||
assert len(resp.pyquery('h3:contains("Applications")')) == 0
|
||||
assert len(resp.pyquery('ul.objects-list img')) == 0
|
||||
app.get('/manage/pricing/check-types/?application=%s' % application.slug, status=404)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('icon', [True, False])
|
||||
def test_pricing(app, admin_user, application_with_icon, application_without_icon, icon):
|
||||
if icon:
|
||||
application = application_with_icon
|
||||
else:
|
||||
application = application_without_icon
|
||||
|
||||
pricing1 = Pricing.objects.create(
|
||||
label='Pricing 1',
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
pricing2 = Pricing.objects.create(
|
||||
label='Pricing 2',
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
ApplicationElement.objects.create(content_object=pricing2, application=application)
|
||||
pricing3 = Pricing.objects.create(
|
||||
label='Pricing 3',
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=10, day=1),
|
||||
)
|
||||
ApplicationElement.objects.create(content_object=pricing3, application=application)
|
||||
|
||||
app = login(app)
|
||||
|
||||
resp = app.get('/manage/pricing/')
|
||||
assert len(resp.pyquery('ul.objects-list li')) == 3
|
||||
assert (
|
||||
resp.pyquery('ul.objects-list li:nth-child(1)').text()
|
||||
== 'Pricing 1 - From 01/09/2021 to 01/10/2021) [identifier: pricing-1]'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('ul.objects-list li:nth-child(2)').text()
|
||||
== 'Pricing 2 - From 01/09/2021 to 01/10/2021) [identifier: pricing-2]'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('ul.objects-list li:nth-child(3)').text()
|
||||
== 'Pricing 3 - From 01/09/2021 to 01/10/2021) [identifier: pricing-3]'
|
||||
)
|
||||
if icon:
|
||||
assert len(resp.pyquery('ul.objects-list img')) == 2
|
||||
assert len(resp.pyquery('ul.objects-list li:nth-child(1) img')) == 0
|
||||
assert len(resp.pyquery('ul.objects-list li:nth-child(2) img.application-icon')) == 1
|
||||
assert len(resp.pyquery('ul.objects-list li:nth-child(3) img.application-icon')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('ul.objects-list img')) == 0
|
||||
assert resp.pyquery('h3:contains("Applications") + .button-paragraph').text() == application.name
|
||||
if icon:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img.application-icon')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img')) == 0
|
||||
assert 'Pricings outside applications' in resp
|
||||
|
||||
# check application view
|
||||
resp = resp.click(application.name)
|
||||
assert resp.pyquery('h2').text() == application.name
|
||||
if icon:
|
||||
assert len(resp.pyquery('h2 img.application-logo')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('h2 img')) == 0
|
||||
assert len(resp.pyquery('ul.objects-list li')) == 2
|
||||
assert (
|
||||
resp.pyquery('ul.objects-list li:nth-child(1)').text()
|
||||
== 'Pricing 2 - From 01/09/2021 to 01/10/2021) [identifier: pricing-2]'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('ul.objects-list li:nth-child(2)').text()
|
||||
== 'Pricing 3 - From 01/09/2021 to 01/10/2021) [identifier: pricing-3]'
|
||||
)
|
||||
assert len(resp.pyquery('ul.objects-list li img')) == 0
|
||||
|
||||
# check elements outside applications
|
||||
resp = app.get('/manage/pricing/')
|
||||
resp = resp.click('Pricings outside applications')
|
||||
assert resp.pyquery('h2').text() == 'Pricings outside applications'
|
||||
assert len(resp.pyquery('ul.objects-list li')) == 1
|
||||
assert (
|
||||
resp.pyquery('ul.objects-list li:nth-child(1)').text()
|
||||
== 'Pricing 1 - From 01/09/2021 to 01/10/2021) [identifier: pricing-1]'
|
||||
)
|
||||
|
||||
# check detail page
|
||||
resp = app.get('/manage/pricing/%s/' % pricing1.pk)
|
||||
assert len(resp.pyquery('h3:contains("Applications")')) == 0
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph')) == 0
|
||||
resp = app.get('/manage/pricing/%s/' % pricing2.pk)
|
||||
assert resp.pyquery('h3:contains("Applications") + .button-paragraph').text() == application.name
|
||||
if icon:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img.application-icon')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img')) == 0
|
||||
|
||||
# check visible flag
|
||||
application.visible = False
|
||||
application.save()
|
||||
resp = app.get('/manage/pricing/')
|
||||
assert len(resp.pyquery('h3:contains("Applications")')) == 0
|
||||
assert len(resp.pyquery('ul.objects-list img')) == 0
|
||||
app.get('/manage/pricing/?application=%s' % application.slug, status=404)
|
||||
resp = app.get('/manage/pricing/%s/' % pricing2.pk)
|
||||
assert len(resp.pyquery('h3:contains("Applications")')) == 0
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph')) == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize('icon', [True, False])
|
||||
def test_criteria_category(app, admin_user, application_with_icon, application_without_icon, icon):
|
||||
if icon:
|
||||
application = application_with_icon
|
||||
else:
|
||||
application = application_without_icon
|
||||
|
||||
CriteriaCategory.objects.create(label='CriteriaCategory 1')
|
||||
criteria_category2 = CriteriaCategory.objects.create(label='CriteriaCategory 2')
|
||||
ApplicationElement.objects.create(content_object=criteria_category2, application=application)
|
||||
criteria_category3 = CriteriaCategory.objects.create(label='CriteriaCategory 3')
|
||||
ApplicationElement.objects.create(content_object=criteria_category3, application=application)
|
||||
|
||||
app = login(app)
|
||||
|
||||
resp = app.get('/manage/pricing/criterias/')
|
||||
assert len(resp.pyquery('.section')) == 3
|
||||
assert len(resp.pyquery('.section h3')) == 3
|
||||
assert (
|
||||
PyQuery(resp.pyquery('.section')[0]).find('h3').text()
|
||||
== 'CriteriaCategory 1 [criteriacategory-1] Export Delete'
|
||||
)
|
||||
assert (
|
||||
PyQuery(resp.pyquery('.section')[1]).find('h3').text()
|
||||
== 'CriteriaCategory 2 [criteriacategory-2] Export Delete'
|
||||
)
|
||||
assert (
|
||||
PyQuery(resp.pyquery('.section')[2]).find('h3').text()
|
||||
== 'CriteriaCategory 3 [criteriacategory-3] Export Delete'
|
||||
)
|
||||
if icon:
|
||||
assert len(resp.pyquery('h3 img')) == 2
|
||||
assert len(PyQuery(resp.pyquery('.section')[0]).find('h3 img')) == 0
|
||||
assert len(PyQuery(resp.pyquery('.section')[1]).find('h3 img.application-icon')) == 1
|
||||
assert len(PyQuery(resp.pyquery('.section')[2]).find('h3 img.application-icon')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('h3 img')) == 0
|
||||
assert resp.pyquery('h3:contains("Applications") + .button-paragraph').text() == application.name
|
||||
if icon:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img.application-icon')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img')) == 0
|
||||
assert 'Criterias outside applications' in resp
|
||||
|
||||
# check application view
|
||||
resp = resp.click(application.name)
|
||||
assert resp.pyquery('h2').text() == application.name
|
||||
if icon:
|
||||
assert len(resp.pyquery('h2 img.application-logo')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('h2 img')) == 0
|
||||
assert len(resp.pyquery('.section')) == 2
|
||||
assert len(resp.pyquery('.section h3')) == 2
|
||||
assert (
|
||||
PyQuery(resp.pyquery('.section')[0]).find('h3').text()
|
||||
== 'CriteriaCategory 2 [criteriacategory-2] Export Delete'
|
||||
)
|
||||
assert (
|
||||
PyQuery(resp.pyquery('.section')[1]).find('h3').text()
|
||||
== 'CriteriaCategory 3 [criteriacategory-3] Export Delete'
|
||||
)
|
||||
assert len(resp.pyquery('h3 img')) == 0
|
||||
|
||||
# check elements outside applications
|
||||
resp = app.get('/manage/pricing/criterias/')
|
||||
resp = resp.click('Criterias outside applications')
|
||||
assert resp.pyquery('h2').text() == 'Criterias outside applications'
|
||||
assert len(resp.pyquery('.section')) == 1
|
||||
assert len(resp.pyquery('.section h3')) == 1
|
||||
assert (
|
||||
PyQuery(resp.pyquery('.section')[0]).find('h3').text()
|
||||
== 'CriteriaCategory 1 [criteriacategory-1] Export Delete'
|
||||
)
|
||||
|
||||
# check visible flag
|
||||
application.visible = False
|
||||
application.save()
|
||||
resp = app.get('/manage/pricing/criterias/')
|
||||
assert len(resp.pyquery('h3:contains("Applications")')) == 0
|
||||
assert len(resp.pyquery('ul.objects-list img')) == 0
|
||||
app.get('/manage/pricing/criterias/?application=%s' % application.slug, status=404)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('icon', [True, False])
|
||||
def test_payer(app, admin_user, application_with_icon, application_without_icon, icon):
|
||||
if icon:
|
||||
application = application_with_icon
|
||||
else:
|
||||
application = application_without_icon
|
||||
|
||||
payer1 = Payer.objects.create(label='Payer 1')
|
||||
payer2 = Payer.objects.create(label='Payer 2')
|
||||
ApplicationElement.objects.create(content_object=payer2, application=application)
|
||||
payer3 = Payer.objects.create(label='Payer 3')
|
||||
ApplicationElement.objects.create(content_object=payer3, application=application)
|
||||
|
||||
app = login(app)
|
||||
|
||||
resp = app.get('/manage/invoicing/payers/')
|
||||
assert len(resp.pyquery('ul.objects-list li')) == 3
|
||||
assert resp.pyquery('ul.objects-list li:nth-child(1)').text() == 'Payer 1 [identifier: payer-1]'
|
||||
assert resp.pyquery('ul.objects-list li:nth-child(2)').text() == 'Payer 2 [identifier: payer-2]'
|
||||
assert resp.pyquery('ul.objects-list li:nth-child(3)').text() == 'Payer 3 [identifier: payer-3]'
|
||||
if icon:
|
||||
assert len(resp.pyquery('ul.objects-list img')) == 2
|
||||
assert len(resp.pyquery('ul.objects-list li:nth-child(1) img')) == 0
|
||||
assert len(resp.pyquery('ul.objects-list li:nth-child(2) img.application-icon')) == 1
|
||||
assert len(resp.pyquery('ul.objects-list li:nth-child(3) img.application-icon')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('ul.objects-list img')) == 0
|
||||
assert resp.pyquery('h3:contains("Applications") + .button-paragraph').text() == application.name
|
||||
if icon:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img.application-icon')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img')) == 0
|
||||
assert 'Payers outside applications' in resp
|
||||
|
||||
# check application view
|
||||
resp = resp.click(application.name)
|
||||
assert resp.pyquery('h2').text() == application.name
|
||||
if icon:
|
||||
assert len(resp.pyquery('h2 img.application-logo')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('h2 img')) == 0
|
||||
assert len(resp.pyquery('ul.objects-list li')) == 2
|
||||
assert resp.pyquery('ul.objects-list li:nth-child(1)').text() == 'Payer 2 [identifier: payer-2]'
|
||||
assert resp.pyquery('ul.objects-list li:nth-child(2)').text() == 'Payer 3 [identifier: payer-3]'
|
||||
assert len(resp.pyquery('ul.objects-list li img')) == 0
|
||||
|
||||
# check elements outside applications
|
||||
resp = app.get('/manage/invoicing/payers/')
|
||||
resp = resp.click('Payers outside applications')
|
||||
assert resp.pyquery('h2').text() == 'Payers outside applications'
|
||||
assert len(resp.pyquery('ul.objects-list li')) == 1
|
||||
assert resp.pyquery('ul.objects-list li:nth-child(1)').text() == 'Payer 1 [identifier: payer-1]'
|
||||
|
||||
# check detail page
|
||||
resp = app.get('/manage/invoicing/payer/%s/' % payer1.pk)
|
||||
assert len(resp.pyquery('h3:contains("Applications")')) == 0
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph')) == 0
|
||||
resp = app.get('/manage/invoicing/payer/%s/' % payer2.pk)
|
||||
assert resp.pyquery('h3:contains("Applications") + .button-paragraph').text() == application.name
|
||||
if icon:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img.application-icon')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img')) == 0
|
||||
|
||||
# check visible flag
|
||||
application.visible = False
|
||||
application.save()
|
||||
resp = app.get('/manage/invoicing/payers/')
|
||||
assert len(resp.pyquery('h3:contains("Applications")')) == 0
|
||||
assert len(resp.pyquery('ul.objects-list img')) == 0
|
||||
app.get('/manage/invoicing/payers/?application=%s' % application.slug, status=404)
|
||||
resp = app.get('/manage/invoicing/payer/%s/' % payer2.pk)
|
||||
assert len(resp.pyquery('h3:contains("Applications")')) == 0
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph')) == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize('icon', [True, False])
|
||||
def test_regie(app, admin_user, application_with_icon, application_without_icon, icon):
|
||||
if icon:
|
||||
application = application_with_icon
|
||||
else:
|
||||
application = application_without_icon
|
||||
|
||||
regie1 = Regie.objects.create(label='Regie 1')
|
||||
regie2 = Regie.objects.create(label='Regie 2')
|
||||
ApplicationElement.objects.create(content_object=regie2, application=application)
|
||||
regie3 = Regie.objects.create(label='Regie 3')
|
||||
ApplicationElement.objects.create(content_object=regie3, application=application)
|
||||
|
||||
app = login(app)
|
||||
|
||||
resp = app.get('/manage/invoicing/regies/')
|
||||
assert len(resp.pyquery('ul.objects-list li')) == 3
|
||||
assert resp.pyquery('ul.objects-list li:nth-child(1)').text() == 'Regie 1 [identifier: regie-1]'
|
||||
assert resp.pyquery('ul.objects-list li:nth-child(2)').text() == 'Regie 2 [identifier: regie-2]'
|
||||
assert resp.pyquery('ul.objects-list li:nth-child(3)').text() == 'Regie 3 [identifier: regie-3]'
|
||||
if icon:
|
||||
assert len(resp.pyquery('ul.objects-list img')) == 2
|
||||
assert len(resp.pyquery('ul.objects-list li:nth-child(1) img')) == 0
|
||||
assert len(resp.pyquery('ul.objects-list li:nth-child(2) img.application-icon')) == 1
|
||||
assert len(resp.pyquery('ul.objects-list li:nth-child(3) img.application-icon')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('ul.objects-list img')) == 0
|
||||
assert resp.pyquery('h3:contains("Applications") + .button-paragraph').text() == application.name
|
||||
if icon:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img.application-icon')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img')) == 0
|
||||
assert 'Regies outside applications' in resp
|
||||
|
||||
# check application view
|
||||
resp = resp.click(application.name)
|
||||
assert resp.pyquery('h2').text() == application.name
|
||||
if icon:
|
||||
assert len(resp.pyquery('h2 img.application-logo')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('h2 img')) == 0
|
||||
assert len(resp.pyquery('ul.objects-list li')) == 2
|
||||
assert resp.pyquery('ul.objects-list li:nth-child(1)').text() == 'Regie 2 [identifier: regie-2]'
|
||||
assert resp.pyquery('ul.objects-list li:nth-child(2)').text() == 'Regie 3 [identifier: regie-3]'
|
||||
assert len(resp.pyquery('ul.objects-list li img')) == 0
|
||||
|
||||
# check elements outside applications
|
||||
resp = app.get('/manage/invoicing/regies/')
|
||||
resp = resp.click('Regies outside applications')
|
||||
assert resp.pyquery('h2').text() == 'Regies outside applications'
|
||||
assert len(resp.pyquery('ul.objects-list li')) == 1
|
||||
assert resp.pyquery('ul.objects-list li:nth-child(1)').text() == 'Regie 1 [identifier: regie-1]'
|
||||
|
||||
# check detail page
|
||||
resp = app.get('/manage/invoicing/regie/%s/' % regie1.pk)
|
||||
assert len(resp.pyquery('h3:contains("Applications")')) == 0
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph')) == 0
|
||||
resp = app.get('/manage/invoicing/regie/%s/' % regie2.pk)
|
||||
assert resp.pyquery('h3:contains("Applications") + .button-paragraph').text() == application.name
|
||||
if icon:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img.application-icon')) == 1
|
||||
else:
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph img')) == 0
|
||||
|
||||
# check visible flag
|
||||
application.visible = False
|
||||
application.save()
|
||||
resp = app.get('/manage/invoicing/regies/')
|
||||
assert len(resp.pyquery('h3:contains("Applications")')) == 0
|
||||
assert len(resp.pyquery('ul.objects-list img')) == 0
|
||||
app.get('/manage/invoicing/regies/?application=%s' % application.slug, status=404)
|
||||
resp = app.get('/manage/invoicing/regie/%s/' % regie2.pk)
|
||||
assert len(resp.pyquery('h3:contains("Applications")')) == 0
|
||||
assert len(resp.pyquery('h3:contains("Applications") + .button-paragraph')) == 0
|
Loading…
Reference in New Issue