lingo/lingo/pricing/views.py

954 lines
32 KiB
Python

# 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
from collections import defaultdict
from operator import itemgetter
from django import forms
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
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
from lingo.agendas.models import Agenda, CheckType, CheckTypeGroup
from lingo.agendas.views import AgendaMixin
from lingo.pricing.forms import (
AgendaPricingForm,
CheckTypeForm,
CriteriaForm,
ExportForm,
ImportForm,
NewCheckTypeForm,
NewCriteriaForm,
PricingCriteriaCategoryAddForm,
PricingCriteriaCategoryEditForm,
PricingDuplicateForm,
PricingMatrixForm,
PricingVariableFormSet,
)
from lingo.pricing.models import AgendaPricing, Criteria, CriteriaCategory, Pricing, PricingCriteriaCategory
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,
),
},
'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')
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']),
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):
# 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):
# 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'])
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()
class AgendaPricingMatrixEdit(AgendaMixin, FormView):
template_name = 'lingo/pricing/manager_agenda_pricing_matrix_form.html'
def set_agenda(self, **kwargs):
super().set_agenda(**kwargs)
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])
agenda_pricing_matrix_edit = AgendaPricingMatrixEdit.as_view()
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()