266 lines
9.0 KiB
Python
266 lines
9.0 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 collections
|
|
import datetime
|
|
import json
|
|
|
|
from django.db import transaction
|
|
from django.db.models import CharField, IntegerField, JSONField, Value
|
|
from django.http import HttpResponse
|
|
from django.shortcuts import get_object_or_404
|
|
from django.urls import reverse
|
|
from django.views.generic import CreateView, DeleteView, DetailView, ListView, UpdateView
|
|
|
|
from lingo.agendas.models import Agenda
|
|
from lingo.invoicing.forms import RegieForm, RegieInvoiceFilterSet
|
|
from lingo.invoicing.models import Counter, InjectedLine, Invoice, InvoiceLine, InvoicePayment, Pool, Regie
|
|
from lingo.invoicing.views.utils import PDFMixin
|
|
|
|
|
|
def import_regies(data):
|
|
results = collections.defaultdict(list)
|
|
with transaction.atomic():
|
|
regies = data.get('regies', [])
|
|
for regie in regies:
|
|
created, regie_obj = Regie.import_json(regie)
|
|
if created:
|
|
results['created'].append(regie_obj)
|
|
else:
|
|
results['updated'].append(regie_obj)
|
|
return results
|
|
|
|
|
|
class RegiesListView(ListView):
|
|
template_name = 'lingo/invoicing/manager_regie_list.html'
|
|
model = Regie
|
|
|
|
|
|
regies_list = RegiesListView.as_view()
|
|
|
|
|
|
class RegieAddView(CreateView):
|
|
template_name = 'lingo/invoicing/manager_regie_form.html'
|
|
model = Regie
|
|
fields = ['label', 'description', 'cashier_role']
|
|
|
|
def get_success_url(self):
|
|
return reverse('lingo-manager-invoicing-regie-detail', args=[self.object.pk])
|
|
|
|
|
|
regie_add = RegieAddView.as_view()
|
|
|
|
|
|
class RegieDetailView(DetailView):
|
|
template_name = 'lingo/invoicing/manager_regie_detail.html'
|
|
model = Regie
|
|
|
|
def get_context_data(self, **kwargs):
|
|
kwargs['regie'] = self.object
|
|
kwargs['agendas'] = Agenda.objects.filter(regie=self.object)
|
|
kwargs['campaigns'] = self.object.campaign_set.all().order_by('-date_start')
|
|
has_related_objects = False
|
|
if kwargs['campaigns']:
|
|
has_related_objects = True
|
|
elif self.object.injectedline_set.exists():
|
|
has_related_objects = True
|
|
kwargs['has_related_objects'] = has_related_objects
|
|
return super().get_context_data(**kwargs)
|
|
|
|
|
|
regie_detail = RegieDetailView.as_view()
|
|
|
|
|
|
class RegieEditView(UpdateView):
|
|
template_name = 'lingo/invoicing/manager_regie_form.html'
|
|
model = Regie
|
|
form_class = RegieForm
|
|
|
|
def get_success_url(self):
|
|
return reverse('lingo-manager-invoicing-regie-detail', args=[self.object.pk])
|
|
|
|
|
|
regie_edit = RegieEditView.as_view()
|
|
|
|
|
|
class RegieDeleteView(DeleteView):
|
|
template_name = 'lingo/manager_confirm_delete.html'
|
|
model = Regie
|
|
|
|
def get_queryset(self):
|
|
return super().get_queryset().filter(campaign__isnull=True, injectedline__isnull=True)
|
|
|
|
def delete(self, request, *args, **kwargs):
|
|
self.object = self.get_object()
|
|
Counter.objects.filter(regie=self.object).delete()
|
|
return super().delete(request, *args, **kwargs)
|
|
|
|
def get_success_url(self):
|
|
return reverse('lingo-manager-invoicing-regie-list')
|
|
|
|
|
|
regie_delete = RegieDeleteView.as_view()
|
|
|
|
|
|
class RegieExport(DetailView):
|
|
model = Regie
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
response = HttpResponse(content_type='application/json')
|
|
today = datetime.date.today()
|
|
attachment = 'attachment; filename="export_regie_{}_{}.json"'.format(
|
|
self.get_object().slug, today.strftime('%Y%m%d')
|
|
)
|
|
response['Content-Disposition'] = attachment
|
|
json.dump({'regies': [self.get_object().export_json()]}, response, indent=2)
|
|
return response
|
|
|
|
|
|
regie_export = RegieExport.as_view()
|
|
|
|
|
|
class NonInvoicedLineListView(ListView):
|
|
template_name = 'lingo/invoicing/manager_non_invoiced_line_list.html'
|
|
paginate_by = 100
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
self.regie = get_object_or_404(Regie, pk=kwargs['regie_pk'])
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
def get_queryset(self):
|
|
fields = [
|
|
'pk',
|
|
'event_date',
|
|
'slug',
|
|
'label',
|
|
'quantity',
|
|
'unit_amount',
|
|
'total_amount',
|
|
'user_external_id',
|
|
'payer_external_id',
|
|
'payer_first_name',
|
|
'payer_last_name',
|
|
'user_first_name',
|
|
'user_last_name',
|
|
'event',
|
|
'pricing_data',
|
|
'status',
|
|
'pool_id',
|
|
]
|
|
qs1 = InvoiceLine.objects.filter(
|
|
status='error', error_status='', pool__campaign__regie=self.regie
|
|
).values(*fields)
|
|
qs2 = (
|
|
InjectedLine.objects.filter(invoiceline__isnull=True, regie=self.regie)
|
|
.annotate(
|
|
user_first_name=Value('', output_field=CharField()),
|
|
user_last_name=Value('', output_field=CharField()),
|
|
event=Value({}, output_field=JSONField()),
|
|
pricing_data=Value({}, output_field=JSONField()),
|
|
status=Value('injected', output_field=CharField()),
|
|
pool_id=Value(0, output_field=IntegerField()),
|
|
)
|
|
.values(*fields)
|
|
)
|
|
qs = qs1.union(qs2).order_by('event_date', 'user_external_id', 'label', 'pk')
|
|
return qs
|
|
|
|
def get_context_data(self, **kwargs):
|
|
kwargs['regie'] = self.regie
|
|
context = super().get_context_data(**kwargs)
|
|
pools = Pool.objects.filter(draft=False).in_bulk()
|
|
for line in context['object_list']:
|
|
if line['status'] == 'error':
|
|
line['user_name'] = InvoiceLine(
|
|
user_first_name=line['user_first_name'], user_last_name=line['user_last_name']
|
|
).user_name
|
|
line['payer_name'] = InvoiceLine(
|
|
payer_first_name=line['payer_first_name'], payer_last_name=line['payer_last_name']
|
|
).payer_name
|
|
line['error_display'] = InvoiceLine(
|
|
status=line['status'], pricing_data=line['pricing_data']
|
|
).get_error_display()
|
|
line['campaign_id'] = pools[line['pool_id']].campaign_id
|
|
line['chrono_event_url'] = InvoiceLine(event=line['event']).get_chrono_event_url()
|
|
return context
|
|
|
|
|
|
non_invoiced_line_list = NonInvoicedLineListView.as_view()
|
|
|
|
|
|
class RegieInvoiceListView(ListView):
|
|
template_name = 'lingo/invoicing/manager_invoice_list.html'
|
|
paginate_by = 100
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
self.regie = get_object_or_404(Regie, pk=kwargs['regie_pk'])
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
def get_queryset(self):
|
|
self.filterset = RegieInvoiceFilterSet(
|
|
data=self.request.GET or None,
|
|
queryset=Invoice.objects.filter(regie=self.regie).prefetch_related('pool').order_by('created_at'),
|
|
)
|
|
return self.filterset.qs
|
|
|
|
def get_context_data(self, **kwargs):
|
|
kwargs['regie'] = self.regie
|
|
kwargs['filterset'] = self.filterset
|
|
return super().get_context_data(**kwargs)
|
|
|
|
|
|
regie_invoice_list = RegieInvoiceListView.as_view()
|
|
|
|
|
|
class RegieInvoicePDFView(PDFMixin, DetailView):
|
|
pk_url_kwarg = 'invoice_pk'
|
|
model = Invoice
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
self.regie = get_object_or_404(Regie, pk=kwargs['regie_pk'])
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
def get_queryset(self):
|
|
return super().get_queryset().filter(regie=self.regie)
|
|
|
|
|
|
regie_invoice_pdf = RegieInvoicePDFView.as_view()
|
|
|
|
|
|
class RegieInvoiceLineListView(ListView):
|
|
template_name = 'lingo/invoicing/manager_invoice_lines.html'
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
self.regie = get_object_or_404(Regie, pk=kwargs['regie_pk'])
|
|
self.invoice = get_object_or_404(Invoice, pk=kwargs['invoice_pk'], regie=self.regie)
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
def get_queryset(self):
|
|
return self.invoice.lines.all().order_by('user_external_id', 'event_date', 'pk')
|
|
|
|
def get_context_data(self, **kwargs):
|
|
kwargs['regie'] = self.regie
|
|
kwargs['invoice'] = self.invoice
|
|
kwargs['invoice_payments'] = (
|
|
InvoicePayment.objects.filter(invoice=self.invoice)
|
|
.select_related('payment')
|
|
.order_by('created_at')
|
|
)
|
|
return super().get_context_data(**kwargs)
|
|
|
|
|
|
regie_invoice_line_list = RegieInvoiceLineListView.as_view()
|