mirror of
https://github.com/pretix/pretix.git
synced 2026-08-11 10:57:00 +00:00
Order creation API: Add support for reverse charge
This commit is contained in:
@@ -747,8 +747,6 @@ Creating orders
|
||||
* does not allow to pass data to plugins and will therefore cause issues with some plugins like the shipping
|
||||
module
|
||||
|
||||
* does not support reverse charge taxation
|
||||
|
||||
* does not support file upload questions
|
||||
|
||||
You can supply the following fields of the resource:
|
||||
@@ -789,6 +787,9 @@ Creating orders
|
||||
* ``state``
|
||||
* ``internal_reference``
|
||||
* ``vat_id``
|
||||
* ``vat_id_validated`` (optional) – If you need support for reverse charge (rarely the case), you need to check
|
||||
yourself if the passed VAT ID is a valid EU VAT ID. In that case, set this to ``true``. Only valid VAT IDs will
|
||||
trigger reverse charge taxation. Don't forget to set ``is_business`` as well!
|
||||
|
||||
* ``positions``
|
||||
|
||||
@@ -881,7 +882,7 @@ Creating orders
|
||||
],
|
||||
"subevent": null
|
||||
}
|
||||
],
|
||||
]
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
@@ -49,7 +49,7 @@ class InvoiceAddressSerializer(I18nAwareModelSerializer):
|
||||
model = InvoiceAddress
|
||||
fields = ('last_modified', 'is_business', 'company', 'name', 'name_parts', 'street', 'zipcode', 'city', 'country',
|
||||
'state', 'vat_id', 'vat_id_validated', 'internal_reference')
|
||||
read_only_fields = ('last_modified', 'vat_id_validated')
|
||||
read_only_fields = ('last_modified',)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -377,7 +377,7 @@ class OrderSerializer(I18nAwareModelSerializer):
|
||||
}
|
||||
try:
|
||||
ia = instance.invoice_address
|
||||
if iadata.get('vat_id') != ia.vat_id:
|
||||
if iadata.get('vat_id') != ia.vat_id and 'vat_id_validated' not in iadata:
|
||||
ia.vat_id_validated = False
|
||||
self.fields['invoice_address'].update(ia, iadata)
|
||||
except InvoiceAddress.DoesNotExist:
|
||||
|
||||
@@ -2889,6 +2889,64 @@ def test_order_create_auto_pricing(token_client, organizer, event, item, quota,
|
||||
assert o.total == item.default_price + Decimal('0.25')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_create_auto_pricing_reverse_charge(token_client, organizer, event, item, quota, question, taxrule):
|
||||
taxrule.eu_reverse_charge = True
|
||||
taxrule.home_country = Country('DE')
|
||||
taxrule.save()
|
||||
item.tax_rule = taxrule
|
||||
item.save()
|
||||
res = copy.deepcopy(ORDER_CREATE_PAYLOAD)
|
||||
res['positions'][0]['item'] = item.pk
|
||||
res['positions'][0]['answers'][0]['question'] = question.pk
|
||||
res['invoice_address']['country'] = 'FR'
|
||||
res['invoice_address']['is_business'] = True
|
||||
res['invoice_address']['vat_id'] = 'FR12345'
|
||||
res['invoice_address']['vat_id_validated'] = True
|
||||
del res['positions'][0]['price']
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/orders/'.format(
|
||||
organizer.slug, event.slug
|
||||
), format='json', data=res
|
||||
)
|
||||
assert resp.status_code == 201
|
||||
with scopes_disabled():
|
||||
o = Order.objects.get(code=resp.data['code'])
|
||||
p = o.positions.first()
|
||||
assert p.price == Decimal('19.33')
|
||||
assert p.tax_rate == Decimal('0.00')
|
||||
assert p.tax_value == Decimal('0.00')
|
||||
assert o.total == Decimal('19.58')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_create_auto_pricing_reverse_charge_require_valid_vatid(token_client, organizer, event, item, quota,
|
||||
question, taxrule):
|
||||
taxrule.eu_reverse_charge = True
|
||||
taxrule.home_country = Country('DE')
|
||||
taxrule.save()
|
||||
item.tax_rule = taxrule
|
||||
item.save()
|
||||
res = copy.deepcopy(ORDER_CREATE_PAYLOAD)
|
||||
res['positions'][0]['item'] = item.pk
|
||||
res['positions'][0]['answers'][0]['question'] = question.pk
|
||||
res['invoice_address']['country'] = 'FR'
|
||||
res['invoice_address']['is_business'] = True
|
||||
res['invoice_address']['vat_id'] = 'FR12345'
|
||||
del res['positions'][0]['price']
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/orders/'.format(
|
||||
organizer.slug, event.slug
|
||||
), format='json', data=res
|
||||
)
|
||||
assert resp.status_code == 201
|
||||
with scopes_disabled():
|
||||
o = Order.objects.get(code=resp.data['code'])
|
||||
p = o.positions.first()
|
||||
assert p.price == Decimal('23.00')
|
||||
assert p.tax_rate == Decimal('19.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_create_voucher_price(token_client, organizer, event, item, quota, question):
|
||||
res = copy.deepcopy(ORDER_CREATE_PAYLOAD)
|
||||
@@ -3391,6 +3449,34 @@ def test_order_update_allowed_fields(token_client, organizer, event, order):
|
||||
assert order.all_logentries().get(action_type='pretix.event.order.modified')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_update_validated_vat_id(token_client, organizer, event, order):
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/orders/{}/'.format(
|
||||
organizer.slug, event.slug, order.code
|
||||
), format='json', data={
|
||||
'invoice_address': {
|
||||
"is_business": False,
|
||||
"company": "This is my company name",
|
||||
"name": "John Doe",
|
||||
"name_parts": {},
|
||||
"street": "",
|
||||
"state": "",
|
||||
"zipcode": "",
|
||||
"city": "Paris",
|
||||
"country": "FR",
|
||||
"internal_reference": "",
|
||||
"vat_id": "FR123",
|
||||
"vat_id_validated": True
|
||||
}
|
||||
}
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
order.refresh_from_db()
|
||||
assert order.invoice_address.vat_id == "FR123"
|
||||
assert order.invoice_address.vat_id_validated
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_update_invoiceaddress_delete_create(token_client, organizer, event, order):
|
||||
event.settings.locales = ['de', 'en']
|
||||
|
||||
Reference in New Issue
Block a user