lingo/lingo/invoicing/views/regie.py

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()