lingo/lingo/pricing/views.py

954 lines
32 KiB
Python
Raw Normal View History

# lingo - payment and billing 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/>.
import datetime
import json
2022-05-13 11:17:18 +02:00
from collections import defaultdict
from operator import itemgetter
2022-05-13 11:17:18 +02:00
from django import forms
2022-05-19 17:39:54 +02:00
from django.contrib import messages
from django.db.models import Prefetch
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect
from django.shortcuts import get_object_or_404
2022-05-19 17:39:54 +02:00
from django.urls import reverse, reverse_lazy
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ungettext
from django.views.generic import (
CreateView,
DeleteView,
DetailView,
FormView,
ListView,
RedirectView,
UpdateView,
)
from django.views.generic.detail import SingleObjectMixin
from lingo.agendas.chrono import refresh_agendas
2022-05-23 09:57:50 +02:00
from lingo.agendas.models import Agenda, CheckType, CheckTypeGroup
from lingo.agendas.views import AgendaMixin
from lingo.pricing.forms import (
AgendaPricingForm,
2022-05-23 09:57:50 +02:00
CheckTypeForm,
CriteriaForm,
2022-05-19 17:39:54 +02:00
ExportForm,
ImportForm,
2022-05-23 09:57:50 +02:00
NewCheckTypeForm,
NewCriteriaForm,
PricingCriteriaCategoryAddForm,
PricingCriteriaCategoryEditForm,
PricingDuplicateForm,
2022-05-13 11:17:18 +02:00
PricingMatrixForm,
PricingVariableFormSet,
)
from lingo.pricing.models import AgendaPricing, Criteria, CriteriaCategory, Pricing, PricingCriteriaCategory
2022-05-19 17:39:54 +02:00
from lingo.pricing.utils import export_site, import_site
from lingo.utils.misc import AgendaImportError
class ConfigExportView(FormView):
form_class = ExportForm
template_name = 'lingo/pricing/export.html'
def form_valid(self, form):
response = HttpResponse(content_type='application/json')
today = datetime.date.today()
response['Content-Disposition'] = 'attachment; filename="export_pricing_config_{}.json"'.format(
today.strftime('%Y%m%d')
)
json.dump(export_site(**form.cleaned_data), response, indent=2)
return response
config_export = ConfigExportView.as_view()
class ConfigImportView(FormView):
form_class = ImportForm
template_name = 'lingo/pricing/import.html'
success_url = reverse_lazy('lingo-manager-pricing-list')
def form_valid(self, form):
try:
config_json = json.loads(force_text(self.request.FILES['config_json'].read()))
except ValueError:
form.add_error('config_json', _('File is not in the expected JSON format.'))
return self.form_invalid(form)
try:
results = import_site(config_json, overwrite=False)
except AgendaImportError as exc:
form.add_error('config_json', '%s' % exc)
return self.form_invalid(form)
except KeyError as exc:
form.add_error('config_json', _('Key "%s" is missing.') % exc.args[0])
return self.form_invalid(form)
import_messages = {
'agendas': {
'update_noop': _('No agenda updated.'),
'update': lambda x: ungettext(
'An agenda has been updated.',
'%(count)d agendas have been updated.',
x,
),
},
'check_type_groups': {
'create_noop': _('No check type group created.'),
'create': lambda x: ungettext(
'A check type group has been created.',
'%(count)d check type groups have been created.',
x,
),
'update_noop': _('No check type group updated.'),
'update': lambda x: ungettext(
'A check type group has been updated.',
'%(count)d check type groups have been updated.',
x,
),
},
2022-05-19 17:39:54 +02:00
'pricing_categories': {
'create_noop': _('No pricing criteria category created.'),
'create': lambda x: ungettext(
'A pricing criteria category has been created.',
'%(count)d pricing criteria categories have been created.',
x,
),
'update_noop': _('No pricing criteria category updated.'),
'update': lambda x: ungettext(
'A pricing criteria category has been updated.',
'%(count)d pricing criteria categories have been updated.',
x,
),
},
'pricing_models': {
'create_noop': _('No pricing model created.'),
'create': lambda x: ungettext(
'A pricing model has been created.',
'%(count)d pricing models have been created.',
x,
),
'update_noop': _('No pricing model updated.'),
'update': lambda x: ungettext(
'A pricing model has been updated.',
'%(count)d pricing models have been updated.',
x,
),
},
}
global_noop = True
for obj_name, obj_results in results.items():
if obj_results['all']:
global_noop = False
count = len(obj_results['created'])
if not count:
message1 = import_messages[obj_name].get('create_noop')
2022-05-19 17:39:54 +02:00
else:
message1 = import_messages[obj_name]['create'](count) % {'count': count}
count = len(obj_results['updated'])
if not count:
message2 = import_messages[obj_name]['update_noop']
else:
message2 = import_messages[obj_name]['update'](count) % {'count': count}
obj_results['messages'] = "%s %s" % (message1, message2)
a_count, ct_count, pc_count, pm_count = (
len(results['agendas']['all']),
len(results['check_type_groups']['all']),
2022-05-19 17:39:54 +02:00
len(results['pricing_categories']['all']),
len(results['pricing_models']['all']),
)
if (a_count, ct_count, pc_count, pm_count) == (1, 0, 0, 0):
# only one agenda imported, redirect to agenda page
return HttpResponseRedirect(
reverse(
'lingo-manager-agenda-detail',
kwargs={'pk': results['agendas']['all'][0].pk},
)
)
if (a_count, ct_count, pc_count, pm_count) == (0, 1, 0, 0):
# only one check type group imported, redirect to check type page
return HttpResponseRedirect(reverse('lingo-manager-check-type-list'))
if (a_count, ct_count, pc_count, pm_count) == (0, 0, 1, 0):
2022-05-19 17:39:54 +02:00
# only one criteria category imported, redirect to criteria page
return HttpResponseRedirect(reverse('lingo-manager-pricing-criteria-list'))
if (a_count, ct_count, pc_count, pm_count) == (0, 0, 0, 1):
2022-05-19 17:39:54 +02:00
# only one pricing imported, redirect to pricing page
return HttpResponseRedirect(
reverse(
'lingo-manager-pricing-detail',
kwargs={'pk': results['pricing_models']['all'][0].pk},
)
)
if global_noop:
messages.info(self.request, _('No data found.'))
else:
messages.info(self.request, results['agendas']['messages'])
messages.info(self.request, results['check_type_groups']['messages'])
2022-05-19 17:39:54 +02:00
messages.info(self.request, results['pricing_categories']['messages'])
messages.info(self.request, results['pricing_models']['messages'])
return super().form_valid(form)
config_import = ConfigImportView.as_view()
class PricingListView(ListView):
template_name = 'lingo/pricing/manager_pricing_list.html'
model = Pricing
pricing_list = PricingListView.as_view()
class CriteriaListView(ListView):
template_name = 'lingo/pricing/manager_criteria_list.html'
model = CriteriaCategory
def get_queryset(self):
return CriteriaCategory.objects.prefetch_related('criterias')
criteria_list = CriteriaListView.as_view()
class PricingAddView(CreateView):
template_name = 'lingo/pricing/manager_pricing_form.html'
model = Pricing
fields = ['label']
def get_success_url(self):
return reverse('lingo-manager-pricing-detail', args=[self.object.pk])
pricing_add = PricingAddView.as_view()
class PricingDetailView(DetailView):
template_name = 'lingo/pricing/manager_pricing_detail.html'
model = Pricing
def get_queryset(self):
return (
super()
.get_queryset()
.prefetch_related(
Prefetch(
'categories', queryset=CriteriaCategory.objects.order_by('pricingcriteriacategory__order')
)
)
)
def get_context_data(self, **kwargs):
kwargs['agendas'] = Agenda.objects.filter(
pk__in=AgendaPricing.objects.filter(pricing=self.object).values('agenda')
)
return super().get_context_data(**kwargs)
pricing_detail = PricingDetailView.as_view()
class PricingEditView(UpdateView):
template_name = 'lingo/pricing/manager_pricing_form.html'
model = Pricing
fields = ['label', 'slug']
def get_success_url(self):
return reverse('lingo-manager-pricing-detail', args=[self.object.pk])
pricing_edit = PricingEditView.as_view()
class PricingDeleteView(DeleteView):
template_name = 'lingo/manager_confirm_delete.html'
model = Pricing
def get_success_url(self):
return reverse('lingo-manager-pricing-list')
pricing_delete = PricingDeleteView.as_view()
class PricingDuplicate(SingleObjectMixin, FormView):
template_name = 'lingo/pricing/manager_pricing_duplicate_form.html'
model = Pricing
form_class = PricingDuplicateForm
def dispatch(self, request, *args, **kwargs):
self.object = self.get_object()
return super().dispatch(request, *args, **kwargs)
def get_success_url(self):
return reverse('lingo-manager-pricing-detail', kwargs={'pk': self.new_pricing.pk})
def form_valid(self, form):
self.new_pricing = self.object.duplicate(label=form.cleaned_data['label'])
return super().form_valid(form)
pricing_duplicate = PricingDuplicate.as_view()
class PricingExport(DetailView):
model = Pricing
def get(self, request, *args, **kwargs):
response = HttpResponse(content_type='application/json')
today = datetime.date.today()
attachment = 'attachment; filename="export_pricing_{}_{}.json"'.format(
self.get_object().slug, today.strftime('%Y%m%d')
)
response['Content-Disposition'] = attachment
json.dump({'pricing_models': [self.get_object().export_json()]}, response, indent=2)
return response
pricing_export = PricingExport.as_view()
class PricingVariableEdit(FormView):
template_name = 'lingo/pricing/manager_pricing_variable_form.html'
model = Pricing
form_class = PricingVariableFormSet
def dispatch(self, request, *args, **kwargs):
self.object = get_object_or_404(Pricing, pk=kwargs['pk'])
return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
kwargs['object'] = self.object
return super().get_context_data(**kwargs)
def get_initial(self):
return sorted(
({'key': k, 'value': v} for k, v in self.object.extra_variables.items()),
key=itemgetter('key'),
)
def form_valid(self, form):
self.object.extra_variables = {}
for sub_data in form.cleaned_data:
if not sub_data.get('key'):
continue
self.object.extra_variables[sub_data['key']] = sub_data['value']
self.object.save()
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse('lingo-manager-pricing-detail', args=[self.object.pk])
pricing_variable_edit = PricingVariableEdit.as_view()
class PricingCriteriaCategoryAddView(FormView):
template_name = 'lingo/pricing/manager_pricing_criteria_category_form.html'
model = Pricing
form_class = PricingCriteriaCategoryAddForm
def dispatch(self, request, *args, **kwargs):
self.object = get_object_or_404(Pricing, pk=kwargs['pk'])
if self.object.categories.count() >= 3:
raise Http404
return super().dispatch(request, *args, **kwargs)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['pricing'] = self.object
return kwargs
def get_context_data(self, **kwargs):
kwargs['object'] = self.object
return super().get_context_data(**kwargs)
def form_valid(self, form):
PricingCriteriaCategory.objects.create(pricing=self.object, category=form.cleaned_data['category'])
return super().form_valid(form)
def get_success_url(self):
return reverse('lingo-manager-pricing-detail', args=[self.object.pk])
pricing_criteria_category_add = PricingCriteriaCategoryAddView.as_view()
class PricingCriteriaCategoryEditView(FormView):
template_name = 'lingo/pricing/manager_pricing_criteria_category_form.html'
model = Pricing
form_class = PricingCriteriaCategoryEditForm
def dispatch(self, request, *args, **kwargs):
self.object = get_object_or_404(Pricing, pk=kwargs['pk'])
self.category = get_object_or_404(self.object.categories, pk=kwargs['category_pk'])
return super().dispatch(request, *args, **kwargs)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['pricing'] = self.object
kwargs['category'] = self.category
return kwargs
def get_context_data(self, **kwargs):
kwargs['object'] = self.object
kwargs['category'] = self.category
return super().get_context_data(**kwargs)
def form_valid(self, form):
old_criterias = self.object.criterias.filter(category=self.category)
new_criterias = form.cleaned_data['criterias']
removed_criterias = set(old_criterias) - set(new_criterias)
self.object.criterias.remove(*removed_criterias)
self.object.criterias.add(*new_criterias)
return super().form_valid(form)
def get_success_url(self):
return reverse('lingo-manager-pricing-detail', args=[self.object.pk])
pricing_criteria_category_edit = PricingCriteriaCategoryEditView.as_view()
class PricingCriteriaCategoryDeleteView(DeleteView):
template_name = 'lingo/manager_confirm_delete.html'
model = CriteriaCategory
pk_url_kwarg = 'category_pk'
def dispatch(self, request, *args, **kwargs):
self.pricing = get_object_or_404(Pricing, pk=kwargs['pk'])
return super().dispatch(request, *args, **kwargs)
def get_queryset(self):
return self.pricing.categories.all()
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
self.pricing.categories.remove(self.object)
self.pricing.criterias.remove(*self.pricing.criterias.filter(category=self.object))
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse('lingo-manager-pricing-detail', args=[self.pricing.pk])
pricing_criteria_category_delete = PricingCriteriaCategoryDeleteView.as_view()
class PricingCriteriaCategoryOrder(DetailView):
model = Pricing
def get(self, request, *args, **kwargs):
if 'new-order' not in request.GET:
return HttpResponseBadRequest('missing new-order parameter')
pricing = self.get_object()
try:
new_order = [int(x) for x in request.GET['new-order'].split(',')]
except ValueError:
return HttpResponseBadRequest('incorrect new-order parameter')
categories = pricing.categories.all()
if set(new_order) != {x.pk for x in categories} or len(new_order) != len(categories):
return HttpResponseBadRequest('incorrect new-order parameter')
for i, c_id in enumerate(new_order):
PricingCriteriaCategory.objects.filter(pricing=pricing, category=c_id).update(order=i + 1)
return HttpResponse(status=204)
pricing_criteria_category_order = PricingCriteriaCategoryOrder.as_view()
class CriteriaCategoryAddView(CreateView):
template_name = 'lingo/pricing/manager_criteria_category_form.html'
model = CriteriaCategory
fields = ['label']
def get_success_url(self):
return reverse('lingo-manager-pricing-criteria-list')
criteria_category_add = CriteriaCategoryAddView.as_view()
class CriteriaCategoryEditView(UpdateView):
template_name = 'lingo/pricing/manager_criteria_category_form.html'
model = CriteriaCategory
fields = ['label', 'slug']
def get_success_url(self):
return reverse('lingo-manager-pricing-criteria-list')
criteria_category_edit = CriteriaCategoryEditView.as_view()
class CriteriaCategoryDeleteView(DeleteView):
template_name = 'lingo/manager_confirm_delete.html'
model = CriteriaCategory
def get_success_url(self):
return reverse('lingo-manager-pricing-criteria-list')
criteria_category_delete = CriteriaCategoryDeleteView.as_view()
class CriteriaCategoryExport(DetailView):
model = CriteriaCategory
def get(self, request, *args, **kwargs):
response = HttpResponse(content_type='application/json')
today = datetime.date.today()
attachment = 'attachment; filename="export_pricing_category_{}_{}.json"'.format(
self.get_object().slug, today.strftime('%Y%m%d')
)
response['Content-Disposition'] = attachment
json.dump({'pricing_categories': [self.get_object().export_json()]}, response, indent=2)
return response
criteria_category_export = CriteriaCategoryExport.as_view()
class CriteriaOrder(DetailView):
model = CriteriaCategory
def get(self, request, *args, **kwargs):
if 'new-order' not in request.GET:
return HttpResponseBadRequest('missing new-order parameter')
category = self.get_object()
try:
new_order = [int(x) for x in request.GET['new-order'].split(',')]
except ValueError:
return HttpResponseBadRequest('incorrect new-order parameter')
criterias = category.criterias.filter(default=False)
if set(new_order) != {x.pk for x in criterias} or len(new_order) != len(criterias):
return HttpResponseBadRequest('incorrect new-order parameter')
criterias_by_id = {c.pk: c for c in criterias}
for i, c_id in enumerate(new_order):
criterias_by_id[c_id].order = i + 1
criterias_by_id[c_id].save()
return HttpResponse(status=204)
criteria_order = CriteriaOrder.as_view()
class CriteriaAddView(CreateView):
template_name = 'lingo/pricing/manager_criteria_form.html'
model = Criteria
form_class = NewCriteriaForm
def dispatch(self, request, *args, **kwargs):
self.category_pk = kwargs.pop('category_pk')
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('lingo-manager-pricing-criteria-list')
criteria_add = CriteriaAddView.as_view()
class CriteriaEditView(UpdateView):
template_name = 'lingo/pricing/manager_criteria_form.html'
model = Criteria
form_class = CriteriaForm
def dispatch(self, request, *args, **kwargs):
self.category_pk = kwargs.pop('category_pk')
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('lingo-manager-pricing-criteria-list')
criteria_edit = CriteriaEditView.as_view()
class CriteriaDeleteView(DeleteView):
template_name = 'lingo/manager_confirm_delete.html'
model = Criteria
def dispatch(self, request, *args, **kwargs):
self.category_pk = kwargs.pop('category_pk')
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('lingo-manager-pricing-criteria-list')
criteria_delete = CriteriaDeleteView.as_view()
class AgendaListView(ListView):
template_name = 'lingo/pricing/manager_agenda_list.html'
model = Agenda
def get_queryset(self):
queryset = super().get_queryset()
return queryset.order_by('category_label', 'label')
agenda_list = AgendaListView.as_view()
class AgendaSyncView(RedirectView):
def get(self, request, *args, **kwargs):
refresh_agendas()
messages.info(self.request, _('Agendas refreshed.'))
return super().get(request, *args, **kwargs)
def get_redirect_url(self, *args, **kwargs):
return reverse('lingo-manager-agenda-list')
agenda_sync = AgendaSyncView.as_view()
class AgendaDetailView(AgendaMixin, DetailView):
template_name = 'lingo/pricing/manager_agenda_detail.html'
model = Agenda
def get_context_data(self, **kwargs):
kwargs['agenda_pricings'] = (
AgendaPricing.objects.filter(agenda=self.agenda)
.select_related('pricing')
.order_by('date_start', 'date_end')
)
return super().get_context_data(**kwargs)
agenda_detail = AgendaDetailView.as_view()
class AgendaDetailRedirectView(RedirectView):
def get_redirect_url(self, *args, **kwargs):
agenda = get_object_or_404(Agenda, slug=kwargs['slug'])
return reverse('lingo-manager-agenda-detail', kwargs={'pk': agenda.pk})
agenda_detail_redirect = AgendaDetailRedirectView.as_view()
class AgendaExport(AgendaMixin, DetailView):
model = Agenda
def get(self, request, *args, **kwargs):
response = HttpResponse(content_type='application/json')
today = datetime.date.today()
response['Content-Disposition'] = 'attachment; filename="export_pricing_agenda_{}_{}.json"'.format(
self.get_object().slug, today.strftime('%Y%m%d')
)
json.dump({'agendas': [self.get_object().export_json()]}, response, indent=2)
return response
agenda_export = AgendaExport.as_view()
class AgendaBookingCheckSettingsView(AgendaMixin, UpdateView):
template_name = 'lingo/pricing/manager_agenda_form.html'
model = Agenda
fields = ['check_type_group']
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form_url'] = reverse('lingo-manager-agenda-booking-check-settings', args=[self.agenda.pk])
context['title'] = _("Configure booking check options")
return context
agenda_booking_check_settings = AgendaBookingCheckSettingsView.as_view()
class AgendaPricingAddView(AgendaMixin, CreateView):
template_name = 'lingo/pricing/manager_agenda_pricing_form.html'
model = AgendaPricing
form_class = AgendaPricingForm
def get_success_url(self):
return reverse('lingo-manager-agenda-pricing-detail', args=[self.agenda.pk, self.object.pk])
agenda_pricing_add = AgendaPricingAddView.as_view()
class AgendaPricingDetailView(AgendaMixin, DetailView):
model = AgendaPricing
pk_url_kwarg = 'pricing_pk'
template_name = 'lingo/pricing/manager_agenda_pricing_detail.html'
def get_queryset(self):
return AgendaPricing.objects.filter(agenda=self.agenda).prefetch_related(
'pricing__criterias__category'
)
agenda_pricing_detail = AgendaPricingDetailView.as_view()
class AgendaPricingEditView(AgendaMixin, UpdateView):
template_name = 'lingo/pricing/manager_agenda_pricing_form.html'
model = AgendaPricing
pk_url_kwarg = 'pricing_pk'
form_class = AgendaPricingForm
def get_queryset(self):
return AgendaPricing.objects.filter(agenda=self.agenda)
def get_success_url(self):
return reverse('lingo-manager-agenda-pricing-detail', args=[self.agenda.pk, self.object.pk])
agenda_pricing_edit = AgendaPricingEditView.as_view()
class AgendaPricingDeleteView(AgendaMixin, DeleteView):
template_name = 'lingo/manager_confirm_delete.html'
model = AgendaPricing
pk_url_kwarg = 'pricing_pk'
def get_queryset(self):
return AgendaPricing.objects.filter(agenda=self.agenda)
agenda_pricing_delete = AgendaPricingDeleteView.as_view()
2022-05-13 11:17:18 +02:00
class AgendaPricingMatrixEdit(AgendaMixin, FormView):
template_name = 'lingo/pricing/manager_agenda_pricing_matrix_form.html'
2022-05-13 11:17:18 +02:00
def set_agenda(self, **kwargs):
super().set_agenda(**kwargs)
2022-05-13 11:17:18 +02:00
self.object = get_object_or_404(
AgendaPricing.objects.filter(agenda=self.agenda), pk=kwargs['pricing_pk']
)
matrix_list = list(self.object.iter_pricing_matrix())
if not matrix_list:
raise Http404
self.matrix = None
if kwargs.get('slug'):
for matrix in matrix_list:
if matrix.criteria is None:
continue
if matrix.criteria.slug == kwargs['slug']:
self.matrix = matrix
break
else:
if matrix_list[0].criteria is None:
self.matrix = matrix_list[0]
if self.matrix is None:
raise Http404
def get_context_data(self, **kwargs):
kwargs['object'] = self.object
kwargs['matrix'] = self.matrix
return super().get_context_data(**kwargs)
def get_form(self):
count = len(self.matrix.rows)
PricingMatrixFormSet = forms.formset_factory(
PricingMatrixForm, min_num=count, max_num=count, extra=0, can_delete=False
)
kwargs = {
'initial': [
{'crit_%i' % i: cell.value for i, cell in enumerate(row.cells)} for row in self.matrix.rows
]
}
if self.request.method == 'POST':
kwargs.update(
{
'data': self.request.POST,
}
)
return PricingMatrixFormSet(form_kwargs={'matrix': self.matrix}, **kwargs)
def post(self, *args, **kwargs):
form = self.get_form()
if form.is_valid():
# build prixing_data for this matrix
matrix_pricing_data = defaultdict(dict)
for i, sub_data in enumerate(form.cleaned_data):
row = self.matrix.rows[i]
for j, cell in enumerate(row.cells):
value = sub_data['crit_%s' % j]
key = cell.criteria.identifier if cell.criteria else None
matrix_pricing_data[key][row.criteria.identifier] = float(value)
if self.matrix.criteria:
# full pricing model with 3 categories
self.object.pricing_data = self.object.pricing_data or {}
self.object.pricing_data[self.matrix.criteria.identifier] = matrix_pricing_data
elif list(matrix_pricing_data.keys()) == [None]:
# only one category
self.object.pricing_data = matrix_pricing_data[None]
else:
# 2 categories
self.object.pricing_data = matrix_pricing_data
self.object.save()
return self.form_valid(form)
else:
return self.form_invalid(form)
def get_success_url(self):
return reverse('lingo-manager-agenda-pricing-detail', args=[self.agenda.pk, self.object.pk])
2022-05-13 11:17:18 +02:00
agenda_pricing_matrix_edit = AgendaPricingMatrixEdit.as_view()
2022-05-23 09:57:50 +02:00
class CheckTypeListView(ListView):
template_name = 'lingo/pricing/manager_check_type_list.html'
model = CheckTypeGroup
def get_queryset(self):
return CheckTypeGroup.objects.prefetch_related('check_types')
check_type_list = CheckTypeListView.as_view()
class CheckTypeGroupAddView(CreateView):
template_name = 'lingo/pricing/manager_check_type_group_form.html'
model = CheckTypeGroup
fields = ['label']
def get_success_url(self):
return reverse('lingo-manager-check-type-list')
check_type_group_add = CheckTypeGroupAddView.as_view()
class CheckTypeGroupEditView(UpdateView):
template_name = 'lingo/pricing/manager_check_type_group_form.html'
model = CheckTypeGroup
fields = ['label', 'slug']
def get_success_url(self):
return reverse('lingo-manager-check-type-list')
check_type_group_edit = CheckTypeGroupEditView.as_view()
class CheckTypeGroupDeleteView(DeleteView):
template_name = 'lingo/manager_confirm_delete.html'
model = CheckTypeGroup
def get_success_url(self):
return reverse('lingo-manager-check-type-list')
check_type_group_delete = CheckTypeGroupDeleteView.as_view()
class CheckTypeGroupExport(DetailView):
model = CheckTypeGroup
def get(self, request, *args, **kwargs):
response = HttpResponse(content_type='application/json')
today = datetime.date.today()
attachment = 'attachment; filename="export_check_type_group_{}_{}.json"'.format(
self.get_object().slug, today.strftime('%Y%m%d')
)
response['Content-Disposition'] = attachment
json.dump({'check_type_groups': [self.get_object().export_json()]}, response, indent=2)
return response
check_type_group_export = CheckTypeGroupExport.as_view()
class CheckTypeAddView(CreateView):
template_name = 'lingo/pricing/manager_check_type_form.html'
model = CheckType
form_class = NewCheckTypeForm
def dispatch(self, request, *args, **kwargs):
self.group_pk = kwargs.pop('group_pk')
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'].group_id = self.group_pk
return kwargs
def get_success_url(self):
return reverse('lingo-manager-check-type-list')
check_type_add = CheckTypeAddView.as_view()
class CheckTypeEditView(UpdateView):
template_name = 'lingo/pricing/manager_check_type_form.html'
model = CheckType
form_class = CheckTypeForm
def dispatch(self, request, *args, **kwargs):
self.group_pk = kwargs.pop('group_pk')
return super().dispatch(request, *args, **kwargs)
def get_queryset(self):
return CheckType.objects.filter(group=self.group_pk)
def get_success_url(self):
return reverse('lingo-manager-check-type-list')
check_type_edit = CheckTypeEditView.as_view()
class CheckTypeDeleteView(DeleteView):
template_name = 'lingo/manager_confirm_delete.html'
model = CheckType
def dispatch(self, request, *args, **kwargs):
self.group_pk = kwargs.pop('group_pk')
return super().dispatch(request, *args, **kwargs)
def get_queryset(self):
return CheckType.objects.filter(group=self.group_pk)
def get_success_url(self):
return reverse('lingo-manager-check-type-list')
check_type_delete = CheckTypeDeleteView.as_view()