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 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. 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 return order