167 lines
6.4 KiB
Python
167 lines
6.4 KiB
Python
"""订单路由(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])
|