Cross selling (#4185)

Product categories can now be marked as "cross-selling categories", causing them to 
appear in the add-on checkout step as additional recommendations, depending on 
their cross-selling visibility (always, only if certain products are already in the cart, or 
only if they qualify for a discount according to discount rules).

---------

Co-authored-by: Raphael Michel <michel@rami.io>
Co-authored-by: Richard Schreiber <schreiber@rami.io>
This commit is contained in:
Mira
2024-10-14 14:39:49 +02:00
committed by GitHub
parent 7607cc5d2f
commit 359df1f51e
24 changed files with 1737 additions and 218 deletions

View File

@@ -1542,10 +1542,9 @@ def add_items_to_cart(self, event: int, items: List[dict], cart_id: str=None, lo
@app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,))
def apply_voucher(self, event: Event, voucher: str, cart_id: str=None, locale='en', sales_channel='web', override_now_dt: datetime=None) -> None:
"""
Removes a list of items from a user's cart.
:param event: The event ID in question
:param voucher: A voucher code
:param session: Session ID of a guest
:param cart_id: The cart ID of the cart to modify
"""
with language(locale), time_machine_now_assigned(override_now_dt):
try:
@@ -1566,10 +1565,10 @@ def apply_voucher(self, event: Event, voucher: str, cart_id: str=None, locale='e
@app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,))
def remove_cart_position(self, event: Event, position: int, cart_id: str=None, locale='en', sales_channel='web', override_now_dt: datetime=None) -> None:
"""
Removes a list of items from a user's cart.
Removes an item specified by its position ID from a user's cart.
:param event: The event ID in question
:param position: A cart position ID
:param session: Session ID of a guest
:param cart_id: The cart ID of the cart to modify
"""
with language(locale), time_machine_now_assigned(override_now_dt):
try:
@@ -1590,9 +1589,9 @@ def remove_cart_position(self, event: Event, position: int, cart_id: str=None, l
@app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,))
def clear_cart(self, event: Event, cart_id: str=None, locale='en', sales_channel='web', override_now_dt: datetime=None) -> None:
"""
Removes a list of items from a user's cart.
Removes all items from a user's cart.
:param event: The event ID in question
:param session: Session ID of a guest
:param cart_id: The cart ID of the cart to modify
"""
with language(locale), time_machine_now_assigned(override_now_dt):
try:
@@ -1611,13 +1610,15 @@ def clear_cart(self, event: Event, cart_id: str=None, locale='en', sales_channel
@app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,))
def set_cart_addons(self, event: Event, addons: List[dict], cart_id: str=None, locale='en',
def set_cart_addons(self, event: Event, addons: List[dict], add_to_cart_items: List[dict], cart_id: str=None, locale='en',
invoice_address: int=None, sales_channel='web', override_now_dt: datetime=None) -> None:
"""
Removes a list of items from a user's cart.
Assigns addons to eligible products in a user's cart, adding and removing the addon products as necessary to
ensure the requested addon state.
:param event: The event ID in question
:param addons: A list of dicts with the keys addon_to, item, variation
:param session: Session ID of a guest
:param add_to_cart_items: A list of dicts with the keys item, variation, count, custom_price, voucher, seat ID
:param cart_id: The cart ID of the cart to modify
"""
with language(locale), time_machine_now_assigned(override_now_dt):
ia = False
@@ -1635,6 +1636,7 @@ def set_cart_addons(self, event: Event, addons: List[dict], cart_id: str=None, l
try:
cm = CartManager(event=event, cart_id=cart_id, invoice_address=ia, sales_channel=sales_channel)
cm.set_addons(addons)
cm.add_new_items(add_to_cart_items)
cm.commit()
except LockTimeoutException:
self.retry()