# CRM Step 03 — Backend: Orders CRUD ## Context Read `.claude/crm-build-plan.md` first for full data models, conventions, and IMPORTANT NOTES. Steps 01 and 02 must be complete. ## Task Add Orders models, service, and router to `backend/crm/`. ## What to build ### 1. Add to `backend/crm/models.py` **Enums:** - `OrderStatus` — draft, confirmed, in_production, shipped, delivered, cancelled - `PaymentStatus` — pending, partial, paid **Structs:** - `OrderDiscount` — type (str: "percentage" | "fixed"), value (float default 0), reason (Optional[str]) - `OrderShipping` — method (Optional[str]), tracking_number (Optional[str]), carrier (Optional[str]), shipped_at (Optional[str]), delivered_at (Optional[str]), destination (Optional[str]) - `OrderItem`: - type: str (console_device | product | freetext) - product_id: Optional[str] - product_name: Optional[str] - description: Optional[str] ← for freetext items - quantity: int default 1 - unit_price: float default 0.0 - serial_numbers: List[str] default [] **Order models:** - `OrderCreate` — customer_id (str), order_number (Optional[str] — auto-generated if not provided), status (OrderStatus default draft), items (List[OrderItem] default []), subtotal (float default 0), discount (Optional[OrderDiscount]), total_price (float default 0), currency (str default "EUR"), shipping (Optional[OrderShipping]), payment_status (PaymentStatus default pending), invoice_path (Optional[str]), notes (Optional[str]) - `OrderUpdate` — all fields Optional - `OrderInDB` — extends OrderCreate + id, created_at, updated_at - `OrderListResponse` — orders: List[OrderInDB], total: int ### 2. Add to `backend/crm/service.py` Firestore collection: `crm_orders` Auto order number generation: `ORD-{YYYY}-{NNN}` — query existing orders for current year, increment max. Functions: - `list_orders(customer_id=None, status=None, payment_status=None) -> List[OrderInDB]` - `get_order(order_id) -> OrderInDB` — 404 if not found - `create_order(data: OrderCreate) -> OrderInDB` — auto-generate order_number if not set - `update_order(order_id, data: OrderUpdate) -> OrderInDB` - `delete_order(order_id) -> None` ### 3. Add to `backend/crm/router.py` Prefix `/api/crm/orders`: - `GET /` — list_orders (query: customer_id, status, payment_status) - `GET /{order_id}` — get_order - `POST /` — create_order - `PUT /{order_id}` — update_order - `DELETE /{order_id}` — delete_order Register in `backend/main.py`. ## Notes - subtotal and total_price are stored as-is (calculated by frontend before POST/PUT). Backend does not recalculate. - Order number generation doesn't need to be atomic/perfect — just a best-effort sequential label.