"""订单路由(Controller 层,只做参数编排,业务在 Service)。""" from fastapi import APIRouter, Depends from huamenchuang.core.deps import CurrentUser, DbSession, require_module from huamenchuang.core.response import fail, ok, paginated from huamenchuang.schemas.order import OrderCreate, OrderProcessUpdate, OrderSearch, OrderUpdate from huamenchuang.services.order_service import OrderService router = APIRouter(prefix="/orders", tags=["订单"], dependencies=[Depends(require_module("order"))]) def _to_out(order) -> dict: return { "id": order.id, "order_no": order.order_no, "contract_id": order.contract_id, "pic_url": order.pic_url, "customer_id": order.customer_id, "customer_name": order.customer_name, "phone": order.phone, "address": order.address, "area": float(order.area), "count": order.count, "money": float(order.money), "status": order.status, "status_label": order.status_label, "cut_status": order.cut_status, "sort": order.sort, "note": order.note, "created_at": str(order.created_at), "updated_at": str(order.updated_at), } @router.post("") async def create_order(body: OrderCreate, user: CurrentUser, db: DbSession): """创建订单。契约对齐目标站:{contract_id, drawing_data, pic_url}。""" try: order = await OrderService(db).create_order(user, body) except Exception: return fail("创建订单失败") return ok(data=_to_out(order), message="创建成功") @router.post("/search") async def search_orders(body: OrderSearch, user: CurrentUser, db: DbSession): """订单搜索(POST 搜索语义对齐目标站)。""" items, total = await OrderService(db).search(user, body) return ok(data=paginated([_to_out(o) for o in items], body.page, body.page_size, total)) @router.get("") async def list_orders(user: CurrentUser, db: DbSession, page: int = 1, page_size: int = 15): """订单分页列表(GET 简化入口)。""" items, total = await OrderService(db).search( user, OrderSearch(page=page, page_size=page_size)) return ok(data=paginated([_to_out(o) for o in items], page, page_size, total)) @router.get("/{order_id}") async def order_detail(order_id: int, user: CurrentUser, db: DbSession): """订单详情:含 drawing_data 与生产进度。""" try: order = await OrderService(db).get_detail(user, order_id) except KeyError as e: return fail(str(e)) data = _to_out(order) data["drawing_data"] = order.drawing_data data["processes"] = [ {"id": p.id, "name": p.name, "status": p.status, "finish_time": str(p.finish_time) if p.finish_time else None} for p in order.processes ] return ok(data=data) @router.get("/{order_id}/bom") async def order_bom(order_id: int, user: CurrentUser, db: DbSession): """订单 BOM 计算单(对齐 calcbomOrder):型材下料清单 + 玻璃/五金汇总。""" try: order = await OrderService(db).get_detail(user, order_id) except KeyError as e: return fail(str(e)) if not order.drawing_data: return fail("该订单没有图纸数据") from huamenchuang.core.drawing import parse_drawing from huamenchuang.services.quote_service import bom as build_bom try: data = build_bom(parse_drawing(order.drawing_data)) except Exception: return fail("图纸数据解析失败") return ok(data={**data, "order_no": order.order_no}, message="BOM 生成成功") @router.get("/{order_id}/export") async def export_order(order_id: int, user: CurrentUser, db: DbSession): """订单导出 Excel(对齐 orders/export:信息 + BOM 下料清单)。""" from fastapi.responses import Response try: order = await OrderService(db).get_detail(user, order_id) except KeyError as e: return fail(str(e)) if not order.drawing_data: return fail("该订单没有图纸数据") from huamenchuang.core.drawing import parse_drawing from huamenchuang.services.excel_service import order_workbook from huamenchuang.services.quote_service import bom as build_bom try: sheet = build_bom(parse_drawing(order.drawing_data)) except Exception: return fail("图纸数据解析失败") content = order_workbook(_to_out(order), sheet) filename = f"order_{order.order_no}.xlsx" return Response( content, media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", headers={"Content-Disposition": f"attachment; filename={filename}"}, ) @router.put("/{order_id}") async def update_order(order_id: int, body: OrderUpdate, user: CurrentUser, db: DbSession): """更新订单基础字段;action=change_status 时执行状态迁移。""" try: order = await OrderService(db).update_order(user, order_id, body) except KeyError as e: return fail(str(e)) except ValueError as e: return fail(str(e)) return ok(data=_to_out(order), message="更新成功") @router.delete("/{order_id}") async def delete_order(order_id: int, user: CurrentUser, db: DbSession): """删除订单(已完工订单拒绝)。""" try: await OrderService(db).delete_order(user, order_id) except KeyError as e: return fail(str(e)) except ValueError as e: return fail(str(e)) return ok(message="删除成功") @router.post("/{order_id}/process") async def update_process(order_id: int, body: OrderProcessUpdate, user: CurrentUser, db: DbSession): """更新生产进度节点。""" try: proc = await OrderService(db).update_process(user, order_id, body) except KeyError as e: return fail(str(e)) return ok(data={"id": proc.id, "name": proc.name, "status": proc.status, "finish_time": str(proc.finish_time) if proc.finish_time else None}, message="操作成功") @router.get("/{order_id}/logs") async def order_logs(order_id: int, user: CurrentUser, db: DbSession): """订单操作日志(对齐 order_up_logs 语义)。""" try: logs = await OrderService(db).list_logs(user, order_id) except KeyError as e: return fail(str(e)) return ok(data=[{"id": g.id, "action": g.action, "detail": g.detail, "created_at": str(g.created_at)} for g in logs])