x
This commit is contained in:
@@ -39,6 +39,24 @@ from .utils import generate_order_no
|
||||
router = APIRouter(prefix="/purchase-orders", tags=["采购订单"])
|
||||
|
||||
|
||||
def _compute_receipt_status(order: PurchaseOrder) -> str:
|
||||
"""收货状态:已下单 / 部分收货 / 已收货 / 已作废"""
|
||||
if order.status == "cancelled":
|
||||
return "cancelled"
|
||||
if order.status in ("received", "paid"):
|
||||
return "received"
|
||||
if order.status == "partial_received":
|
||||
return "partial_received"
|
||||
return "pending"
|
||||
|
||||
|
||||
def _compute_payment_status(order: PurchaseOrder) -> str:
|
||||
"""付款状态:未付款 / 已付款"""
|
||||
if order.status == "paid" or order.paid_date:
|
||||
return "paid"
|
||||
return "unpaid"
|
||||
|
||||
|
||||
def _build_purchase_order_response(order: PurchaseOrder, supplier_name: str) -> PurchaseOrderResponse:
|
||||
return PurchaseOrderResponse(
|
||||
id=order.id,
|
||||
@@ -47,6 +65,8 @@ def _build_purchase_order_response(order: PurchaseOrder, supplier_name: str) ->
|
||||
order_date=order.order_date,
|
||||
expected_date=order.expected_date,
|
||||
status=order.status,
|
||||
receipt_status=_compute_receipt_status(order),
|
||||
payment_status=_compute_payment_status(order),
|
||||
total_amount=order.total_amount,
|
||||
paid_amount=order.paid_amount,
|
||||
remark=order.remark,
|
||||
@@ -92,6 +112,8 @@ async def _build_purchase_order_detail(
|
||||
order_date=order.order_date,
|
||||
expected_date=order.expected_date,
|
||||
status=order.status,
|
||||
receipt_status=_compute_receipt_status(order),
|
||||
payment_status=_compute_payment_status(order),
|
||||
total_amount=order.total_amount,
|
||||
paid_amount=order.paid_amount,
|
||||
remark=order.remark,
|
||||
@@ -319,19 +341,27 @@ async def update_purchase_order_status(
|
||||
if not new_status:
|
||||
raise HTTPException(status_code=400, detail="状态不能为空")
|
||||
|
||||
valid_statuses = ["pending", "partial_received", "received", "paid"]
|
||||
valid_statuses = ["pending", "partial_received", "received", "paid", "cancelled"]
|
||||
if new_status not in valid_statuses:
|
||||
raise HTTPException(status_code=400, detail=f"无效的状态值,有效值为: {valid_statuses}")
|
||||
|
||||
# 状态转换逻辑
|
||||
if order.status == "paid":
|
||||
raise HTTPException(status_code=400, detail="已付款的采购订单禁止修改状态")
|
||||
if order.status == "cancelled":
|
||||
raise HTTPException(status_code=400, detail="已作废的采购订单禁止修改状态")
|
||||
|
||||
if order.status == "received" and new_status != "paid":
|
||||
raise HTTPException(status_code=400, detail="已收货的采购订单只能标记为已付款")
|
||||
if order.status == "received" and new_status not in ("paid", "cancelled"):
|
||||
raise HTTPException(status_code=400, detail="已收货的采购订单只能标记为已付款或已作废")
|
||||
|
||||
if order.status == "partial_received" and new_status not in ("received", "paid"):
|
||||
raise HTTPException(status_code=400, detail="部分收货的采购订单只能标记为已收货或已付款")
|
||||
if order.status == "partial_received" and new_status not in ("received", "paid", "cancelled"):
|
||||
raise HTTPException(status_code=400, detail="部分收货的采购订单只能标记为已收货、已付款或已作废")
|
||||
|
||||
if order.status == "pending" and new_status not in ("received", "cancelled"):
|
||||
raise HTTPException(status_code=400, detail="待收货的采购订单只能标记为已收货或已作废")
|
||||
|
||||
if new_status == "cancelled" and order.status == "paid":
|
||||
raise HTTPException(status_code=400, detail="已付款的订单不能作废")
|
||||
|
||||
# 更新状态和对应时间
|
||||
order.status = new_status
|
||||
|
||||
@@ -44,10 +44,26 @@ from .schemas import (
|
||||
from .utils import generate_order_no
|
||||
|
||||
router = APIRouter(prefix="/sales-orders", tags=["销售订单"])
|
||||
VALID_ORDER_STATUSES = {"draft", "manufacturing", "delivered", "paid"}
|
||||
VALID_ORDER_STATUSES = {"manufacturing", "delivered", "paid", "cancelled"}
|
||||
PRODUCTION_STATUSES = {"not_started", "bom_missing", "material_issued", "completed"}
|
||||
|
||||
|
||||
def _compute_delivery_status(order: SalesOrder) -> str:
|
||||
"""物流状态:制造中 / 已交付 / 已作废"""
|
||||
if order.status == "cancelled":
|
||||
return "cancelled"
|
||||
if order.status in ("delivered", "paid") or order.actual_delivery_date:
|
||||
return "delivered"
|
||||
return "manufacturing"
|
||||
|
||||
|
||||
def _compute_payment_status(order: SalesOrder) -> str:
|
||||
"""收款状态:未收款 / 已收款"""
|
||||
if order.status == "paid" or order.actual_payment_date:
|
||||
return "paid"
|
||||
return "unpaid"
|
||||
|
||||
|
||||
def _build_sales_order_response(order: SalesOrder, customer_name: str) -> SalesOrderResponse:
|
||||
return SalesOrderResponse(
|
||||
id=order.id,
|
||||
@@ -59,6 +75,8 @@ def _build_sales_order_response(order: SalesOrder, customer_name: str) -> SalesO
|
||||
actual_delivery_date=order.actual_delivery_date,
|
||||
actual_payment_date=order.actual_payment_date,
|
||||
status=order.status,
|
||||
delivery_status=_compute_delivery_status(order),
|
||||
payment_status=_compute_payment_status(order),
|
||||
production_status=order.production_status or "not_started",
|
||||
production_no=order.production_no,
|
||||
planned_material_cost=Decimal(str(order.planned_material_cost or 0)),
|
||||
@@ -90,6 +108,8 @@ async def _build_sales_order_detail_response(
|
||||
actual_delivery_date=order.actual_delivery_date,
|
||||
actual_payment_date=order.actual_payment_date,
|
||||
status=order.status,
|
||||
delivery_status=_compute_delivery_status(order),
|
||||
payment_status=_compute_payment_status(order),
|
||||
production_status=order.production_status or "not_started",
|
||||
production_no=order.production_no,
|
||||
planned_material_cost=Decimal(str(order.planned_material_cost or 0)),
|
||||
@@ -508,16 +528,27 @@ async def update_sales_order_status(
|
||||
raise HTTPException(status_code=400, detail="订单状态必须为 manufacturing、delivered、paid")
|
||||
|
||||
order, customer = await _get_sales_order_with_customer(db_session, order_id)
|
||||
# 只禁止从已交付状态改为非已收款状态
|
||||
if order.status == "delivered" and payload.status != "paid":
|
||||
raise HTTPException(status_code=400, detail="已交付的销售订单只能修改为已收款状态")
|
||||
|
||||
|
||||
# 状态转换守卫
|
||||
if order.status == "paid":
|
||||
raise HTTPException(status_code=400, detail="已收款的销售订单禁止修改状态")
|
||||
if order.status == "cancelled":
|
||||
raise HTTPException(status_code=400, detail="已作废的销售订单禁止修改状态")
|
||||
if order.status == "manufacturing" and payload.status == "paid":
|
||||
raise HTTPException(status_code=400, detail="制造中的订单不能直接标记为已收款,请先标记为已交付")
|
||||
if order.status == "delivered" and payload.status not in ("paid", "cancelled"):
|
||||
raise HTTPException(status_code=400, detail="已交付的销售订单只能修改为已收款或已作废")
|
||||
if payload.status == "cancelled" and order.status == "paid":
|
||||
raise HTTPException(status_code=400, detail="已收款的订单不能作废,请联系管理员")
|
||||
|
||||
# 根据状态更新相应的日期字段
|
||||
from datetime import datetime
|
||||
if payload.status == "delivered" and not order.actual_delivery_date:
|
||||
order.actual_delivery_date = datetime.now()
|
||||
elif payload.status == "paid" and not order.actual_payment_date:
|
||||
order.actual_payment_date = datetime.now()
|
||||
elif payload.status == "cancelled" and not order.actual_delivery_date:
|
||||
order.actual_delivery_date = datetime.now()
|
||||
|
||||
order.status = payload.status
|
||||
await db_session.commit()
|
||||
|
||||
@@ -25,6 +25,8 @@ class PurchaseOrderResponse(BaseModel):
|
||||
order_date: datetime
|
||||
expected_date: Optional[date]
|
||||
status: str
|
||||
receipt_status: str # "pending" | "partial_received" | "received" | "cancelled"
|
||||
payment_status: str # "unpaid" | "paid"
|
||||
total_amount: Decimal
|
||||
paid_amount: Decimal
|
||||
remark: Optional[str]
|
||||
|
||||
@@ -32,6 +32,8 @@ class SalesOrderResponse(BaseModel):
|
||||
actual_delivery_date: Optional[datetime]
|
||||
actual_payment_date: Optional[datetime]
|
||||
status: str
|
||||
delivery_status: str # "manufacturing" | "delivered" | "cancelled"
|
||||
payment_status: str # "unpaid" | "paid"
|
||||
production_status: str
|
||||
production_no: Optional[str]
|
||||
planned_material_cost: Decimal
|
||||
|
||||
Reference in New Issue
Block a user