diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index e8b4bf9411..5c9556f141 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -1630,7 +1630,7 @@ class OrderChangeManager: MembershipOperation = namedtuple('MembershipOperation', ('position', 'membership')) CancelOperation = namedtuple('CancelOperation', ('position', 'price_diff')) AddOperation = namedtuple('AddOperation', ('item', 'variation', 'price', 'addon_to', 'subevent', 'seat', 'membership', - 'valid_from', 'valid_until', 'is_bundled')) + 'valid_from', 'valid_until', 'is_bundled', 'result')) SplitOperation = namedtuple('SplitOperation', ('position',)) FeeValueOperation = namedtuple('FeeValueOperation', ('fee', 'value', 'price_diff')) AddFeeOperation = namedtuple('AddFeeOperation', ('fee', 'price_diff')) @@ -1642,6 +1642,18 @@ class OrderChangeManager: AddBlockOperation = namedtuple('AddBlockOperation', ('position', 'block_name', 'ignore_from_quota_while_blocked')) RemoveBlockOperation = namedtuple('RemoveBlockOperation', ('position', 'block_name', 'ignore_from_quota_while_blocked')) + class AddPositionResult: + _position: Optional[OrderPosition] + + def __init__(self): + self._position = None + + @property + def position(self) -> OrderPosition: + if self._position is None: + raise RuntimeError("Order position has not been created yet. Call commit() first on OrderChangeManager.") + return self._position + def __init__(self, order: Order, user=None, auth=None, notify=True, reissue_invoice=True, allow_blocked_seats=False): self.order = order self.user = user @@ -1846,7 +1858,7 @@ class OrderChangeManager: def add_position(self, item: Item, variation: ItemVariation, price: Decimal, addon_to: OrderPosition = None, subevent: SubEvent = None, seat: Seat = None, membership: Membership = None, - valid_from: datetime = None, valid_until: datetime = None): + valid_from: datetime = None, valid_until: datetime = None) -> 'OrderChangeManager.AddPositionResult': if isinstance(seat, str): if not seat: seat = None @@ -1905,8 +1917,11 @@ class OrderChangeManager: self._quotadiff.update(new_quotas) if seat: self._seatdiff.update([seat]) + + result = self.AddPositionResult() self._operations.append(self.AddOperation(item, variation, price, addon_to, subevent, seat, membership, - valid_from, valid_until, is_bundled)) + valid_from, valid_until, is_bundled, result)) + return result def split(self, position: OrderPosition): if self.order.event.settings.invoice_include_free or position.price != Decimal('0.00'): @@ -2525,6 +2540,7 @@ class OrderChangeManager: 'valid_from': op.valid_from.isoformat() if op.valid_from else None, 'valid_until': op.valid_until.isoformat() if op.valid_until else None, }) + op.result._position = pos elif isinstance(op, self.SplitOperation): position = position_cache.setdefault(op.position.pk, op.position) split_positions.append(position) diff --git a/src/tests/base/test_orders.py b/src/tests/base/test_orders.py index 486fb24a70..b46745a368 100644 --- a/src/tests/base/test_orders.py +++ b/src/tests/base/test_orders.py @@ -2465,6 +2465,16 @@ class OrderChangeManagerTests(TestCase): assert nop.price == Decimal('12.00') assert nop.subevent == se1 + @classscope(attr='o') + def test_add_item_result_value(self): + res_shirt = self.ocm.add_position(self.shirt, None, None, None) + res_ticket2 = self.ocm.add_position(self.ticket2, None, None, None) + with self.assertRaises(RuntimeError): + _ = res_ticket2.position + self.ocm.commit() + assert res_shirt.position.item == self.shirt + assert res_ticket2.position.item == self.ticket2 + @classscope(attr='o') def test_add_item_with_rounding(self): self.order.tax_rounding_mode = "sum_by_net"