forked from CGM_Public/pretix_original
Create invoice exporter mixin (#1725)
* Create invoice exporter mixin * code style
This commit is contained in:
@@ -1,89 +1,32 @@
|
|||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
from decimal import Decimal
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
|
|
||||||
import dateutil.parser
|
import dateutil.parser
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.db.models import Exists, OuterRef, Q
|
from django.db.models import CharField, Exists, F, OuterRef, Q, Subquery, Sum
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.formats import date_format
|
||||||
|
from django.utils.functional import cached_property
|
||||||
|
from django.utils.translation import gettext, gettext_lazy as _, pgettext
|
||||||
|
|
||||||
from pretix.base.models import Invoice, OrderPayment
|
from pretix.base.models import Invoice, InvoiceLine, OrderPayment
|
||||||
|
|
||||||
from ...control.forms.filter import get_all_payment_providers
|
from ...control.forms.filter import get_all_payment_providers
|
||||||
from ..exporter import BaseExporter
|
from ...helpers import GroupConcat
|
||||||
|
from ..exporter import BaseExporter, MultiSheetListExporter
|
||||||
from ..services.invoices import invoice_pdf_task
|
from ..services.invoices import invoice_pdf_task
|
||||||
from ..signals import (
|
from ..signals import (
|
||||||
register_data_exporters, register_multievent_data_exporters,
|
register_data_exporters, register_multievent_data_exporters,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class InvoiceExporter(BaseExporter):
|
class InvoiceExporterMixin:
|
||||||
identifier = 'invoices'
|
|
||||||
verbose_name = _('All invoices')
|
|
||||||
|
|
||||||
def render(self, form_data: dict, output_file=None):
|
|
||||||
qs = Invoice.objects.filter(event__in=self.events, shredded=False)
|
|
||||||
|
|
||||||
if form_data.get('payment_provider'):
|
|
||||||
qs = qs.annotate(
|
|
||||||
has_payment_with_provider=Exists(
|
|
||||||
OrderPayment.objects.filter(
|
|
||||||
Q(order=OuterRef('order_id')) & Q(provider=form_data.get('payment_provider'))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
qs = qs.filter(has_payment_with_provider=1)
|
|
||||||
|
|
||||||
if form_data.get('date_from'):
|
|
||||||
date_value = form_data.get('date_from')
|
|
||||||
if isinstance(date_value, str):
|
|
||||||
date_value = dateutil.parser.parse(date_value).date()
|
|
||||||
qs = qs.filter(date__gte=date_value)
|
|
||||||
|
|
||||||
if form_data.get('date_to'):
|
|
||||||
date_value = form_data.get('date_to')
|
|
||||||
if isinstance(date_value, str):
|
|
||||||
date_value = dateutil.parser.parse(date_value).date()
|
|
||||||
qs = qs.filter(date__lte=date_value)
|
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory() as d:
|
|
||||||
any = False
|
|
||||||
with ZipFile(output_file or os.path.join(d, 'tmp.zip'), 'w') as zipf:
|
|
||||||
for i in qs:
|
|
||||||
try:
|
|
||||||
if not i.file:
|
|
||||||
invoice_pdf_task.apply(args=(i.pk,))
|
|
||||||
i.refresh_from_db()
|
|
||||||
i.file.open('rb')
|
|
||||||
zipf.writestr('{}.pdf'.format(i.number), i.file.read())
|
|
||||||
any = True
|
|
||||||
i.file.close()
|
|
||||||
except FileNotFoundError:
|
|
||||||
invoice_pdf_task.apply(args=(i.pk,))
|
|
||||||
i.refresh_from_db()
|
|
||||||
i.file.open('rb')
|
|
||||||
zipf.writestr('{}.pdf'.format(i.number), i.file.read())
|
|
||||||
any = True
|
|
||||||
i.file.close()
|
|
||||||
|
|
||||||
if not any:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if self.is_multievent:
|
|
||||||
filename = '{}_invoices.zip'.format(self.events.first().organizer.slug)
|
|
||||||
else:
|
|
||||||
filename = '{}_invoices.zip'.format(self.event.slug)
|
|
||||||
|
|
||||||
if output_file:
|
|
||||||
return filename, 'application/zip', None
|
|
||||||
else:
|
|
||||||
with open(os.path.join(d, 'tmp.zip'), 'rb') as zipf:
|
|
||||||
return filename, 'application/zip', zipf.read()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def export_form_fields(self):
|
def invoice_exporter_form_fields(self):
|
||||||
return OrderedDict(
|
return OrderedDict(
|
||||||
[
|
[
|
||||||
('date_from',
|
('date_from',
|
||||||
@@ -121,6 +64,312 @@ class InvoiceExporter(BaseExporter):
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def invoices_queryset(self, form_data: dict):
|
||||||
|
qs = Invoice.objects.filter(event__in=self.events)
|
||||||
|
|
||||||
|
if form_data.get('payment_provider'):
|
||||||
|
qs = qs.annotate(
|
||||||
|
has_payment_with_provider=Exists(
|
||||||
|
OrderPayment.objects.filter(
|
||||||
|
Q(order=OuterRef('order_id')) & Q(provider=form_data.get('payment_provider'))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
qs = qs.filter(has_payment_with_provider=1)
|
||||||
|
if form_data.get('date_from'):
|
||||||
|
date_value = form_data.get('date_from')
|
||||||
|
if isinstance(date_value, str):
|
||||||
|
date_value = dateutil.parser.parse(date_value).date()
|
||||||
|
qs = qs.filter(date__gte=date_value)
|
||||||
|
if form_data.get('date_to'):
|
||||||
|
date_value = form_data.get('date_to')
|
||||||
|
if isinstance(date_value, str):
|
||||||
|
date_value = dateutil.parser.parse(date_value).date()
|
||||||
|
qs = qs.filter(date__lte=date_value)
|
||||||
|
|
||||||
|
return qs
|
||||||
|
|
||||||
|
|
||||||
|
class InvoiceExporter(InvoiceExporterMixin, BaseExporter):
|
||||||
|
identifier = 'invoices'
|
||||||
|
verbose_name = _('All invoices')
|
||||||
|
|
||||||
|
def render(self, form_data: dict, output_file=None):
|
||||||
|
qs = self.invoices_queryset(form_data).filter(shredded=False)
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as d:
|
||||||
|
any = False
|
||||||
|
with ZipFile(output_file or os.path.join(d, 'tmp.zip'), 'w') as zipf:
|
||||||
|
for i in qs:
|
||||||
|
try:
|
||||||
|
if not i.file:
|
||||||
|
invoice_pdf_task.apply(args=(i.pk,))
|
||||||
|
i.refresh_from_db()
|
||||||
|
i.file.open('rb')
|
||||||
|
zipf.writestr('{}.pdf'.format(i.number), i.file.read())
|
||||||
|
any = True
|
||||||
|
i.file.close()
|
||||||
|
except FileNotFoundError:
|
||||||
|
invoice_pdf_task.apply(args=(i.pk,))
|
||||||
|
i.refresh_from_db()
|
||||||
|
i.file.open('rb')
|
||||||
|
zipf.writestr('{}.pdf'.format(i.number), i.file.read())
|
||||||
|
any = True
|
||||||
|
i.file.close()
|
||||||
|
|
||||||
|
if not any:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if self.is_multievent:
|
||||||
|
filename = '{}_invoices.zip'.format(self.events.first().organizer.slug)
|
||||||
|
else:
|
||||||
|
filename = '{}_invoices.zip'.format(self.event.slug)
|
||||||
|
|
||||||
|
if output_file:
|
||||||
|
return filename, 'application/zip', None
|
||||||
|
else:
|
||||||
|
with open(os.path.join(d, 'tmp.zip'), 'rb') as zipf:
|
||||||
|
return filename, 'application/zip', zipf.read()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def export_form_fields(self):
|
||||||
|
return self.invoice_exporter_form_fields
|
||||||
|
|
||||||
|
|
||||||
|
class InvoiceDataExporter(InvoiceExporterMixin, MultiSheetListExporter):
|
||||||
|
identifier = 'invoicedata'
|
||||||
|
verbose_name = _('Invoice data')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def additional_form_fields(self):
|
||||||
|
return self.invoice_exporter_form_fields
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sheets(self):
|
||||||
|
return (
|
||||||
|
('invoices', _('Invoices')),
|
||||||
|
('lines', _('Invoice lines')),
|
||||||
|
)
|
||||||
|
|
||||||
|
def iterate_sheet(self, form_data, sheet):
|
||||||
|
_ = gettext
|
||||||
|
if sheet == 'invoices':
|
||||||
|
yield [
|
||||||
|
_('Invoice number'),
|
||||||
|
_('Date'),
|
||||||
|
_('Order code'),
|
||||||
|
_('E-mail address'),
|
||||||
|
_('Invoice type'),
|
||||||
|
_('Cancellation of'),
|
||||||
|
_('Language'),
|
||||||
|
_('Invoice sender:') + ' ' + _('Name'),
|
||||||
|
_('Invoice sender:') + ' ' + _('Address'),
|
||||||
|
_('Invoice sender:') + ' ' + _('ZIP code'),
|
||||||
|
_('Invoice sender:') + ' ' + _('City'),
|
||||||
|
_('Invoice sender:') + ' ' + _('Country'),
|
||||||
|
_('Invoice sender:') + ' ' + _('Tax ID'),
|
||||||
|
_('Invoice sender:') + ' ' + _('VAT ID'),
|
||||||
|
_('Invoice recipient:') + ' ' + _('Company'),
|
||||||
|
_('Invoice recipient:') + ' ' + _('Name'),
|
||||||
|
_('Invoice recipient:') + ' ' + _('Street address'),
|
||||||
|
_('Invoice recipient:') + ' ' + _('ZIP code'),
|
||||||
|
_('Invoice recipient:') + ' ' + _('City'),
|
||||||
|
_('Invoice recipient:') + ' ' + _('Country'),
|
||||||
|
_('Invoice recipient:') + ' ' + pgettext('address', 'State'),
|
||||||
|
_('Invoice recipient:') + ' ' + _('VAT ID'),
|
||||||
|
_('Invoice recipient:') + ' ' + _('Beneficiary'),
|
||||||
|
_('Invoice recipient:') + ' ' + _('Internal reference'),
|
||||||
|
_('Reverse charge'),
|
||||||
|
_('Shown foreign currency'),
|
||||||
|
_('Foreign currency rate'),
|
||||||
|
_('Total value (with taxes)'),
|
||||||
|
_('Total value (without taxes)'),
|
||||||
|
_('Payment matching IDs'),
|
||||||
|
_('Payment providers'),
|
||||||
|
]
|
||||||
|
|
||||||
|
p_providers = OrderPayment.objects.filter(
|
||||||
|
order=OuterRef('order'),
|
||||||
|
state__in=(OrderPayment.PAYMENT_STATE_CONFIRMED, OrderPayment.PAYMENT_STATE_REFUNDED,
|
||||||
|
OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_CREATED),
|
||||||
|
).values('order').annotate(
|
||||||
|
m=GroupConcat('provider', delimiter=',')
|
||||||
|
).values(
|
||||||
|
'm'
|
||||||
|
).order_by()
|
||||||
|
|
||||||
|
qs = self.invoices_queryset(form_data).order_by('full_invoice_no').select_related(
|
||||||
|
'order', 'refers'
|
||||||
|
).prefetch_related('order__payments').annotate(
|
||||||
|
payment_providers=Subquery(p_providers, output_field=CharField()),
|
||||||
|
total_gross=Subquery(
|
||||||
|
InvoiceLine.objects.filter(
|
||||||
|
invoice=OuterRef('pk')
|
||||||
|
).order_by().values('invoice').annotate(
|
||||||
|
s=Sum('gross_value')
|
||||||
|
).values('s')
|
||||||
|
),
|
||||||
|
total_net=Subquery(
|
||||||
|
InvoiceLine.objects.filter(
|
||||||
|
invoice=OuterRef('pk')
|
||||||
|
).order_by().values('invoice').annotate(
|
||||||
|
s=Sum(F('gross_value') - F('tax_value'))
|
||||||
|
).values('s')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
for i in qs:
|
||||||
|
pmis = []
|
||||||
|
for p in i.order.payments.all():
|
||||||
|
if p.state in (OrderPayment.PAYMENT_STATE_CONFIRMED, OrderPayment.PAYMENT_STATE_CREATED,
|
||||||
|
OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_REFUNDED):
|
||||||
|
pprov = p.payment_provider
|
||||||
|
if pprov:
|
||||||
|
mid = pprov.matching_id(p)
|
||||||
|
if mid:
|
||||||
|
pmis.append(mid)
|
||||||
|
pmi = '\n'.join(pmis)
|
||||||
|
yield [
|
||||||
|
i.full_invoice_no,
|
||||||
|
date_format(i.date, "SHORT_DATE_FORMAT"),
|
||||||
|
i.order.code,
|
||||||
|
i.order.email,
|
||||||
|
_('Cancellation') if i.is_cancellation else _('Invoice'),
|
||||||
|
i.refers.full_invoice_no if i.refers else '',
|
||||||
|
i.locale,
|
||||||
|
i.invoice_from_name,
|
||||||
|
i.invoice_from,
|
||||||
|
i.invoice_from_zipcode,
|
||||||
|
i.invoice_from_city,
|
||||||
|
i.invoice_from_country,
|
||||||
|
i.invoice_from_tax_id,
|
||||||
|
i.invoice_from_vat_id,
|
||||||
|
i.invoice_to_company,
|
||||||
|
i.invoice_to_name,
|
||||||
|
i.invoice_to_street or i.invoice_to,
|
||||||
|
i.invoice_to_zipcode,
|
||||||
|
i.invoice_to_city,
|
||||||
|
i.invoice_to_country,
|
||||||
|
i.invoice_to_state,
|
||||||
|
i.invoice_to_vat_id,
|
||||||
|
i.invoice_to_beneficiary,
|
||||||
|
i.internal_reference,
|
||||||
|
_('Yes') if i.reverse_charge else _('No'),
|
||||||
|
i.foreign_currency_display,
|
||||||
|
i.foreign_currency_rate,
|
||||||
|
i.total_gross if i.total_gross else Decimal('0.00'),
|
||||||
|
Decimal(i.total_net if i.total_net else '0.00').quantize(Decimal('0.01')),
|
||||||
|
pmi,
|
||||||
|
', '.join([
|
||||||
|
str(self.providers.get(p, p)) for p in sorted(set((i.payment_providers or '').split(',')))
|
||||||
|
if p and p != 'free'
|
||||||
|
])
|
||||||
|
]
|
||||||
|
elif sheet == 'lines':
|
||||||
|
yield [
|
||||||
|
_('Invoice number'),
|
||||||
|
_('Line number'),
|
||||||
|
_('Description'),
|
||||||
|
_('Gross price'),
|
||||||
|
_('Net price'),
|
||||||
|
_('Tax value'),
|
||||||
|
_('Tax rate'),
|
||||||
|
_('Tax name'),
|
||||||
|
_('Event start date'),
|
||||||
|
|
||||||
|
_('Date'),
|
||||||
|
_('Order code'),
|
||||||
|
_('E-mail address'),
|
||||||
|
_('Invoice type'),
|
||||||
|
_('Cancellation of'),
|
||||||
|
_('Invoice sender:') + ' ' + _('Name'),
|
||||||
|
_('Invoice sender:') + ' ' + _('Address'),
|
||||||
|
_('Invoice sender:') + ' ' + _('ZIP code'),
|
||||||
|
_('Invoice sender:') + ' ' + _('City'),
|
||||||
|
_('Invoice sender:') + ' ' + _('Country'),
|
||||||
|
_('Invoice sender:') + ' ' + _('Tax ID'),
|
||||||
|
_('Invoice sender:') + ' ' + _('VAT ID'),
|
||||||
|
_('Invoice recipient:') + ' ' + _('Company'),
|
||||||
|
_('Invoice recipient:') + ' ' + _('Name'),
|
||||||
|
_('Invoice recipient:') + ' ' + _('Street address'),
|
||||||
|
_('Invoice recipient:') + ' ' + _('ZIP code'),
|
||||||
|
_('Invoice recipient:') + ' ' + _('City'),
|
||||||
|
_('Invoice recipient:') + ' ' + _('Country'),
|
||||||
|
_('Invoice recipient:') + ' ' + pgettext('address', 'State'),
|
||||||
|
_('Invoice recipient:') + ' ' + _('VAT ID'),
|
||||||
|
_('Invoice recipient:') + ' ' + _('Beneficiary'),
|
||||||
|
_('Invoice recipient:') + ' ' + _('Internal reference'),
|
||||||
|
_('Payment providers'),
|
||||||
|
]
|
||||||
|
|
||||||
|
p_providers = OrderPayment.objects.filter(
|
||||||
|
order=OuterRef('invoice__order'),
|
||||||
|
state__in=(OrderPayment.PAYMENT_STATE_CONFIRMED, OrderPayment.PAYMENT_STATE_REFUNDED,
|
||||||
|
OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_CREATED),
|
||||||
|
).values('order').annotate(
|
||||||
|
m=GroupConcat('provider', delimiter=',')
|
||||||
|
).values(
|
||||||
|
'm'
|
||||||
|
).order_by()
|
||||||
|
|
||||||
|
qs = InvoiceLine.objects.annotate(
|
||||||
|
payment_providers=Subquery(p_providers, output_field=CharField()),
|
||||||
|
).filter(
|
||||||
|
invoice__in=self.invoices_queryset(form_data)
|
||||||
|
).order_by('invoice__full_invoice_no', 'position').select_related(
|
||||||
|
'invoice', 'invoice__order', 'invoice__refers'
|
||||||
|
)
|
||||||
|
|
||||||
|
for l in qs:
|
||||||
|
i = l.invoice
|
||||||
|
yield [
|
||||||
|
i.full_invoice_no,
|
||||||
|
l.position + 1,
|
||||||
|
l.description.replace("<br />", " - "),
|
||||||
|
l.gross_value,
|
||||||
|
l.net_value,
|
||||||
|
l.tax_value,
|
||||||
|
l.tax_rate,
|
||||||
|
l.tax_name,
|
||||||
|
date_format(l.event_date_from, "SHORT_DATE_FORMAT") if l.event_date_from else "",
|
||||||
|
date_format(i.date, "SHORT_DATE_FORMAT"),
|
||||||
|
i.order.code,
|
||||||
|
i.order.email,
|
||||||
|
_('Cancellation') if i.is_cancellation else _('Invoice'),
|
||||||
|
i.refers.full_invoice_no if i.refers else '',
|
||||||
|
i.invoice_from_name,
|
||||||
|
i.invoice_from,
|
||||||
|
i.invoice_from_zipcode,
|
||||||
|
i.invoice_from_city,
|
||||||
|
i.invoice_from_country,
|
||||||
|
i.invoice_from_tax_id,
|
||||||
|
i.invoice_from_vat_id,
|
||||||
|
i.invoice_to_company,
|
||||||
|
i.invoice_to_name,
|
||||||
|
i.invoice_to_street or i.invoice_to,
|
||||||
|
i.invoice_to_zipcode,
|
||||||
|
i.invoice_to_city,
|
||||||
|
i.invoice_to_country,
|
||||||
|
i.invoice_to_state,
|
||||||
|
i.invoice_to_vat_id,
|
||||||
|
i.invoice_to_beneficiary,
|
||||||
|
i.internal_reference,
|
||||||
|
', '.join([
|
||||||
|
str(self.providers.get(p, p)) for p in sorted(set((l.payment_providers or '').split(',')))
|
||||||
|
if p and p != 'free'
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def providers(self):
|
||||||
|
return dict(get_all_payment_providers())
|
||||||
|
|
||||||
|
def get_filename(self):
|
||||||
|
if self.is_multievent:
|
||||||
|
return '{}_invoices'.format(self.events.first().organizer.slug)
|
||||||
|
else:
|
||||||
|
return '{}_invoices'.format(self.event.slug)
|
||||||
|
|
||||||
|
|
||||||
@receiver(register_data_exporters, dispatch_uid="exporter_invoices")
|
@receiver(register_data_exporters, dispatch_uid="exporter_invoices")
|
||||||
def register_invoice_export(sender, **kwargs):
|
def register_invoice_export(sender, **kwargs):
|
||||||
@@ -130,3 +379,13 @@ def register_invoice_export(sender, **kwargs):
|
|||||||
@receiver(register_multievent_data_exporters, dispatch_uid="multiexporter_invoices")
|
@receiver(register_multievent_data_exporters, dispatch_uid="multiexporter_invoices")
|
||||||
def register_multievent_invoice_export(sender, **kwargs):
|
def register_multievent_invoice_export(sender, **kwargs):
|
||||||
return InvoiceExporter
|
return InvoiceExporter
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(register_data_exporters, dispatch_uid="exporter_invoicedata")
|
||||||
|
def register_invoicedata_exporter(sender, **kwargs):
|
||||||
|
return InvoiceDataExporter
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(register_multievent_data_exporters, dispatch_uid="multiexporter_invoicedata")
|
||||||
|
def register_multievent_invoicedatae_xporter(sender, **kwargs):
|
||||||
|
return InvoiceDataExporter
|
||||||
|
|||||||
@@ -4,17 +4,15 @@ from decimal import Decimal
|
|||||||
import pytz
|
import pytz
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.db.models import (
|
from django.db.models import (
|
||||||
CharField, Count, DateTimeField, F, IntegerField, Max, OuterRef, Subquery,
|
CharField, Count, DateTimeField, IntegerField, Max, OuterRef, Subquery,
|
||||||
Sum,
|
Sum,
|
||||||
)
|
)
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.utils.formats import date_format
|
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.translation import gettext as _, gettext_lazy, pgettext
|
from django.utils.translation import gettext as _, gettext_lazy, pgettext
|
||||||
|
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
GiftCard, Invoice, InvoiceAddress, InvoiceLine, Order, OrderPosition,
|
GiftCard, InvoiceAddress, Order, OrderPosition, Question,
|
||||||
Question,
|
|
||||||
)
|
)
|
||||||
from pretix.base.models.orders import OrderFee, OrderPayment, OrderRefund
|
from pretix.base.models.orders import OrderFee, OrderPayment, OrderRefund
|
||||||
from pretix.base.services.quotas import QuotaAvailability
|
from pretix.base.services.quotas import QuotaAvailability
|
||||||
@@ -606,230 +604,6 @@ class QuotaListExporter(ListExporter):
|
|||||||
return '{}_quotas'.format(self.event.slug)
|
return '{}_quotas'.format(self.event.slug)
|
||||||
|
|
||||||
|
|
||||||
class InvoiceDataExporter(MultiSheetListExporter):
|
|
||||||
identifier = 'invoicedata'
|
|
||||||
verbose_name = gettext_lazy('Invoice data')
|
|
||||||
|
|
||||||
@property
|
|
||||||
def sheets(self):
|
|
||||||
return (
|
|
||||||
('invoices', _('Invoices')),
|
|
||||||
('lines', _('Invoice lines')),
|
|
||||||
)
|
|
||||||
|
|
||||||
def iterate_sheet(self, form_data, sheet):
|
|
||||||
if sheet == 'invoices':
|
|
||||||
yield [
|
|
||||||
_('Invoice number'),
|
|
||||||
_('Date'),
|
|
||||||
_('Order code'),
|
|
||||||
_('E-mail address'),
|
|
||||||
_('Invoice type'),
|
|
||||||
_('Cancellation of'),
|
|
||||||
_('Language'),
|
|
||||||
_('Invoice sender:') + ' ' + _('Name'),
|
|
||||||
_('Invoice sender:') + ' ' + _('Address'),
|
|
||||||
_('Invoice sender:') + ' ' + _('ZIP code'),
|
|
||||||
_('Invoice sender:') + ' ' + _('City'),
|
|
||||||
_('Invoice sender:') + ' ' + _('Country'),
|
|
||||||
_('Invoice sender:') + ' ' + _('Tax ID'),
|
|
||||||
_('Invoice sender:') + ' ' + _('VAT ID'),
|
|
||||||
_('Invoice recipient:') + ' ' + _('Company'),
|
|
||||||
_('Invoice recipient:') + ' ' + _('Name'),
|
|
||||||
_('Invoice recipient:') + ' ' + _('Street address'),
|
|
||||||
_('Invoice recipient:') + ' ' + _('ZIP code'),
|
|
||||||
_('Invoice recipient:') + ' ' + _('City'),
|
|
||||||
_('Invoice recipient:') + ' ' + _('Country'),
|
|
||||||
_('Invoice recipient:') + ' ' + pgettext('address', 'State'),
|
|
||||||
_('Invoice recipient:') + ' ' + _('VAT ID'),
|
|
||||||
_('Invoice recipient:') + ' ' + _('Beneficiary'),
|
|
||||||
_('Invoice recipient:') + ' ' + _('Internal reference'),
|
|
||||||
_('Reverse charge'),
|
|
||||||
_('Shown foreign currency'),
|
|
||||||
_('Foreign currency rate'),
|
|
||||||
_('Total value (with taxes)'),
|
|
||||||
_('Total value (without taxes)'),
|
|
||||||
_('Payment matching IDs'),
|
|
||||||
_('Payment providers'),
|
|
||||||
]
|
|
||||||
p_providers = OrderPayment.objects.filter(
|
|
||||||
order=OuterRef('order'),
|
|
||||||
state__in=(OrderPayment.PAYMENT_STATE_CONFIRMED, OrderPayment.PAYMENT_STATE_REFUNDED,
|
|
||||||
OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_CREATED),
|
|
||||||
).values('order').annotate(
|
|
||||||
m=GroupConcat('provider', delimiter=',')
|
|
||||||
).values(
|
|
||||||
'm'
|
|
||||||
).order_by()
|
|
||||||
qs = Invoice.objects.filter(event__in=self.events).order_by('full_invoice_no').select_related(
|
|
||||||
'order', 'refers'
|
|
||||||
).prefetch_related('order__payments').annotate(
|
|
||||||
payment_providers=Subquery(p_providers, output_field=CharField()),
|
|
||||||
total_gross=Subquery(
|
|
||||||
InvoiceLine.objects.filter(
|
|
||||||
invoice=OuterRef('pk')
|
|
||||||
).order_by().values('invoice').annotate(
|
|
||||||
s=Sum('gross_value')
|
|
||||||
).values('s')
|
|
||||||
),
|
|
||||||
total_net=Subquery(
|
|
||||||
InvoiceLine.objects.filter(
|
|
||||||
invoice=OuterRef('pk')
|
|
||||||
).order_by().values('invoice').annotate(
|
|
||||||
s=Sum(F('gross_value') - F('tax_value'))
|
|
||||||
).values('s')
|
|
||||||
)
|
|
||||||
)
|
|
||||||
for i in qs:
|
|
||||||
pmis = []
|
|
||||||
for p in i.order.payments.all():
|
|
||||||
if p.state in (OrderPayment.PAYMENT_STATE_CONFIRMED, OrderPayment.PAYMENT_STATE_CREATED,
|
|
||||||
OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_REFUNDED):
|
|
||||||
pprov = p.payment_provider
|
|
||||||
if pprov:
|
|
||||||
mid = pprov.matching_id(p)
|
|
||||||
if mid:
|
|
||||||
pmis.append(mid)
|
|
||||||
pmi = '\n'.join(pmis)
|
|
||||||
yield [
|
|
||||||
i.full_invoice_no,
|
|
||||||
date_format(i.date, "SHORT_DATE_FORMAT"),
|
|
||||||
i.order.code,
|
|
||||||
i.order.email,
|
|
||||||
_('Cancellation') if i.is_cancellation else _('Invoice'),
|
|
||||||
i.refers.full_invoice_no if i.refers else '',
|
|
||||||
i.locale,
|
|
||||||
i.invoice_from_name,
|
|
||||||
i.invoice_from,
|
|
||||||
i.invoice_from_zipcode,
|
|
||||||
i.invoice_from_city,
|
|
||||||
i.invoice_from_country,
|
|
||||||
i.invoice_from_tax_id,
|
|
||||||
i.invoice_from_vat_id,
|
|
||||||
i.invoice_to_company,
|
|
||||||
i.invoice_to_name,
|
|
||||||
i.invoice_to_street or i.invoice_to,
|
|
||||||
i.invoice_to_zipcode,
|
|
||||||
i.invoice_to_city,
|
|
||||||
i.invoice_to_country,
|
|
||||||
i.invoice_to_state,
|
|
||||||
i.invoice_to_vat_id,
|
|
||||||
i.invoice_to_beneficiary,
|
|
||||||
i.internal_reference,
|
|
||||||
_('Yes') if i.reverse_charge else _('No'),
|
|
||||||
i.foreign_currency_display,
|
|
||||||
i.foreign_currency_rate,
|
|
||||||
i.total_gross if i.total_gross else Decimal('0.00'),
|
|
||||||
Decimal(i.total_net if i.total_net else '0.00').quantize(Decimal('0.01')),
|
|
||||||
pmi,
|
|
||||||
', '.join([
|
|
||||||
str(self.providers.get(p, p)) for p in sorted(set((i.payment_providers or '').split(',')))
|
|
||||||
if p and p != 'free'
|
|
||||||
])
|
|
||||||
]
|
|
||||||
elif sheet == 'lines':
|
|
||||||
yield [
|
|
||||||
_('Invoice number'),
|
|
||||||
_('Line number'),
|
|
||||||
_('Description'),
|
|
||||||
_('Gross price'),
|
|
||||||
_('Net price'),
|
|
||||||
_('Tax value'),
|
|
||||||
_('Tax rate'),
|
|
||||||
_('Tax name'),
|
|
||||||
_('Event start date'),
|
|
||||||
|
|
||||||
_('Date'),
|
|
||||||
_('Order code'),
|
|
||||||
_('E-mail address'),
|
|
||||||
_('Invoice type'),
|
|
||||||
_('Cancellation of'),
|
|
||||||
_('Invoice sender:') + ' ' + _('Name'),
|
|
||||||
_('Invoice sender:') + ' ' + _('Address'),
|
|
||||||
_('Invoice sender:') + ' ' + _('ZIP code'),
|
|
||||||
_('Invoice sender:') + ' ' + _('City'),
|
|
||||||
_('Invoice sender:') + ' ' + _('Country'),
|
|
||||||
_('Invoice sender:') + ' ' + _('Tax ID'),
|
|
||||||
_('Invoice sender:') + ' ' + _('VAT ID'),
|
|
||||||
_('Invoice recipient:') + ' ' + _('Company'),
|
|
||||||
_('Invoice recipient:') + ' ' + _('Name'),
|
|
||||||
_('Invoice recipient:') + ' ' + _('Street address'),
|
|
||||||
_('Invoice recipient:') + ' ' + _('ZIP code'),
|
|
||||||
_('Invoice recipient:') + ' ' + _('City'),
|
|
||||||
_('Invoice recipient:') + ' ' + _('Country'),
|
|
||||||
_('Invoice recipient:') + ' ' + pgettext('address', 'State'),
|
|
||||||
_('Invoice recipient:') + ' ' + _('VAT ID'),
|
|
||||||
_('Invoice recipient:') + ' ' + _('Beneficiary'),
|
|
||||||
_('Invoice recipient:') + ' ' + _('Internal reference'),
|
|
||||||
_('Payment providers'),
|
|
||||||
]
|
|
||||||
p_providers = OrderPayment.objects.filter(
|
|
||||||
order=OuterRef('invoice__order'),
|
|
||||||
state__in=(OrderPayment.PAYMENT_STATE_CONFIRMED, OrderPayment.PAYMENT_STATE_REFUNDED,
|
|
||||||
OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_CREATED),
|
|
||||||
).values('order').annotate(
|
|
||||||
m=GroupConcat('provider', delimiter=',')
|
|
||||||
).values(
|
|
||||||
'm'
|
|
||||||
).order_by()
|
|
||||||
qs = InvoiceLine.objects.annotate(
|
|
||||||
payment_providers=Subquery(p_providers, output_field=CharField()),
|
|
||||||
).filter(
|
|
||||||
invoice__event__in=self.events
|
|
||||||
).order_by('invoice__full_invoice_no', 'position').select_related(
|
|
||||||
'invoice', 'invoice__order', 'invoice__refers'
|
|
||||||
)
|
|
||||||
for l in qs:
|
|
||||||
i = l.invoice
|
|
||||||
yield [
|
|
||||||
i.full_invoice_no,
|
|
||||||
l.position + 1,
|
|
||||||
l.description.replace("<br />", " - "),
|
|
||||||
l.gross_value,
|
|
||||||
l.net_value,
|
|
||||||
l.tax_value,
|
|
||||||
l.tax_rate,
|
|
||||||
l.tax_name,
|
|
||||||
date_format(l.event_date_from, "SHORT_DATE_FORMAT") if l.event_date_from else "",
|
|
||||||
date_format(i.date, "SHORT_DATE_FORMAT"),
|
|
||||||
i.order.code,
|
|
||||||
i.order.email,
|
|
||||||
_('Cancellation') if i.is_cancellation else _('Invoice'),
|
|
||||||
i.refers.full_invoice_no if i.refers else '',
|
|
||||||
i.invoice_from_name,
|
|
||||||
i.invoice_from,
|
|
||||||
i.invoice_from_zipcode,
|
|
||||||
i.invoice_from_city,
|
|
||||||
i.invoice_from_country,
|
|
||||||
i.invoice_from_tax_id,
|
|
||||||
i.invoice_from_vat_id,
|
|
||||||
i.invoice_to_company,
|
|
||||||
i.invoice_to_name,
|
|
||||||
i.invoice_to_street or i.invoice_to,
|
|
||||||
i.invoice_to_zipcode,
|
|
||||||
i.invoice_to_city,
|
|
||||||
i.invoice_to_country,
|
|
||||||
i.invoice_to_state,
|
|
||||||
i.invoice_to_vat_id,
|
|
||||||
i.invoice_to_beneficiary,
|
|
||||||
i.internal_reference,
|
|
||||||
', '.join([
|
|
||||||
str(self.providers.get(p, p)) for p in sorted(set((l.payment_providers or '').split(',')))
|
|
||||||
if p and p != 'free'
|
|
||||||
])
|
|
||||||
]
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def providers(self):
|
|
||||||
return dict(get_all_payment_providers())
|
|
||||||
|
|
||||||
def get_filename(self):
|
|
||||||
if self.is_multievent:
|
|
||||||
return '{}_invoices'.format(self.events.first().organizer.slug)
|
|
||||||
else:
|
|
||||||
return '{}_invoices'.format(self.event.slug)
|
|
||||||
|
|
||||||
|
|
||||||
class GiftcardRedemptionListExporter(ListExporter):
|
class GiftcardRedemptionListExporter(ListExporter):
|
||||||
identifier = 'giftcardredemptionlist'
|
identifier = 'giftcardredemptionlist'
|
||||||
verbose_name = gettext_lazy('Gift card redemptions')
|
verbose_name = gettext_lazy('Gift card redemptions')
|
||||||
@@ -897,16 +671,6 @@ def register_quotalist_exporter(sender, **kwargs):
|
|||||||
return QuotaListExporter
|
return QuotaListExporter
|
||||||
|
|
||||||
|
|
||||||
@receiver(register_data_exporters, dispatch_uid="exporter_invoicedata")
|
|
||||||
def register_invoicedata_exporter(sender, **kwargs):
|
|
||||||
return InvoiceDataExporter
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(register_multievent_data_exporters, dispatch_uid="multiexporter_invoicedata")
|
|
||||||
def register_multievent_invoicedatae_xporter(sender, **kwargs):
|
|
||||||
return InvoiceDataExporter
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(register_data_exporters, dispatch_uid="exporter_giftcardredemptionlist")
|
@receiver(register_data_exporters, dispatch_uid="exporter_giftcardredemptionlist")
|
||||||
def register_giftcardredemptionlist_exporter(sender, **kwargs):
|
def register_giftcardredemptionlist_exporter(sender, **kwargs):
|
||||||
return GiftcardRedemptionListExporter
|
return GiftcardRedemptionListExporter
|
||||||
|
|||||||
Reference in New Issue
Block a user