diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index 4e160036b..d78aa1217 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -1430,19 +1430,25 @@ class OrderChangeManager: fee.delete() split_order.total += fee.value + remaining_total = sum([p.price for p in self.order.positions.all()]) + sum([f.value for f in self.order.fees.all()]) + offset_amount = min(max(0, self.completed_payment_sum - remaining_total), split_order.total) + if offset_amount >= split_order.total: + split_order.status = Order.STATUS_PAID + else: + split_order.status = Order.STATUS_PENDING split_order.save() - if split_order.status == Order.STATUS_PAID: + if offset_amount > Decimal('0.00'): split_order.payments.create( state=OrderPayment.PAYMENT_STATE_CONFIRMED, - amount=split_order.total, + amount=offset_amount, payment_date=now(), provider='offsetting', info=json.dumps({'orders': [self.order.code]}) ) self.order.refunds.create( state=OrderRefund.REFUND_STATE_DONE, - amount=split_order.total, + amount=offset_amount, execution_date=now(), provider='offsetting', info=json.dumps({'orders': [split_order.code]}) diff --git a/src/tests/base/test_orders.py b/src/tests/base/test_orders.py index bef271b68..b39c43e7e 100644 --- a/src/tests/base/test_orders.py +++ b/src/tests/base/test_orders.py @@ -1517,6 +1517,86 @@ class OrderChangeManagerTests(TestCase): assert p.amount == Decimal('23.00') assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED + @classscope(attr='o') + def test_split_and_change_higher(self): + self.order.status = Order.STATUS_PAID + self.order.save() + self.order.payments.create( + provider='manual', + state=OrderPayment.PAYMENT_STATE_CONFIRMED, + amount=self.order.total, + ) + + # Split + self.ocm.change_price(self.op2, Decimal('42.00')) + self.ocm.split(self.op2) + self.ocm.commit() + self.order.refresh_from_db() + self.op2.refresh_from_db() + + # First order + assert self.order.total == Decimal('23.00') + assert not self.order.fees.exists() + assert self.order.status == Order.STATUS_PAID + assert self.order.pending_sum == Decimal('0.00') + r = self.order.refunds.last() + assert r.provider == 'offsetting' + assert r.amount == Decimal('23.00') + assert r.state == OrderRefund.REFUND_STATE_DONE + + # New order + assert self.op2.order != self.order + o2 = self.op2.order + assert o2.total == Decimal('42.00') + assert o2.status == Order.STATUS_PENDING + assert o2.positions.count() == 1 + assert o2.fees.count() == 0 + assert o2.pending_sum == Decimal('19.00') + p = o2.payments.last() + assert p.provider == 'offsetting' + assert p.amount == Decimal('23.00') + assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED + + @classscope(attr='o') + def test_split_and_change_lower(self): + self.order.status = Order.STATUS_PAID + self.order.save() + self.order.payments.create( + provider='manual', + state=OrderPayment.PAYMENT_STATE_CONFIRMED, + amount=self.order.total, + ) + + # Split + self.ocm.change_price(self.op2, Decimal('10.00')) + self.ocm.split(self.op2) + self.ocm.commit() + self.order.refresh_from_db() + self.op2.refresh_from_db() + + # First order + assert self.order.total == Decimal('23.00') + assert not self.order.fees.exists() + assert self.order.status == Order.STATUS_PAID + assert self.order.pending_sum == Decimal('-13.00') + r = self.order.refunds.last() + assert r.provider == 'offsetting' + assert r.amount == Decimal('10.00') + assert r.state == OrderRefund.REFUND_STATE_DONE + + # New order + assert self.op2.order != self.order + o2 = self.op2.order + assert o2.total == Decimal('10.00') + assert o2.status == Order.STATUS_PAID + assert o2.positions.count() == 1 + assert o2.fees.count() == 0 + assert o2.pending_sum == Decimal('0.00') + p = o2.payments.last() + assert p.provider == 'offsetting' + assert p.amount == Decimal('10.00') + assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED + @classscope(attr='o') def test_split_invoice_address(self): ia = InvoiceAddress.objects.create(