Discounts: Fix edge case in computation (#4126)

* Add new test case for discounts:

Two discounts:
- "For every 1 item1, you get three item2 for 10 % off."
- "For every 1 item1, you get five item3 for 10 % off."
Cart: 2x item1, 2x item2, 6x item3
Expected result: 2x item1 full price, 2x item2 discounted, 5x item3 discounted, 1x item3 full price

* Fix discount calculation bug

* Update src/pretix/base/models/discount.py

Co-authored-by: Raphael Michel <michel@rami.io>

* Update src/pretix/base/models/discount.py

Co-authored-by: Richard Schreiber <schreiber@rami.io>

---------

Co-authored-by: Raphael Michel <michel@rami.io>
Co-authored-by: Richard Schreiber <schreiber@rami.io>
This commit is contained in:
Mira
2024-05-02 18:21:56 +02:00
committed by GitHub
parent d2b96b2425
commit 541b8f5bd6
2 changed files with 70 additions and 1 deletions

View File

@@ -51,6 +51,11 @@ def item2(event):
return event.items.create(name='Ticket II', default_price=Decimal('50.00'))
@pytest.fixture
def item3(event):
return event.items.create(name='Ticket III', default_price=Decimal('42.00'))
@pytest.fixture
def voucher(event):
return event.vouchers.create()
@@ -1338,3 +1343,66 @@ def test_multiple_discounts_with_benefit_condition_overlap(event, item, item2):
new_prices = [p for p, d in apply_discounts(event, 'web', positions)]
assert sorted(new_prices) == sorted(expected)
@pytest.mark.django_db
@scopes_disabled()
def test_multiple_discounts_with_same_condition(event, item, item2, item3):
# "For every 1 item1, you get three item2 for 10 % off." + "For every 1 item1, you get five item3 for 10 % off."
d1 = Discount(
event=event,
condition_min_count=1,
condition_all_products=False,
benefit_only_apply_to_cheapest_n_matches=3,
benefit_discount_matching_percent=10,
benefit_same_products=False,
position=1,
)
d1.save()
d1.condition_limit_products.add(item)
d1.benefit_limit_products.add(item2)
d2 = Discount(
event=event,
condition_min_count=1,
condition_all_products=False,
benefit_only_apply_to_cheapest_n_matches=5,
benefit_discount_matching_percent=10,
benefit_same_products=False,
position=2,
)
d2.save()
d2.condition_limit_products.add(item)
d2.benefit_limit_products.add(item3)
positions = (
(item3.pk, None, Decimal('42.00'), False, False, Decimal('0.00')),
(item3.pk, None, Decimal('42.00'), False, False, Decimal('0.00')),
(item3.pk, None, Decimal('42.00'), False, False, Decimal('0.00')),
(item3.pk, None, Decimal('42.00'), False, False, Decimal('0.00')),
(item3.pk, None, Decimal('42.00'), False, False, Decimal('0.00')),
(item3.pk, None, Decimal('42.00'), False, False, Decimal('0.00')),
(item2.pk, None, Decimal('50.00'), False, False, Decimal('0.00')),
(item2.pk, None, Decimal('50.00'), False, False, Decimal('0.00')),
(item.pk, None, Decimal('23.00'), False, False, Decimal('0.00')),
(item.pk, None, Decimal('23.00'), False, False, Decimal('0.00')),
)
expected = (
# both item1 remain full price
Decimal('23.00'),
Decimal('23.00'),
# 5 item3 discounted
Decimal('37.80'),
Decimal('37.80'),
Decimal('37.80'),
Decimal('37.80'),
Decimal('37.80'),
# 2 item2 discounted
Decimal('45.00'),
Decimal('45.00'),
# 1 item3 remains untouched
Decimal('42.00'),
)
new_prices = [p for p, d in apply_discounts(event, 'web', positions)]
assert sorted(new_prices) == sorted(expected)