From d2b0e7209fd73d961efad880fbcee544a1dbbeeb Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Wed, 19 Jul 2017 12:08:18 +0200 Subject: [PATCH] Use a choice field for invoice address countries --- doc/api/resources/orders.rst | 7 +++ src/pretix/api/serializers/order.py | 10 +++++ src/pretix/base/exporters/orderlist.py | 2 +- .../migrations/0070_auto_20170719_0910.py | 43 +++++++++++++++++++ src/pretix/base/models/orders.py | 5 ++- src/pretix/base/services/invoices.py | 7 ++- .../templates/pretixcontrol/order/index.html | 2 +- .../pretixpresale/event/checkout_confirm.html | 2 +- .../templates/pretixpresale/event/order.html | 2 +- src/pretix/settings.py | 1 + src/requirements/production.txt | 2 + src/tests/api/test_orders.py | 7 +-- src/tests/base/test_invoices.py | 20 +++++++-- 13 files changed, 96 insertions(+), 14 deletions(-) create mode 100644 src/pretix/base/migrations/0070_auto_20170719_0910.py diff --git a/doc/api/resources/orders.rst b/doc/api/resources/orders.rst index d2ed0ac485..9c823b125b 100644 --- a/doc/api/resources/orders.rst +++ b/doc/api/resources/orders.rst @@ -50,6 +50,13 @@ downloads list of objects List of ticket └ url string Download URL ===================================== ========================== ======================================================= + +.. versionchanged:: 1.6 + + The ``invoice_address.country`` attribute contains a two-letter country code for all new orders. For old orders, + a custom text might still be returned. + + Order position resource ----------------------- diff --git a/src/pretix/api/serializers/order.py b/src/pretix/api/serializers/order.py index 79205b4c19..530198d6c9 100644 --- a/src/pretix/api/serializers/order.py +++ b/src/pretix/api/serializers/order.py @@ -9,7 +9,17 @@ from pretix.base.models import ( from pretix.base.signals import register_ticket_outputs +class CompatibleCountryField(serializers.Field): + def to_representation(self, instance: InvoiceAddress): + if instance.country: + return str(instance.country) + else: + return instance.country_old + + class InvoiceAdddressSerializer(I18nAwareModelSerializer): + country = CompatibleCountryField(source='*') + class Meta: model = InvoiceAddress fields = ('last_modified', 'company', 'name', 'street', 'zipcode', 'city', 'country', 'vat_id') diff --git a/src/pretix/base/exporters/orderlist.py b/src/pretix/base/exporters/orderlist.py index 85b89583da..78030765b3 100644 --- a/src/pretix/base/exporters/orderlist.py +++ b/src/pretix/base/exporters/orderlist.py @@ -100,7 +100,7 @@ class OrderListExporter(BaseExporter): order.invoice_address.street, order.invoice_address.zipcode, order.invoice_address.city, - order.invoice_address.country, + order.invoice_address.country if order.invoice_address.country else order.invoice_address.country_old, order.invoice_address.vat_id, ] except InvoiceAddress.DoesNotExist: diff --git a/src/pretix/base/migrations/0070_auto_20170719_0910.py b/src/pretix/base/migrations/0070_auto_20170719_0910.py new file mode 100644 index 0000000000..2fd211d56e --- /dev/null +++ b/src/pretix/base/migrations/0070_auto_20170719_0910.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.2 on 2017-07-19 09:10 +from __future__ import unicode_literals + +import django_countries +from django.db import migrations, models + + +def fwd(app, schema_editor): + InvoiceAddress = app.get_model('pretixbase', 'InvoiceAddress') + for ia in InvoiceAddress.objects.all(): + if ia.company or ia.vat_id: + ia.is_business = True + ia.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('pretixbase', '0069_invoice_prefix'), + ] + + operations = [ + migrations.RenameField( + model_name='invoiceaddress', + old_name='country', + new_name='country_old', + ), + migrations.AddField( + model_name='invoiceaddress', + name='country', + field=django_countries.fields.CountryField(default='', max_length=2, verbose_name='Country'), + preserve_default=False, + ), + migrations.AddField( + model_name='invoiceaddress', + name='is_business', + field=models.BooleanField(default=False, verbose_name='Business customer'), + ), + migrations.RunPython( + fwd, migrations.RunPython.noop + ), + ] diff --git a/src/pretix/base/models/orders.py b/src/pretix/base/models/orders.py index 6fc144ee1c..a67cb2a268 100644 --- a/src/pretix/base/models/orders.py +++ b/src/pretix/base/models/orders.py @@ -19,6 +19,7 @@ from django.utils.html import escape from django.utils.safestring import mark_safe from django.utils.timezone import make_aware, now from django.utils.translation import pgettext_lazy, ugettext_lazy as _ +from django_countries.fields import CountryField from pretix.base.reldate import RelativeDateWrapper @@ -727,13 +728,15 @@ class CartPosition(AbstractPosition): class InvoiceAddress(models.Model): last_modified = models.DateTimeField(auto_now=True) + is_business = models.BooleanField(default=False, verbose_name=_('Business customer')) order = models.OneToOneField(Order, null=True, blank=True, related_name='invoice_address') company = models.CharField(max_length=255, blank=True, verbose_name=_('Company name')) name = models.CharField(max_length=255, verbose_name=_('Full name'), blank=True) street = models.TextField(verbose_name=_('Address'), blank=False) zipcode = models.CharField(max_length=30, verbose_name=_('ZIP code'), blank=False) city = models.CharField(max_length=255, verbose_name=_('City'), blank=False) - country = models.CharField(max_length=255, verbose_name=_('Country'), blank=False) + country_old = models.CharField(max_length=255, verbose_name=_('Country'), blank=False) + country = CountryField(verbose_name=_('Country'), blank=False, blank_label=_('Select country')) vat_id = models.CharField(max_length=255, blank=True, verbose_name=_('VAT ID')) diff --git a/src/pretix/base/services/invoices.py b/src/pretix/base/services/invoices.py index 33c7f0da41..6b7a1de7e2 100644 --- a/src/pretix/base/services/invoices.py +++ b/src/pretix/base/services/invoices.py @@ -37,8 +37,11 @@ def build_invoice(invoice: Invoice) -> Invoice: {i.name} {i.street} {i.zipcode} {i.city} -{i.country}""") - invoice.invoice_to = addr_template.format(i=invoice.order.invoice_address).strip() +{country}""") + invoice.invoice_to = addr_template.format( + i=invoice.order.invoice_address, + country=invoice.order.invoice_address.country.name if invoice.order.invoice_address.country else invoice.order.invoice_address.country_old + ).strip() if invoice.order.invoice_address.vat_id: invoice.invoice_to += "\n" + pgettext("invoice", "VAT-ID: %s") % invoice.order.invoice_address.vat_id except InvoiceAddress.DoesNotExist: diff --git a/src/pretix/control/templates/pretixcontrol/order/index.html b/src/pretix/control/templates/pretixcontrol/order/index.html index c22a3400a2..cb502a6265 100644 --- a/src/pretix/control/templates/pretixcontrol/order/index.html +++ b/src/pretix/control/templates/pretixcontrol/order/index.html @@ -347,7 +347,7 @@
{% trans "ZIP code and city" %}
{{ order.invoice_address.zipcode }} {{ order.invoice_address.city }}
{% trans "Country" %}
-
{{ order.invoice_address.country }}
+
{{ order.invoice_address.country.name|default:order.invoice_address.country_old }}
{% if request.event.settings.invoice_address_vatid %}
{% trans "VAT ID" %}
{{ order.invoice_address.vat_id }}
diff --git a/src/pretix/presale/templates/pretixpresale/event/checkout_confirm.html b/src/pretix/presale/templates/pretixpresale/event/checkout_confirm.html index 87e4870bc9..f6d33f4750 100644 --- a/src/pretix/presale/templates/pretixpresale/event/checkout_confirm.html +++ b/src/pretix/presale/templates/pretixpresale/event/checkout_confirm.html @@ -83,7 +83,7 @@
{% trans "ZIP code and city" %}
{{ addr.zipcode }} {{ addr.city }}
{% trans "Country" %}
-
{{ addr.country }}
+
{{ addr.country.name }}
{% if request.event.settings.invoice_address_vatid %}
{% trans "VAT ID" %}
{{ addr.vat_id }}
diff --git a/src/pretix/presale/templates/pretixpresale/event/order.html b/src/pretix/presale/templates/pretixpresale/event/order.html index c401904da3..ddf212aee3 100644 --- a/src/pretix/presale/templates/pretixpresale/event/order.html +++ b/src/pretix/presale/templates/pretixpresale/event/order.html @@ -182,7 +182,7 @@
{% trans "ZIP code and city" %}
{{ order.invoice_address.zipcode }} {{ order.invoice_address.city }}
{% trans "Country" %}
-
{{ order.invoice_address.country }}
+
{{ order.invoice_address.country.name|default:order.invoice_address.country_old }}
{% if request.event.settings.invoice_address_vatid %}
{% trans "VAT ID" %}
{{ order.invoice_address.vat_id }}
diff --git a/src/pretix/settings.py b/src/pretix/settings.py index cdd5dd6af3..8735a24876 100644 --- a/src/pretix/settings.py +++ b/src/pretix/settings.py @@ -219,6 +219,7 @@ INSTALLED_APPS = [ 'django_otp.plugins.otp_totp', 'django_otp.plugins.otp_static', 'statici18n', + 'django_countries' ] try: diff --git a/src/requirements/production.txt b/src/requirements/production.txt index 1fcc3021c4..da3c9cfa3b 100644 --- a/src/requirements/production.txt +++ b/src/requirements/production.txt @@ -41,3 +41,5 @@ chardet<3.1.0,>=3.0.2 mt-940==3.2 vobject==0.9.* pycountry +django-countries +pyuca # for better sorting of country names in django-countries diff --git a/src/tests/api/test_orders.py b/src/tests/api/test_orders.py index 8729d1f437..52e3c0eba6 100644 --- a/src/tests/api/test_orders.py +++ b/src/tests/api/test_orders.py @@ -3,6 +3,7 @@ from decimal import Decimal from unittest import mock import pytest +from django_countries.fields import Country from pytz import UTC from pretix.base.models import InvoiceAddress, Order, OrderPosition @@ -29,7 +30,7 @@ def order(event, item): expires=datetime.datetime(2017, 12, 10, 10, 0, 0, tzinfo=UTC), total=23, payment_provider='banktransfer', locale='en' ) - InvoiceAddress.objects.create(order=o, company="Sample company") + InvoiceAddress.objects.create(order=o, company="Sample company", country=Country('NZ')) OrderPosition.objects.create( order=o, item=item, @@ -82,7 +83,7 @@ TEST_ORDER_RES = { "street": "", "zipcode": "", "city": "", - "country": "", + "country": "NZ", "vat_id": "" }, "positions": [TEST_ORDERPOSITION_RES], @@ -259,7 +260,7 @@ TEST_INVOICE_RES = { "number": "DUMMY-00001", "is_cancellation": False, "invoice_from": "", - "invoice_to": "Sample company", + "invoice_to": "Sample company\n\n\n \nNew Zealand", "date": "2017-12-10", "refers": None, "locale": "en", diff --git a/src/tests/base/test_invoices.py b/src/tests/base/test_invoices.py index c7ce6e8c04..902beaf1a1 100644 --- a/src/tests/base/test_invoices.py +++ b/src/tests/base/test_invoices.py @@ -4,6 +4,7 @@ from decimal import Decimal import pytest from django.db import DatabaseError from django.utils.timezone import now +from django_countries.fields import Country from pretix.base.models import ( Event, Invoice, InvoiceAddress, Item, ItemVariation, Order, OrderPosition, @@ -71,15 +72,26 @@ def test_locale_user(env): assert inv.locale == order.locale +@pytest.mark.django_db +def test_address_old_country(env): + event, order = env + event.settings.set('invoice_language', 'en') + InvoiceAddress.objects.create(company='Acme Company', street='221B Baker Street', + zipcode='12345', city='London', country_old='England', country='', + order=order) + inv = generate_invoice(order) + assert inv.invoice_to == "Acme Company\n\n221B Baker Street\n12345 London\nEngland" + + @pytest.mark.django_db def test_address(env): event, order = env event.settings.set('invoice_language', 'en') InvoiceAddress.objects.create(company='Acme Company', street='221B Baker Street', - zipcode='12345', city='London', country='UK', + zipcode='12345', city='London', country=Country('GB'), order=order) inv = generate_invoice(order) - assert inv.invoice_to == "Acme Company\n\n221B Baker Street\n12345 London\nUK" + assert inv.invoice_to == "Acme Company\n\n221B Baker Street\n12345 London\nUnited Kingdom" @pytest.mark.django_db @@ -87,8 +99,8 @@ def test_address_vat_id(env): event, order = env event.settings.set('invoice_language', 'en') InvoiceAddress.objects.create(company='Acme Company', street='221B Baker Street', - name='Sherlock Holmes', zipcode='12345', city='London', country='UK', - vat_id='UK1234567', order=order) + name='Sherlock Holmes', zipcode='12345', city='London', country_old='UK', + country='', vat_id='UK1234567', order=order) inv = generate_invoice(order) assert inv.invoice_to == "Acme Company\nSherlock Holmes\n221B Baker Street\n12345 London\nUK\nVAT-ID: UK1234567"