diff --git a/src/pretix/base/models/tax.py b/src/pretix/base/models/tax.py index 391af5ca26..716f867643 100644 --- a/src/pretix/base/models/tax.py +++ b/src/pretix/base/models/tax.py @@ -206,7 +206,12 @@ class TaxRule(LoggedModel): base_price_is = 'net' if base_price_is == 'gross': - gross = max(Decimal('0.00'), base_price - subtract_from_gross) + if base_price >= Decimal('0.00'): + # For positive prices, make sure they don't go negative because of bundles + gross = max(Decimal('0.00'), base_price - subtract_from_gross) + else: + # If the price is already negative, we don't really care any more + gross = base_price - subtract_from_gross net = round_decimal(gross - (gross * (1 - 100 / (100 + rate))), currency) elif base_price_is == 'net': diff --git a/src/tests/api/test_orders.py b/src/tests/api/test_orders.py index 7fbafd7cf7..528e1ac354 100644 --- a/src/tests/api/test_orders.py +++ b/src/tests/api/test_orders.py @@ -2128,6 +2128,30 @@ def test_order_create_fee_with_auto_tax(token_client, organizer, event, item, qu assert o.total == Decimal('25.30') +@pytest.mark.django_db +def test_order_create_negative_fee_with_auto_tax(token_client, organizer, event, item, quota, question, taxrule): + res = copy.deepcopy(ORDER_CREATE_PAYLOAD) + res['fees'][0]['_split_taxes_like_products'] = True + res['fees'][0]['value'] = '-10.00' + res['positions'][0]['item'] = item.pk + res['positions'][0]['answers'][0]['question'] = question.pk + item.tax_rule = taxrule + item.save() + 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']) + fee = o.fees.first() + assert fee.value == Decimal('-10.00') + assert fee.tax_value == Decimal('-1.60') + assert fee.tax_rate == Decimal('19.00') + assert o.total == Decimal('13.00') + + @pytest.mark.django_db def test_order_create_tax_rule_wrong_event(token_client, organizer, event, item, quota, question, taxrule2): res = copy.deepcopy(ORDER_CREATE_PAYLOAD)