diff --git a/doc/development/api/payment.rst b/doc/development/api/payment.rst index e9b95de938..870d58ebe2 100644 --- a/doc/development/api/payment.rst +++ b/doc/development/api/payment.rst @@ -62,6 +62,8 @@ The provider class .. automethod:: settings_content_render + .. automethod:: render_invoice_text + .. automethod:: payment_form_render .. automethod:: payment_form diff --git a/doc/development/implementation/logging.rst b/doc/development/implementation/logging.rst index f68efd9471..5c9c8a3bbd 100644 --- a/doc/development/implementation/logging.rst +++ b/doc/development/implementation/logging.rst @@ -29,7 +29,7 @@ Logging form actions A very common use case is to log the changes to a model that have been done in a ``ModelForm``. In this case, we generally use a custom ``form_valid`` method on our ``FormView`` that looks like this:: - @transaction.atomic() + @transaction.atomic def form_valid(self, form): if form.has_changed(): self.request.event.log_action('pretix.event.changed', user=self.request.user, data={ @@ -40,7 +40,7 @@ we generally use a custom ``form_valid`` method on our ``FormView`` that looks l It gets a little bit more complicated if your form allows file uploads:: - @transaction.atomic() + @transaction.atomic def form_valid(self, form): if form.has_changed(): self.request.event.log_action( diff --git a/src/pretix/base/migrations/0037_invoice_payment_provider_text.py b/src/pretix/base/migrations/0037_invoice_payment_provider_text.py new file mode 100644 index 0000000000..9659a910ec --- /dev/null +++ b/src/pretix/base/migrations/0037_invoice_payment_provider_text.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.9 on 2016-09-06 21:31 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pretixbase', '0036_auto_20160902_0755'), + ] + + operations = [ + migrations.AddField( + model_name='invoice', + name='payment_provider_text', + field=models.TextField(blank=True), + ), + ] diff --git a/src/pretix/base/models/invoices.py b/src/pretix/base/models/invoices.py index ec73130b77..b65b688f22 100644 --- a/src/pretix/base/models/invoices.py +++ b/src/pretix/base/models/invoices.py @@ -43,6 +43,8 @@ class Invoice(models.Model): :type introductory_text: str :param additional_text: Additional text for the invoice :type additional_text: str + :param payment_provider_text: A payment provider specific text + :type payment_provider_text: str :param footer_text: A footer text, displayed smaller and centered on every page :type footer_text: str :param file: The filename of the rendered invoice @@ -59,6 +61,7 @@ class Invoice(models.Model): locale = models.CharField(max_length=50, default='en') introductory_text = models.TextField(blank=True) additional_text = models.TextField(blank=True) + payment_provider_text = models.TextField(blank=True) footer_text = models.TextField(blank=True) file = models.FileField(null=True, blank=True, upload_to=invoice_filename) diff --git a/src/pretix/base/payment.py b/src/pretix/base/payment.py index 3b8f636969..e0ded320e5 100644 --- a/src/pretix/base/payment.py +++ b/src/pretix/base/payment.py @@ -12,6 +12,7 @@ from django.template.loader import get_template from django.utils.translation import ugettext_lazy as _ from pretix.base.decimal import round_decimal +from pretix.base.i18n import I18nFormField, I18nTextarea, LazyI18nString from pretix.base.models import CartPosition, Event, Order, Quota from pretix.base.settings import SettingsSandbox from pretix.base.signals import register_payment_providers @@ -134,6 +135,13 @@ class BasePaymentProvider: 'above!'), required=False )), + ('_invoice_text', + I18nFormField( + label=_('Text on invoices'), + help_text=_('Will be printed just below the payment figures and above the closing text on invoices.'), + required=False, + widget=I18nTextarea, + )), ]) def settings_content_render(self, request: HttpRequest) -> str: @@ -144,6 +152,14 @@ class BasePaymentProvider: """ pass + def render_invoice_text(self, order: Order) -> str: + """ + This is called when an invoice for an order with this payment provider is generated. + The default implementation returns the content of the _invoice_text configuration + variable (an I18nString), or an empty string if unconfigured. + """ + return self.settings.get('_invoice_text', as_type=LazyI18nString, default='') + @property def payment_form_fields(self) -> dict: """ diff --git a/src/pretix/base/services/invoices.py b/src/pretix/base/services/invoices.py index c9dde9c6c1..9099058f5b 100644 --- a/src/pretix/base/services/invoices.py +++ b/src/pretix/base/services/invoices.py @@ -26,37 +26,27 @@ from pretix.base.models import Invoice, InvoiceAddress, InvoiceLine, Order from pretix.base.signals import register_payment_providers -def generate_cancellation(invoice: Invoice): - cancellation = copy.copy(invoice) - cancellation.pk = None - cancellation.is_cancellation = True - cancellation.date = date.today() - cancellation.refers = invoice - cancellation.invoice_no = None - cancellation.save() - for line in invoice.lines.all(): - line.pk = None - line.invoice = cancellation - line.gross_value *= -1 - line.tax_value *= -1 - line.save() - - invoice_pdf(cancellation.pk) - return cancellation - - @transaction.atomic -def regenerate_invoice(invoice: Invoice): +def build_invoice(invoice: Invoice) -> Invoice: with language(invoice.locale): + responses = register_payment_providers.send(invoice.event) + for receiver, response in responses: + provider = response(invoice.event) + if provider.identifier == invoice.order.payment_provider: + payment_provider = provider + break + invoice.invoice_from = invoice.event.settings.get('invoice_address_from') introductory = invoice.event.settings.get('invoice_introductory_text', as_type=LazyI18nString) additional = invoice.event.settings.get('invoice_additional_text', as_type=LazyI18nString) footer = invoice.event.settings.get('invoice_footer_text', as_type=LazyI18nString) + payment = payment_provider.render_invoice_text(invoice.order) invoice.introductory_text = str(introductory).replace('\n', '
') - invoice.additional_text = str(additional).replace('\n', '
') invoice.footer_text = str(footer) + invoice.payment_provider_text = str(payment).replace('\n', '
') try: addr_template = pgettext("invoice", """{i.company} @@ -72,15 +62,8 @@ def regenerate_invoice(invoice: Invoice): invoice.file = None invoice.save() - - responses = register_payment_providers.send(invoice.event) - for receiver, response in responses: - provider = response(invoice.event) - if provider.identifier == invoice.order.payment_provider: - payment_provider = provider - break - invoice.lines.all().delete() + for p in invoice.order.positions.all(): desc = str(p.item.name) if p.variation: @@ -98,71 +81,60 @@ def regenerate_invoice(invoice: Invoice): tax_rate=invoice.order.payment_fee_tax_rate ) - invoice_pdf(invoice.pk) + return invoice + + +def build_cancellation(invoice: Invoice): + invoice.lines.all().delete() + + for line in invoice.refers.lines.all(): + line.pk = None + line.invoice = invoice + line.gross_value *= -1 + line.tax_value *= -1 + line.save() + return invoice + + +def generate_cancellation(invoice: Invoice): + cancellation = copy.copy(invoice) + cancellation.pk = None + cancellation.invoice_no = None + cancellation.refers = invoice + cancellation.is_cancellation = True + cancellation.date = date.today() + cancellation.payment_provider_text = '' + cancellation.save() + + cancellation = build_cancellation(cancellation) + invoice_pdf(cancellation.pk) + return cancellation + + +def regenerate_invoice(invoice: Invoice): + if invoice.is_cancellation: + invoice = build_cancellation(invoice) + else: + invoice = build_invoice(invoice) + invoice_pdf(invoice.pk) return invoice -@transaction.atomic def generate_invoice(order: Order): locale = order.event.settings.get('invoice_language') if locale: if locale == '__user__': locale = order.locale - with language(locale): - i = Invoice(order=order, event=order.event) - i.invoice_from = order.event.settings.get('invoice_address_from') - - introductory = i.event.settings.get('invoice_introductory_text', as_type=LazyI18nString) - additional = i.event.settings.get('invoice_additional_text', as_type=LazyI18nString) - footer = i.event.settings.get('invoice_footer_text', as_type=LazyI18nString) - - i.introductory_text = str(introductory).replace('\n', '
') - i.additional_text = str(additional).replace('\n', '