shop.modules.cart

Attributes

Classes

Cart

Abstract Class for all viur-shop sub/nested modules.

Functions

delete_guest_cart(session)

Delete carts from guest sessions to avoid orphaned carts.

Module Contents

shop.modules.cart.logger
class shop.modules.cart.Cart(moduleName=None, modulePath=None, shop=None, *args, **kwargs)

Bases: viur.shop.modules.abstract.ShopModuleAbstract, viur.core.prototypes.Tree

Abstract Class for all viur-shop sub/nested modules.

The implementations should set moduleName as class variable, so the final module name for routing it not affected by the name of custom classes.

Parameters:
  • moduleName (str)

  • modulePath (str)

  • shop (viur.shop.Shop)

moduleName = 'cart'
nodeSkelCls
leafSkelCls
adminInfo()
Return type:

dict

baseSkel(skelType, sub_skel=None, *args, **kwargs)

Extend default baseSkel() by sub_skel parameter

Parameters:
  • skelType (viur.core.prototypes.tree.SkelType)

  • sub_skel (str | list[str] | None)

Return type:

viur.core.skeleton.SkeletonInstance

canView(skelType, skel)
Parameters:
  • skelType (viur.core.prototypes.tree.SkelType)

  • skel (viur.core.skeleton.SkeletonInstance)

Return type:

bool

property current_session_cart_key: viur.core.db.Key | None
Return type:

viur.core.db.Key | None

get_current_session_cart_key(*, create_if_missing=False)
Parameters:

create_if_missing (bool)

Return type:

viur.core.db.Key | None

property current_session_cart: viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartNodeSkel]
Return type:

viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartNodeSkel]

_ensure_current_session_cart()
Return type:

viur.core.db.Key

detach_session_cart()

Unlink the current cart from the session (and the user’s basket).

The cart entity itself is kept. Tolerates a session that has no session_cart_key (anymore) instead of raising a KeyError.

Returns:

The key of the detached cart, or None if none was set.

Return type:

viur.core.db.Key | None

static _set_basket_txn(user_key, basket_key)
Parameters:
  • user_key (viur.core.db.Key)

  • basket_key (viur.core.db.Key | None)

Return type:

viur.core.skeleton.SkeletonInstance

get_available_root_nodes(*args, **kwargs)
Return type:

list[dict[viur.shop.types.t.Literal[name, key], str]]

getAvailableRootNodes
listRootNodes(*args, **kwargs)

Renders a list of all available repositories for the current user using the modules default renderer.

Returns:

The rendered representation of the available root-nodes.

Return type:

viur.shop.types.t.Any

is_valid_node(node_key, root_node=False)

is this a valid node key for the user?

Parameters:
  • node_key (viur.core.db.Key) – Key of node to check

  • root_node (bool) – Must this be a root node, or is any node okay?

Return type:

bool

get_children(parent_cart_key, **filters)
Parameters:
  • parent_cart_key (viur.core.db.Key)

  • filters (viur.shop.types.t.Any)

Return type:

viur.shop.types.t.Iterator[viur.core.skeleton.SkeletonInstance]

get_children_from_cache(parent_cart_key)
Parameters:

parent_cart_key (viur.core.db.Key)

Return type:

list[viur.core.skeleton.SkeletonInstance]

clear_children_cache()
Return type:

None

cart_get(cart_key, skel_type)
Parameters:
  • cart_key (viur.core.db.Key)

  • skel_type (viur.core.prototypes.tree.SkelType)

Return type:

viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartNodeSkel | shop.skeletons.cart.CartItemSkel] | None

get_article(article_key, parent_cart_key, *, must_be_listed=True)
Parameters:
  • article_key (viur.core.db.Key)

  • parent_cart_key (viur.core.db.Key)

  • must_be_listed (bool)

Return type:

viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartItemSkel]

add_or_update_article(article_key, parent_cart_key, *, quantity, quantity_mode, **kwargs)
Parameters:
  • article_key (viur.core.db.Key)

  • parent_cart_key (viur.core.db.Key)

  • quantity (int)

  • quantity_mode (viur.shop.types.QuantityMode)

Return type:

viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartItemSkel] | None

copy_article_values(article_skel, skel)

Copy values from the article to the cart leaf

Parameters:
Return type:

viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartItemSkel]

move_article(article_key, parent_cart_key, new_parent_cart_key)
Parameters:
  • article_key (viur.core.db.Key)

  • parent_cart_key (viur.core.db.Key)

  • new_parent_cart_key (viur.core.db.Key)

Return type:

viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartItemSkel] | None

cart_add(*, parent_cart_key=None, cart_type=None, name=SENTINEL, customer_comment=SENTINEL, shipping_address_key=SENTINEL, shipping_key=SENTINEL, discount_key=SENTINEL, **kwargs)
Parameters:
  • parent_cart_key (str | viur.core.db.Key)

  • cart_type (viur.shop.types.CartType)

  • name (str)

  • customer_comment (str)

  • shipping_address_key (str | viur.core.db.Key)

  • shipping_key (str | viur.core.db.Key)

  • discount_key (str | viur.core.db.Key)

Return type:

viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartNodeSkel] | None

cart_update(cart_key, *, parent_cart_key=SENTINEL, cart_type=None, name=SENTINEL, customer_comment=SENTINEL, shipping_address_key=SENTINEL, shipping_key=SENTINEL, discount_key=SENTINEL, **kwargs)
Parameters:
  • cart_key (viur.core.db.Key)

  • parent_cart_key (str | viur.core.db.Key)

  • cart_type (viur.shop.types.CartType)

  • name (str)

  • customer_comment (str)

  • shipping_address_key (str | viur.core.db.Key)

  • shipping_key (str | viur.core.db.Key)

  • discount_key (str | viur.core.db.Key)

Return type:

viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartNodeSkel] | None

_cart_set_values(skel, *, parent_cart_key=SENTINEL, cart_type=None, name=SENTINEL, customer_comment=SENTINEL, shipping_address_key=SENTINEL, shipping_key=SENTINEL, discount_key=SENTINEL)
Parameters:
  • skel (viur.core.skeleton.SkeletonInstance | shop.skeletons.cart.CartNodeSkel)

  • parent_cart_key (viur.core.db.Key)

  • cart_type (viur.shop.types.CartType)

  • name (str)

  • customer_comment (str)

  • shipping_address_key (str | viur.core.db.Key)

  • shipping_key (str | viur.core.db.Key)

  • discount_key (str | viur.core.db.Key)

Return type:

viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartNodeSkel]

cart_remove(cart_key)

Remove a cart node with its entire subtree.

The subtree is deleted bottom-up and before the node itself: leafs first, then sub-nodes, the given node last. This order keeps the tree consistent at any point in time – if the process crashes in between, no children can be left behind whose parententry points to an already deleted node (orphaned entries). A repeated call simply continues the work (idempotent).

Frozen carts belong to an order and cannot be removed.

This also checks upfront whether the node is locked by a RelationalConsistency.PreventDeletion relation (e.g. an order referencing an in-progress checkout cart that has not been frozen yet) and fails before touching any child – deleting the children first and finding out only at skel.delete() that the node itself is locked would leave the order pointing at an emptied-out cart.

Parameters:

cart_key (viur.core.db.Key) – Key of the cart node to remove.

Raises:
  • errors.NotFound – If the cart node does not exist.

  • errors.Forbidden – If the cart node is frozen.

  • errors.Locked – If the cart node is referenced by a PreventDeletion relation (e.g. an order).

Return type:

None

_delete_children(parent_cart_key)

Delete all children of a cart node bottom-up and synchronously.

Leafs of parent_cart_key are deleted first, then each sub-node is processed recursively (its own children before the sub-node itself).

Deliberately does not call the inherited deleteRecursive() of the Tree prototype: that method is @CallDeferred and only deletes the children, while the node itself is deleted synchronously by the caller right away (see Tree.delete() / cart_remove()). If that deferred task gets lost (queue purge, crash, or the task being pinned to an App Engine version that no longer exists), the node is gone but its children survive it forever – orphaned entries whose broken parententry chain crashes price computations and update_relations tasks later. Cart trees are small (a handful of nodes/leafs), so there is no need to defer this work at all; running it synchronously, bottom-up and before the node itself is deleted removes the race entirely instead of just narrowing it.

Parameters:

parent_cart_key (viur.core.db.Key) – Key of the cart node whose subtree gets deleted.

Return type:

None

cart_clear(cart_key, *, keep_sub_carts=False)
Parameters:
  • cart_key (viur.core.db.Key)

  • keep_sub_carts (bool)

Return type:

None

additional_add_or_update_article(skel, /, **kwargs)

Hook method called by add_or_update_article() before the skeleton is saved.

This method can be overridden in a subclass to implement additional API fields or make further modifications to the cart skeleton (skel). By default, it raises an exception if unexpected arguments (kwargs) are provided and returns the unchanged skel object.

Parameters:
  • skel (viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartItemSkel]) – The current instance of the cart item skeleton.

  • kwargs – Additional optional arguments for extended implementations.

Raises:

TooManyArgumentsException – If unexpected arguments are passed in kwargs.

Returns:

The (potentially modified) cart item skeleton.

Return type:

viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartItemSkel]

additional_cart_add(skel, /, **kwargs)

Hook method called by cart_add() before the skeleton is saved.

This method can be overridden in a subclass to implement additional API fields or make further modifications to the cart skeleton (skel). By default, it raises an exception if unexpected arguments (kwargs) are provided and returns the unchanged skel object.

Parameters:
  • skel (viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartNodeSkel]) – The current instance of the cart skeleton.

  • kwargs – Additional optional arguments for extended implementations.

Raises:

TooManyArgumentsException – If unexpected arguments are passed in kwargs.

Returns:

The (potentially modified) cart skeleton.

Return type:

viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartNodeSkel]

additional_cart_update(skel, /, **kwargs)

Hook method called by cart_update() before the skeleton is saved.

This method can be overridden in a subclass to implement additional API fields or make further modifications to the cart skeleton (skel). By default, it raises an exception if unexpected arguments (kwargs) are provided and returns the unchanged skel object.

Parameters:
  • skel (viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartNodeSkel]) – The current instance of the cart skeleton.

  • kwargs – Additional optional arguments for extended implementations.

Raises:

TooManyArgumentsException – If unexpected arguments are passed in kwargs.

Returns:

The (potentially modified) cart skeleton.

Return type:

viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartNodeSkel]

freeze_cart(cart_key)

Freeze (lock) cart values and children items.

Parameters:

cart_key (viur.core.db.Key) – Key of the (sub-)cart skeleton.

Returns:

The frozen CartNode skeleton.

Return type:

viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartNodeSkel]

freeze_leaf(leaf_skel)
Parameters:

leaf_skel (viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartItemSkel])

get_discount_for_leaf(leaf_key_or_skel)

Collect the discounts of all cart nodes above the given leaf.

Walks the parententry chain from the leaf up to the root node and collects the discount relation of every node on the way.

The walk is tolerant against broken tree data: if a parent node does not exist anymore (orphaned entry) or the chain contains a cycle, the walk stops at the broken link with a warning and the discounts collected so far are returned. This keeps computed bones (e.g. the price) usable on orphaned entries instead of raising and thereby crashing deferred tasks (like update_relations) forever.

Parameters:

leaf_key_or_skel (viur.core.db.Key | viur.core.skeleton.SkeletonInstance) – Key or skeleton of the cart leaf to start from.

Returns:

The discount ref-skels found on the ancestor nodes.

Return type:

list[viur.core.skeleton.SkeletonInstance]

add_new_parent(leaf_skel, **kwargs)
get_cached_cart_skel(key)

Read a cart node skeleton with request-local caching.

Parameters:

key (viur.core.db.Key) – Key of the cart node to read.

Returns:

The cached or freshly read node skeleton or None if the node does not exist (anymore). Missing nodes are not cached, so a later call re-checks the datastore.

Return type:

viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartNodeSkel] | None

get_closest_node(start, condition=lambda skel: ...)

Walk the parententry chain upwards and return the first ancestor node that satisfies condition.

The walk stops and returns None when

  • the root node is reached without a match,

  • the current entry has no parententry (detached entry),

  • a parent node does not exist anymore (orphaned entry) or

  • the parententry chain contains a cycle.

The latter cases are broken tree states which must not crash callers like the price computation running inside deferred tasks.

Parameters:
Returns:

The closest matching ancestor node or None.

Return type:

viur.shop.types.SkeletonInstance_T[shop.skeletons.cart.CartNodeSkel] | None

shop.modules.cart.delete_guest_cart(session)

Delete carts from guest sessions to avoid orphaned carts.

Runs as Session.on_delete() hook. Any failure is logged and swallowed: this hook must never prevent the session deletion itself. Carts that are referenced by an order, already gone or frozen are left alone.

Parameters:

session (viur.core.db.Entity)

Return type:

None