mirror of
https://github.com/pretix/pretix.git
synced 2026-05-05 15:14:04 +00:00
Allow tax rules to trigger approval requirement (#2409)
This commit is contained in:
@@ -1442,11 +1442,13 @@ class AbstractPosition(models.Model):
|
||||
lines = [r.strip() for r in lines if r]
|
||||
return '\n'.join(lines).strip()
|
||||
|
||||
def requires_approval(self):
|
||||
def requires_approval(self, invoice_address=None):
|
||||
if self.item.require_approval:
|
||||
return True
|
||||
if self.variation and self.variation.require_approval:
|
||||
return True
|
||||
if self.item.tax_rule and self.item.tax_rule._require_approval(invoice_address):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
@@ -211,7 +211,7 @@ class TaxRule(LoggedModel):
|
||||
rule = self.get_matching_rule(invoice_address)
|
||||
if rule.get('action', 'vat') == 'block':
|
||||
raise self.SaleNotAllowed()
|
||||
if rule.get('action', 'vat') == 'vat' and rule.get('rate') is not None:
|
||||
if rule.get('action', 'vat') in ('vat', 'require_approval') and rule.get('rate') is not None:
|
||||
return Decimal(rule.get('rate'))
|
||||
return Decimal(self.rate)
|
||||
|
||||
@@ -337,12 +337,19 @@ class TaxRule(LoggedModel):
|
||||
|
||||
return False
|
||||
|
||||
def _require_approval(self, invoice_address):
|
||||
if self._custom_rules:
|
||||
rule = self.get_matching_rule(invoice_address)
|
||||
if rule.get('action', 'vat') == 'require_approval':
|
||||
return True
|
||||
return False
|
||||
|
||||
def _tax_applicable(self, invoice_address):
|
||||
if self._custom_rules:
|
||||
rule = self.get_matching_rule(invoice_address)
|
||||
if rule.get('action', 'vat') == 'block':
|
||||
raise self.SaleNotAllowed()
|
||||
return rule.get('action', 'vat') == 'vat'
|
||||
return rule.get('action', 'vat') in ('vat', 'require_approval')
|
||||
|
||||
if not self.eu_reverse_charge:
|
||||
# No reverse charge rules? Always apply VAT!
|
||||
|
||||
@@ -856,7 +856,7 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d
|
||||
total=total,
|
||||
testmode=True if sales_channel.testmode_supported and event.testmode else False,
|
||||
meta_info=json.dumps(meta_info or {}),
|
||||
require_approval=any(p.requires_approval() for p in positions),
|
||||
require_approval=any(p.requires_approval(invoice_address=address) for p in positions),
|
||||
sales_channel=sales_channel.identifier,
|
||||
customer=customer,
|
||||
)
|
||||
@@ -2071,7 +2071,7 @@ class OrderChangeManager:
|
||||
split_order.code = None
|
||||
split_order.datetime = now()
|
||||
split_order.secret = generate_secret()
|
||||
split_order.require_approval = self.order.require_approval and any(p.requires_approval() for p in split_positions)
|
||||
split_order.require_approval = self.order.require_approval and any(p.requires_approval(invoice_address=self._invoice_address) for p in split_positions)
|
||||
split_order.save()
|
||||
split_order.log_action('pretix.event.order.changed.split_from', user=self.user, auth=self.auth, data={
|
||||
'original_order': self.order.code
|
||||
|
||||
@@ -1215,6 +1215,7 @@ class TaxRuleLineForm(I18nForm):
|
||||
('reverse', _('Reverse charge')),
|
||||
('no', _('No VAT')),
|
||||
('block', _('Sale not allowed')),
|
||||
('require_approval', _('Order requires approval')),
|
||||
],
|
||||
)
|
||||
rate = forms.DecimalField(
|
||||
|
||||
@@ -490,6 +490,7 @@ class OrganizerCreate(CreateView):
|
||||
organizer=form.instance, name=_('Administrators'),
|
||||
all_events=True, can_create_events=True, can_change_teams=True, can_manage_gift_cards=True,
|
||||
can_change_organizer_settings=True, can_change_event_settings=True, can_change_items=True,
|
||||
can_manage_customers=True,
|
||||
can_view_orders=True, can_change_orders=True, can_view_vouchers=True, can_change_vouchers=True
|
||||
)
|
||||
t.members.add(self.request.user)
|
||||
|
||||
@@ -1161,7 +1161,7 @@ class PaymentStep(CartMixin, TemplateFlowStep):
|
||||
self.request = request
|
||||
|
||||
for cartpos in get_cart(self.request):
|
||||
if cartpos.requires_approval():
|
||||
if cartpos.requires_approval(invoice_address=self.invoice_address):
|
||||
if 'payment' in self.cart_session:
|
||||
del self.cart_session['payment']
|
||||
return False
|
||||
@@ -1206,7 +1206,7 @@ class ConfirmStep(CartMixin, AsyncAction, TemplateFlowStep):
|
||||
if self.payment_provider:
|
||||
ctx['payment'] = self.payment_provider.checkout_confirm_render(self.request)
|
||||
ctx['payment_provider'] = self.payment_provider
|
||||
ctx['require_approval'] = any(cp.requires_approval() for cp in ctx['cart']['positions'])
|
||||
ctx['require_approval'] = any(cp.requires_approval(invoice_address=self.invoice_address) for cp in ctx['cart']['positions'])
|
||||
ctx['addr'] = self.invoice_address
|
||||
ctx['confirm_messages'] = self.confirm_messages
|
||||
ctx['cart_session'] = self.cart_session
|
||||
|
||||
@@ -448,6 +448,38 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
cr1.refresh_from_db()
|
||||
assert cr1.price == Decimal('19.33')
|
||||
|
||||
def test_custom_tax_rules_require_approval(self):
|
||||
self.tr19.custom_rules = json.dumps([
|
||||
{'country': 'AT', 'address_type': 'business_vat_id', 'action': 'reverse'},
|
||||
{'country': 'ZZ', 'address_type': '', 'action': 'require_approval'},
|
||||
])
|
||||
self.tr19.save()
|
||||
self.event.settings.invoice_address_vatid = True
|
||||
|
||||
with scopes_disabled():
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
|
||||
self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'is_business': 'business',
|
||||
'company': 'Foo',
|
||||
'name': 'Bar',
|
||||
'street': 'Baz',
|
||||
'zipcode': '12345',
|
||||
'city': 'Here',
|
||||
'country': 'DE',
|
||||
'email': 'admin@localhost'
|
||||
}, follow=True)
|
||||
|
||||
self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
with scopes_disabled():
|
||||
assert not CartPosition.objects.filter(pk=cr1.pk).exists()
|
||||
o = Order.objects.last()
|
||||
assert o.require_approval
|
||||
assert o.positions.first().tax_rate == Decimal('19.00')
|
||||
|
||||
def _test_country_taxing(self):
|
||||
self._enable_country_specific_taxing()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user