Source code for app.orders

from itertools import count

from app.pydantic_models import Order, CartItem
from app.state_machine import StateMachine
from app.cart import CartManager
from app.inventory import InventoryManager
from app.config import discount_strategy, shipping_strategy

# In-memory storage for orders: order_id -> (Order, StateMachine)
_ORDERS: dict[int, tuple[Order, StateMachine]] = {}
_order_seq = count(start=1)


def _calculate_order_breakdown(items: list[CartItem]) -> dict[str, float]:
    """
    Calculate pricing breakdown for a list of order items.

    Args:
        items: List of CartItem objects

    Returns:
        dict: Breakdown with subtotal, discount, shipping, and total
    """
    # Calculate subtotal (price before discounts and shipping)
    subtotal = 0.0
    for it in items:
        p = InventoryManager.get_instance().get_product(it.product_id)
        assert p is not None
        subtotal += p.price * it.quantity

    # Prepare items list for shipping calculation
    items_for_shipping = [(it.product_id, it.quantity) for it in items]

    # Apply discount and shipping strategies
    discount = discount_strategy.calculate_discount(subtotal)
    shipping = shipping_strategy.calculate_shipping(subtotal, items_for_shipping)

    # Calculate final total
    total = subtotal - discount + shipping

    return {
        "subtotal": round(subtotal, 2),
        "discount": round(discount, 2),
        "shipping": round(shipping, 2),
        "total": round(total, 2)
    }

[docs] def create_order(cart_id: str = "default") -> Order: """ Create an order from a shopping cart. Validates stock availability for every item in the cart, decrements the inventory, computes the total price, and clears the cart. Args: cart_id: The identifier of the cart to order from. Defaults to "default". Returns: Order: The newly created order. Raises: ValueError: If any product in the cart has insufficient stock. """ cart = CartManager.get_instance().get_cart(cart_id) items: list[CartItem] = [] for pid, qty in cart.items.items(): if not InventoryManager.get_instance().has_stock(pid, qty): raise ValueError(f"Insufficient stock for product {pid}") items.append(CartItem(product_id=pid, quantity=qty)) for it in items: InventoryManager.get_instance().decrement_stock(it.product_id, it.quantity) # Calculate subtotal (price before discounts and shipping) subtotal = 0.0 for it in items: p = InventoryManager.get_instance().get_product(it.product_id) assert p is not None subtotal += p.price * it.quantity # Prepare items list for shipping calculation items_for_shipping = [(it.product_id, it.quantity) for it in items] # Apply discount and shipping strategies discount = discount_strategy.calculate_discount(subtotal) shipping = shipping_strategy.calculate_shipping(subtotal, items_for_shipping) # Calculate final total total = subtotal - discount + shipping oid = next(_order_seq) order = Order(id=oid, cart_id=cart_id, items=items, total=round(total, 2), status="created") _ORDERS[oid] = (order, StateMachine()) cart.clear() return order
[docs] def cancel_order(order_id: int): """ Cancels the order `order_id`. It restocks the ordered items into the inventory. Args: order_id: The ID of the order Raises: ValueError: If the order with the specified ID is not found in the system. """ order = get_order(order_id) inventory_manager = InventoryManager.get_instance() for item in order.items: inventory_manager.increment_stock(item.product_id, item.quantity)
[docs] def get_order_breakdown(order_id: int) -> dict[str, float]: """ Calculate the pricing breakdown for an order. Args: order_id: The ID of the order Returns: dict: Breakdown with subtotal, discount, shipping, and total """ order = get_order(order_id) return _calculate_order_breakdown(order.items)
[docs] def get_order(order_id: int) -> Order: """ Retrieves the order by its ID. Raises ValueError if the order is not found. Args: order_id: The unique identifier of the order to retrieve. Returns: The Order object corresponding to the given order_id. Raises: ValueError: If the order with the specified ID is not found in the system. """ if order_id not in _ORDERS: raise ValueError("Order not found") return _ORDERS[order_id][0]
[docs] def get_machine(order_id: int) -> StateMachine: """ Retrieves the state machine for an order by its ID. Raises ValueError if the order is not found. Args: order_id: The unique identifier of the state machine to retrieve. Returns: The StateMachine object corresponding to the given order_id. Raises: ValueError: If the state machine for the specified order ID is not found in the system. """ if order_id not in _ORDERS: raise ValueError("Order not found") return _ORDERS[order_id][1]
[docs] def set_status(order_id: int, new_status: str) -> Order: """ Updates the status of an order and triggers the state machine transition. Raises ValueError if the order is not found or if the status transition is invalid. If the new state is 'cancelled', then it calls a function to restock items. Args: order_id: The unique identifier of the order to update. new_status: The new status to set for the order. Returns: The updated Order object with the new status. Raises: ValueError: If the order with the specified ID is not found or if the status transition is invalid according to the state machine rules. """ order = get_order(order_id) machine = get_machine(order_id) machine.update(new_status) order.status = new_status if new_status == "cancelled": cancel_order(order_id) return order