mirror of
https://github.com/pretix/pretix.git
synced 2026-05-03 14:54:04 +00:00
New data model for default tax rule and new options for cancellation fees (#4962)
* New data model for default tax rule * Remove misleading empty label when field is not optional * Allow to split cancellation fee * Fix API and tests * Update migration * Update src/tests/api/test_taxrules.py Co-authored-by: luelista <weller@rami.io> * Update src/tests/api/test_taxrules.py Co-authored-by: luelista <weller@rami.io> * Review note * Update src/pretix/base/models/tax.py Co-authored-by: luelista <weller@rami.io> * Flip API behaviour for default * Fix failing tests * Fix failing test * Split migration --------- Co-authored-by: luelista <weller@rami.io>
This commit is contained in:
@@ -192,7 +192,7 @@ def subevent2(event2, meta_prop):
|
||||
@pytest.fixture
|
||||
@scopes_disabled()
|
||||
def taxrule(event):
|
||||
return event.tax_rules.create(name="VAT", rate=19, code="S/standard")
|
||||
return event.tax_rules.create(name="VAT", rate=19, code="S/standard", default=True)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -50,7 +50,7 @@ def item2(event2):
|
||||
|
||||
@pytest.fixture
|
||||
def taxrule(event):
|
||||
return event.tax_rules.create(rate=Decimal('19.00'), code="S/standard")
|
||||
return event.tax_rules.create(rate=Decimal('19.00'), code="S/standard", default=True)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -1351,7 +1351,7 @@ def test_order_mark_canceled_pending(token_client, organizer, event, order):
|
||||
@pytest.mark.django_db
|
||||
def test_order_mark_canceled_pending_fee_with_tax(token_client, organizer, event, order, taxrule):
|
||||
djmail.outbox = []
|
||||
event.settings.tax_rate_default = taxrule
|
||||
event.settings.tax_rule_cancellation = "default"
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/orders/{}/mark_canceled/'.format(
|
||||
organizer.slug, event.slug, order.code
|
||||
|
||||
@@ -31,6 +31,7 @@ TEST_TAXRULE_RES = {
|
||||
'keep_gross_if_rate_changes': False,
|
||||
'name': {'en': 'VAT'},
|
||||
'rate': '19.00',
|
||||
'default': True,
|
||||
'code': 'S/standard',
|
||||
'price_includes_tax': True,
|
||||
'eu_reverse_charge': False,
|
||||
@@ -80,6 +81,45 @@ def test_rule_create(token_client, organizer, event):
|
||||
assert str(rule.home_country) == "DE"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_rule_create_auto_default(token_client, organizer, event):
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/taxrules/'.format(organizer.slug, event.slug),
|
||||
{
|
||||
"name": {"en": "VAT", "de": "MwSt"},
|
||||
"rate": "19.00",
|
||||
"price_includes_tax": True,
|
||||
"eu_reverse_charge": False,
|
||||
"home_country": "DE",
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 201
|
||||
rule = TaxRule.objects.get(pk=resp.data['id'])
|
||||
assert rule.default
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_rule_create_only_one_default(token_client, taxrule, organizer, event):
|
||||
assert taxrule.default
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/taxrules/'.format(organizer.slug, event.slug),
|
||||
{
|
||||
"name": {"en": "VAT", "de": "MwSt"},
|
||||
"rate": "19.00",
|
||||
"price_includes_tax": True,
|
||||
"eu_reverse_charge": False,
|
||||
"home_country": "DE",
|
||||
"default": True,
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 201
|
||||
|
||||
taxrule.refresh_from_db()
|
||||
assert not taxrule.default
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_rule_update(token_client, organizer, event, taxrule):
|
||||
resp = token_client.patch(
|
||||
|
||||
@@ -2215,7 +2215,7 @@ class EventTest(TestCase):
|
||||
is_public=True,
|
||||
)
|
||||
event1.meta_values.create(property=prop, value="DE")
|
||||
tr7 = event1.tax_rules.create(rate=Decimal('7.00'))
|
||||
tr7 = event1.tax_rules.create(rate=Decimal('7.00'), default=True)
|
||||
c1 = event1.categories.create(name='Tickets')
|
||||
c2 = event1.categories.create(name='Workshops')
|
||||
i1 = event1.items.create(name='Foo', default_price=Decimal('13.00'), tax_rule=tr7,
|
||||
@@ -2228,7 +2228,6 @@ class EventTest(TestCase):
|
||||
que1 = event1.questions.create(question="Age", type="N")
|
||||
que1.items.add(i1)
|
||||
event1.settings.foo_setting = 23
|
||||
event1.settings.tax_rate_default = tr7
|
||||
cl1 = event1.checkin_lists.create(
|
||||
name="All", all_products=False,
|
||||
rules={
|
||||
@@ -2271,7 +2270,7 @@ class EventTest(TestCase):
|
||||
assert que1new.type == que1.type
|
||||
assert que1new.items.get(pk=i1new.pk)
|
||||
assert event2.settings.foo_setting == '23'
|
||||
assert event2.settings.tax_rate_default == trnew
|
||||
assert event2.cached_default_tax_rule == trnew
|
||||
assert event2.checkin_lists.count() == 1
|
||||
clnew = event2.checkin_lists.first()
|
||||
assert [i.pk for i in clnew.limit_products.all()] == [i1new.pk]
|
||||
|
||||
@@ -1117,7 +1117,7 @@ class OrderCancelTests(TestCase):
|
||||
self.order.save()
|
||||
self.order.payments.create(state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=48.5)
|
||||
with pytest.raises(OrderError):
|
||||
cancel_order(self.order.pk, cancellation_fee=50)
|
||||
cancel_order(self.order.pk, cancellation_fee=Decimal("50.00"))
|
||||
self.order.refresh_from_db()
|
||||
assert self.order.status == Order.STATUS_PAID
|
||||
assert self.order.total == 46
|
||||
@@ -1131,7 +1131,7 @@ class OrderCancelTests(TestCase):
|
||||
self.order.payments.create(state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=48.5)
|
||||
self.op1.voucher = self.event.vouchers.create(item=self.ticket, redeemed=1)
|
||||
self.op1.save()
|
||||
cancel_order(self.order.pk, cancellation_fee=2.5)
|
||||
cancel_order(self.order.pk, cancellation_fee=Decimal("2.50"))
|
||||
self.order.refresh_from_db()
|
||||
assert self.order.status == Order.STATUS_PAID
|
||||
self.op1.refresh_from_db()
|
||||
@@ -1158,7 +1158,7 @@ class OrderCancelTests(TestCase):
|
||||
self.order.payments.create(state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=48.5)
|
||||
self.op1.voucher = self.event.vouchers.create(item=self.ticket, redeemed=1)
|
||||
self.op1.save()
|
||||
cancel_order(self.order.pk, cancellation_fee=2.5)
|
||||
cancel_order(self.order.pk, cancellation_fee=Decimal("2.50"))
|
||||
self.order.refresh_from_db()
|
||||
assert self.order.status == Order.STATUS_PAID
|
||||
self.op1.refresh_from_db()
|
||||
@@ -1172,7 +1172,7 @@ class OrderCancelTests(TestCase):
|
||||
state=OrderPayment.PAYMENT_STATE_CONFIRMED,
|
||||
provider='testdummy_partialrefund'
|
||||
)
|
||||
cancel_order(self.order.pk, cancellation_fee=2, try_auto_refund=True)
|
||||
cancel_order(self.order.pk, cancellation_fee=Decimal("2.00"), try_auto_refund=True)
|
||||
r = self.order.refunds.get()
|
||||
assert r.state == OrderRefund.REFUND_STATE_DONE
|
||||
assert r.amount == Decimal('44.00')
|
||||
@@ -1190,7 +1190,7 @@ class OrderCancelTests(TestCase):
|
||||
provider='giftcard',
|
||||
info='{"gift_card": %d}' % gc.pk
|
||||
)
|
||||
cancel_order(self.order.pk, cancellation_fee=2, try_auto_refund=True)
|
||||
cancel_order(self.order.pk, cancellation_fee=Decimal("2.00"), try_auto_refund=True)
|
||||
r = self.order.refunds.get()
|
||||
assert r.state == OrderRefund.REFUND_STATE_DONE
|
||||
assert r.amount == Decimal('44.00')
|
||||
@@ -1209,7 +1209,7 @@ class OrderCancelTests(TestCase):
|
||||
state=OrderPayment.PAYMENT_STATE_CONFIRMED,
|
||||
provider='testdummy_partialrefund'
|
||||
)
|
||||
cancel_order(self.order.pk, cancellation_fee=2, try_auto_refund=True)
|
||||
cancel_order(self.order.pk, cancellation_fee=Decimal("2.00"), try_auto_refund=True)
|
||||
r = self.order.refunds.get()
|
||||
assert r.state == OrderRefund.REFUND_STATE_DONE
|
||||
assert gc.value == Decimal('0.00')
|
||||
@@ -1224,7 +1224,7 @@ class OrderCancelTests(TestCase):
|
||||
provider='testdummy_partialrefund'
|
||||
)
|
||||
with pytest.raises(OrderError):
|
||||
cancel_order(self.order.pk, cancellation_fee=2, try_auto_refund=True)
|
||||
cancel_order(self.order.pk, cancellation_fee=Decimal("2.00"), try_auto_refund=True)
|
||||
assert gc.value == Decimal('20.00')
|
||||
|
||||
@classscope(attr='o')
|
||||
@@ -1234,7 +1234,7 @@ class OrderCancelTests(TestCase):
|
||||
state=OrderPayment.PAYMENT_STATE_CONFIRMED,
|
||||
provider='testdummy_fullrefund'
|
||||
)
|
||||
cancel_order(self.order.pk, cancellation_fee=2, try_auto_refund=True)
|
||||
cancel_order(self.order.pk, cancellation_fee=Decimal("2.00"), try_auto_refund=True)
|
||||
assert not self.order.refunds.exists()
|
||||
assert self.order.all_logentries().filter(action_type='pretix.event.order.refund.requested').exists()
|
||||
|
||||
@@ -1258,7 +1258,7 @@ class OrderChangeManagerTests(TestCase):
|
||||
provider='banktransfer', state=OrderPayment.PAYMENT_STATE_CREATED, amount=self.order.total
|
||||
)
|
||||
self.tr7 = self.event.tax_rules.create(rate=Decimal('7.00'))
|
||||
self.tr19 = self.event.tax_rules.create(rate=Decimal('19.00'))
|
||||
self.tr19 = self.event.tax_rules.create(rate=Decimal('19.00'), default=True)
|
||||
self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', tax_rule=self.tr7,
|
||||
default_price=Decimal('23.00'), admission=True)
|
||||
self.ticket2 = Item.objects.create(event=self.event, name='Other ticket', tax_rule=self.tr7,
|
||||
@@ -1868,7 +1868,6 @@ class OrderChangeManagerTests(TestCase):
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_payment_fee_calculation(self):
|
||||
self.event.settings.set('tax_rate_default', self.tr19.pk)
|
||||
prov = self.ocm._get_payment_provider()
|
||||
prov.settings.set('_fee_abs', Decimal('0.30'))
|
||||
self.ocm.change_price(self.op1, Decimal('24.00'))
|
||||
@@ -1882,7 +1881,6 @@ class OrderChangeManagerTests(TestCase):
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_pending_free_order_stays_pending(self):
|
||||
self.event.settings.set('tax_rate_default', self.tr19.pk)
|
||||
self.ocm.change_price(self.op1, Decimal('0.00'))
|
||||
self.ocm.change_price(self.op2, Decimal('0.00'))
|
||||
self.ocm.commit()
|
||||
@@ -2270,7 +2268,6 @@ class OrderChangeManagerTests(TestCase):
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_recalculate_country_rate(self):
|
||||
self.event.settings.set('tax_rate_default', self.tr19.pk)
|
||||
prov = self.ocm._get_payment_provider()
|
||||
prov.settings.set('_fee_abs', Decimal('0.30'))
|
||||
self.ocm._recalculate_total_and_payment_fee()
|
||||
@@ -2303,7 +2300,6 @@ class OrderChangeManagerTests(TestCase):
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_recalculate_country_rate_keep_gross(self):
|
||||
self.event.settings.set('tax_rate_default', self.tr19.pk)
|
||||
prov = self.ocm._get_payment_provider()
|
||||
prov.settings.set('_fee_abs', Decimal('0.30'))
|
||||
self.ocm._recalculate_total_and_payment_fee()
|
||||
@@ -2334,7 +2330,6 @@ class OrderChangeManagerTests(TestCase):
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_recalculate_reverse_charge(self):
|
||||
self.event.settings.set('tax_rate_default', self.tr19.pk)
|
||||
prov = self.ocm._get_payment_provider()
|
||||
prov.settings.set('_fee_abs', Decimal('0.30'))
|
||||
self.ocm._recalculate_total_and_payment_fee()
|
||||
@@ -2493,7 +2488,6 @@ class OrderChangeManagerTests(TestCase):
|
||||
@classscope(attr='o')
|
||||
def test_split_pending_payment_fees(self):
|
||||
# Set payment fees
|
||||
self.event.settings.set('tax_rate_default', self.tr19.pk)
|
||||
prov = self.ocm._get_payment_provider()
|
||||
prov.settings.set('_fee_percent', Decimal('2.00'))
|
||||
prov.settings.set('_fee_abs', Decimal('1.00'))
|
||||
@@ -2697,7 +2691,6 @@ class OrderChangeManagerTests(TestCase):
|
||||
ia = self._enable_reverse_charge()
|
||||
|
||||
# Set payment fees
|
||||
self.event.settings.set('tax_rate_default', self.tr19.pk)
|
||||
prov = self.ocm._get_payment_provider()
|
||||
prov.settings.set('_fee_percent', Decimal('2.00'))
|
||||
prov.settings.set('_fee_reverse_calc', False)
|
||||
@@ -2791,7 +2784,6 @@ class OrderChangeManagerTests(TestCase):
|
||||
@classscope(attr='o')
|
||||
def test_split_paid_payment_fees(self):
|
||||
# Set payment fees
|
||||
self.event.settings.set('tax_rate_default', self.tr19.pk)
|
||||
prov = self.ocm._get_payment_provider()
|
||||
prov.settings.set('_fee_percent', Decimal('2.00'))
|
||||
prov.settings.set('_fee_abs', Decimal('1.00'))
|
||||
|
||||
@@ -27,8 +27,11 @@ from django.utils.timezone import now
|
||||
from django_countries.fields import Country
|
||||
from django_scopes import scope
|
||||
|
||||
from pretix.base.models import Event, InvoiceAddress, Organizer, TaxRule
|
||||
from pretix.base.models import (
|
||||
Event, InvoiceAddress, OrderFee, OrderPosition, Organizer, TaxRule,
|
||||
)
|
||||
from pretix.base.models.tax import TaxedPrice
|
||||
from pretix.base.services.tax import split_fee_for_taxes
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -962,3 +965,39 @@ def test_allow_negative(event):
|
||||
price_includes_tax=True,
|
||||
)
|
||||
assert tr.tax(Decimal('-100.00')).gross == Decimal("-100.00")
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_split_fees(event):
|
||||
tr19 = TaxRule(rate=Decimal("19.00"), pk=1)
|
||||
tr7 = TaxRule(rate=Decimal("7.00"), pk=2)
|
||||
item = event.items.create(name="Budget Ticket", default_price=23)
|
||||
|
||||
op1 = OrderPosition(price=Decimal("11.90"), item=item)
|
||||
op1._calculate_tax(tax_rule=tr19, invoice_address=InvoiceAddress())
|
||||
op2 = OrderPosition(price=Decimal("10.70"), item=item)
|
||||
op2._calculate_tax(tax_rule=tr7, invoice_address=InvoiceAddress())
|
||||
of1 = OrderFee(value=Decimal("5.00"), fee_type=OrderFee.FEE_TYPE_SHIPPING)
|
||||
of1._calculate_tax(tax_rule=tr7, invoice_address=InvoiceAddress())
|
||||
|
||||
# Example of a 10% service fee
|
||||
assert split_fee_for_taxes([op1, op2], Decimal("2.26"), event) == [
|
||||
(tr7, Decimal("1.07")),
|
||||
(tr19, Decimal("1.19")),
|
||||
]
|
||||
|
||||
# Example of a full cancellation fee
|
||||
assert split_fee_for_taxes([op1, op2], Decimal("22.60"), event) == [
|
||||
(tr7, Decimal("10.70")),
|
||||
(tr19, Decimal("11.90")),
|
||||
]
|
||||
assert split_fee_for_taxes([op1, op2, of1], Decimal("27.60"), event) == [
|
||||
(tr7, Decimal("15.70")),
|
||||
(tr19, Decimal("11.90")),
|
||||
]
|
||||
|
||||
# Example that rounding always is done with benefit to the highest tax rate
|
||||
assert split_fee_for_taxes([op1, op2], Decimal("0.03"), event) == [
|
||||
(tr7, Decimal("0.01")),
|
||||
(tr19, Decimal("0.02")),
|
||||
]
|
||||
|
||||
@@ -443,19 +443,17 @@ class EventsTest(SoupTest):
|
||||
assert self.event1.settings.get('payment_banktransfer__fee_abs', as_type=Decimal) == Decimal('12.23')
|
||||
|
||||
def test_payment_settings(self):
|
||||
tr19 = self.event1.tax_rules.create(rate=Decimal('19.00'))
|
||||
self.get_doc('/control/event/%s/%s/settings/payment' % (self.orga1.slug, self.event1.slug))
|
||||
self.post_doc('/control/event/%s/%s/settings/payment' % (self.orga1.slug, self.event1.slug), {
|
||||
'payment_term_days': '2',
|
||||
'payment_term_minutes': '30',
|
||||
'payment_term_mode': 'days',
|
||||
'tax_rate_default': tr19.pk,
|
||||
'tax_rule_payment': 'default',
|
||||
})
|
||||
self.event1.settings.flush()
|
||||
assert self.event1.settings.get('payment_term_days', as_type=int) == 2
|
||||
|
||||
def test_payment_settings_last_date_payment_after_presale_end(self):
|
||||
tr19 = self.event1.tax_rules.create(rate=Decimal('19.00'))
|
||||
self.event1.presale_end = now()
|
||||
self.event1.save(update_fields=['presale_end'])
|
||||
doc = self.post_doc('/control/event/%s/%s/settings/payment' % (self.orga1.slug, self.event1.slug), {
|
||||
@@ -464,15 +462,13 @@ class EventsTest(SoupTest):
|
||||
'payment_term_last_1': (self.event1.presale_end - datetime.timedelta(1)).strftime('%Y-%m-%d'),
|
||||
'payment_term_last_2': '0',
|
||||
'payment_term_last_3': 'date_from',
|
||||
'tax_rate_default': tr19.pk,
|
||||
'tax_rule_payment': 'default',
|
||||
})
|
||||
assert doc.select('.alert-danger')
|
||||
self.event1.presale_end = None
|
||||
self.event1.save(update_fields=['presale_end'])
|
||||
|
||||
def test_payment_settings_relative_date_payment_after_presale_end(self):
|
||||
with scopes_disabled():
|
||||
tr19 = self.event1.tax_rules.create(rate=Decimal('19.00'))
|
||||
self.event1.presale_end = self.event1.date_from - datetime.timedelta(days=5)
|
||||
self.event1.save(update_fields=['presale_end'])
|
||||
doc = self.post_doc('/control/event/%s/%s/settings/payment' % (self.orga1.slug, self.event1.slug), {
|
||||
@@ -481,7 +477,7 @@ class EventsTest(SoupTest):
|
||||
'payment_term_last_1': '',
|
||||
'payment_term_last_2': '10',
|
||||
'payment_term_last_3': 'date_from',
|
||||
'tax_rate_default': tr19.pk,
|
||||
'tax_rule_payment': 'default',
|
||||
})
|
||||
assert doc.select('.alert-danger')
|
||||
self.event1.presale_end = None
|
||||
@@ -912,7 +908,7 @@ class EventsTest(SoupTest):
|
||||
def test_create_event_copy_success(self):
|
||||
with scopes_disabled():
|
||||
tr = self.event1.tax_rules.create(
|
||||
rate=19, name="VAT"
|
||||
rate=19, name="VAT", default=True
|
||||
)
|
||||
q1 = self.event1.quotas.create(
|
||||
name='Foo',
|
||||
@@ -923,7 +919,6 @@ class EventsTest(SoupTest):
|
||||
category=None, default_price=23, tax_rule=tr,
|
||||
admission=True, hidden_if_available=q1
|
||||
)
|
||||
self.event1.settings.tax_rate_default = tr
|
||||
doc = self.get_doc('/control/events/add')
|
||||
|
||||
doc = self.post_doc('/control/events/add', {
|
||||
@@ -990,14 +985,13 @@ class EventsTest(SoupTest):
|
||||
def test_create_event_clone_success(self):
|
||||
with scopes_disabled():
|
||||
tr = self.event1.tax_rules.create(
|
||||
rate=19, name="VAT"
|
||||
rate=19, name="VAT", default=True
|
||||
)
|
||||
self.event1.items.create(
|
||||
name='Early-bird ticket',
|
||||
category=None, default_price=23, tax_rule=tr,
|
||||
admission=True
|
||||
)
|
||||
self.event1.settings.tax_rate_default = tr
|
||||
doc = self.get_doc('/control/events/add?clone=' + str(self.event1.pk))
|
||||
tabletext = doc.select("form")[0].text
|
||||
self.assertIn("CCC", tabletext)
|
||||
|
||||
@@ -439,8 +439,37 @@ def test_order_cancel_paid_keep_fee(client, env):
|
||||
o.payments.create(state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=o.total)
|
||||
o.status = Order.STATUS_PAID
|
||||
o.save()
|
||||
tr7 = o.event.tax_rules.create(rate=Decimal('7.00'))
|
||||
o.event.settings.tax_rate_default = tr7
|
||||
o.event.tax_rules.create(rate=Decimal('7.00'), default=True)
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
client.get('/control/event/dummy/dummy/orders/FOO/transition?status=c')
|
||||
client.post('/control/event/dummy/dummy/orders/FOO/transition', {
|
||||
'status': 'c',
|
||||
'cancellation_fee': '6.00'
|
||||
})
|
||||
with scopes_disabled():
|
||||
o = Order.objects.get(id=env[2].id)
|
||||
assert not o.positions.exists()
|
||||
assert o.all_positions.exists()
|
||||
f = o.fees.get()
|
||||
assert f.fee_type == OrderFee.FEE_TYPE_CANCELLATION
|
||||
assert f.value == Decimal('6.00')
|
||||
assert f.tax_value == Decimal('0.00')
|
||||
assert f.tax_rate == Decimal('0.00')
|
||||
assert f.tax_rule is None
|
||||
assert o.status == Order.STATUS_PAID
|
||||
assert o.total == Decimal('6.00')
|
||||
assert o.pending_sum == Decimal('-8.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_cancel_paid_keep_fee_taxed(client, env):
|
||||
env[0].settings.tax_rule_cancellation = "default"
|
||||
with scopes_disabled():
|
||||
o = Order.objects.get(id=env[2].id)
|
||||
o.payments.create(state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=o.total)
|
||||
o.status = Order.STATUS_PAID
|
||||
o.save()
|
||||
tr7 = o.event.tax_rules.create(rate=Decimal('7.00'), default=True)
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
client.get('/control/event/dummy/dummy/orders/FOO/transition?status=c')
|
||||
client.post('/control/event/dummy/dummy/orders/FOO/transition', {
|
||||
@@ -462,6 +491,50 @@ def test_order_cancel_paid_keep_fee(client, env):
|
||||
assert o.pending_sum == Decimal('-8.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_cancel_paid_keep_fee_tax_split(client, env):
|
||||
env[0].settings.tax_rule_cancellation = "split"
|
||||
with scopes_disabled():
|
||||
o = Order.objects.get(id=env[2].id)
|
||||
o.payments.create(state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=o.total)
|
||||
o.status = Order.STATUS_PAID
|
||||
o.save()
|
||||
tr7 = o.event.tax_rules.create(rate=Decimal('7.00'), default=False)
|
||||
tr19 = o.event.tax_rules.create(rate=Decimal('19.00'), default=True)
|
||||
op1 = o.positions.first()
|
||||
op1._calculate_tax(tax_rule=tr7)
|
||||
op1.save()
|
||||
op2 = o.all_positions.last()
|
||||
op2.canceled = False
|
||||
op2._calculate_tax(tax_rule=tr19)
|
||||
op2.save()
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
client.get('/control/event/dummy/dummy/orders/FOO/transition?status=c')
|
||||
client.post('/control/event/dummy/dummy/orders/FOO/transition', {
|
||||
'status': 'c',
|
||||
'cancellation_fee': '6.00'
|
||||
})
|
||||
with scopes_disabled():
|
||||
o = Order.objects.get(id=env[2].id)
|
||||
assert not o.positions.exists()
|
||||
assert o.all_positions.exists()
|
||||
f = o.fees.order_by("-tax_rate")
|
||||
assert len(f) == 2
|
||||
assert f[0].fee_type == OrderFee.FEE_TYPE_CANCELLATION
|
||||
assert f[0].value == Decimal('3.00')
|
||||
assert f[0].tax_value == Decimal('0.48')
|
||||
assert f[0].tax_rate == Decimal('19')
|
||||
assert f[0].tax_rule == tr19
|
||||
assert f[1].fee_type == OrderFee.FEE_TYPE_CANCELLATION
|
||||
assert f[1].value == Decimal('3.00')
|
||||
assert f[1].tax_value == Decimal('0.20')
|
||||
assert f[1].tax_rate == Decimal('7')
|
||||
assert f[1].tax_rule == tr7
|
||||
assert o.status == Order.STATUS_PAID
|
||||
assert o.total == Decimal('6.00')
|
||||
assert o.pending_sum == Decimal('-8.00')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_cancel_pending_keep_fee(client, env):
|
||||
with scopes_disabled():
|
||||
|
||||
@@ -104,6 +104,7 @@ event_urls = [
|
||||
"settings/tax/add",
|
||||
"settings/tax/1/",
|
||||
"settings/tax/1/delete",
|
||||
"settings/tax/1/default",
|
||||
"items/",
|
||||
"items/add",
|
||||
"items/1/",
|
||||
@@ -318,6 +319,7 @@ event_permission_urls = [
|
||||
("can_change_event_settings", "settings/tax/1/", 404, HTTP_GET),
|
||||
("can_change_event_settings", "settings/tax/add", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/tax/1/delete", 404, HTTP_GET),
|
||||
("can_change_event_settings", "settings/tax/1/default", 404, HTTP_POST),
|
||||
("can_change_event_settings", "comment/", 405, HTTP_GET),
|
||||
# Lists are currently not access-controlled
|
||||
# ("can_change_items", "items/", 200),
|
||||
|
||||
@@ -56,9 +56,22 @@ class TaxRateFormTest(SoupTest):
|
||||
assert doc.select(".alert-success")
|
||||
self.assertIn("VAT", doc.select("#page-wrapper table")[0].text)
|
||||
with scopes_disabled():
|
||||
assert self.event1.tax_rules.get(
|
||||
tr = self.event1.tax_rules.get(
|
||||
rate=19, price_includes_tax=True, eu_reverse_charge=False
|
||||
)
|
||||
assert tr.default
|
||||
|
||||
def test_set_default(self):
|
||||
with scopes_disabled():
|
||||
tr = self.event1.tax_rules.create(rate=19, name="VAT")
|
||||
tr2 = self.event1.tax_rules.create(rate=7, name="VAT", default=True)
|
||||
doc = self.post_doc('/control/event/%s/%s/settings/tax/%s/default' % (self.orga1.slug, self.event1.slug, tr.id),
|
||||
{})
|
||||
assert doc.select(".alert-success")
|
||||
tr.refresh_from_db()
|
||||
assert tr.default
|
||||
tr2.refresh_from_db()
|
||||
assert not tr2.default
|
||||
|
||||
def test_update(self):
|
||||
with scopes_disabled():
|
||||
@@ -98,8 +111,8 @@ class TaxRateFormTest(SoupTest):
|
||||
|
||||
def test_delete_default_rule(self):
|
||||
with scopes_disabled():
|
||||
tr = self.event1.tax_rules.create(rate=19, name="VAT")
|
||||
self.event1.settings.tax_rate_default = tr
|
||||
tr = self.event1.tax_rules.create(rate=19, name="VAT", default=True)
|
||||
self.event1.tax_rules.create(rate=7, name="V2")
|
||||
doc = self.get_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id))
|
||||
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
|
||||
doc = self.post_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id),
|
||||
|
||||
@@ -483,7 +483,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
assert cr1.price == Decimal('23.00')
|
||||
|
||||
def test_custom_tax_rules_blocked_on_fee(self):
|
||||
self.tr7 = self.event.tax_rules.create(rate=7)
|
||||
self.tr7 = self.event.tax_rules.create(rate=7, default=True)
|
||||
self.tr7.custom_rules = json.dumps([
|
||||
{'country': 'AT', 'address_type': 'business_vat_id', 'action': 'reverse'},
|
||||
{'country': 'ZZ', 'address_type': '', 'action': 'block'},
|
||||
@@ -492,7 +492,6 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
self.event.settings.set('payment_banktransfer__enabled', True)
|
||||
self.event.settings.set('payment_banktransfer__fee_percent', 20)
|
||||
self.event.settings.set('payment_banktransfer__fee_reverse_calc', False)
|
||||
self.event.settings.set('tax_rate_default', self.tr7)
|
||||
self.event.settings.invoice_address_vatid = True
|
||||
|
||||
with scopes_disabled():
|
||||
|
||||
Reference in New Issue
Block a user