This commit is contained in:
2026-03-18 00:07:53 +08:00
parent 2a5821805c
commit 434bc59266
4 changed files with 115 additions and 27 deletions
+52 -9
View File
@@ -35,11 +35,13 @@ from .schemas import (
SalesOrderProductionPlanResponse,
ProductionMaterialPlanItemResponse,
SalesOrderIssueRequest,
SalesOrderIssueResponse
SalesOrderIssueResponse,
SalesOrderStatusUpdate
)
from .utils import generate_order_no
router = APIRouter(prefix="/sales-orders", tags=["销售订单"])
VALID_ORDER_STATUSES = {"manufacturing", "delivered", "paid"}
def _build_sales_order_response(order: SalesOrder, customer_name: str) -> SalesOrderResponse:
@@ -317,17 +319,40 @@ async def _apply_order_items(
) -> float:
total_amount = 0.0
for item_data in order_data.items:
product_result = await db_session.execute(
select(Product).where(Product.id == item_data.product_id, Product.is_active == True)
)
product = product_result.scalar_one_or_none()
if not product:
raise HTTPException(status_code=400, detail=f"产品不存在: {item_data.product_id}")
product = None
if item_data.product_id is not None:
product_result = await db_session.execute(
select(Product).where(Product.id == item_data.product_id, Product.is_active == True)
)
product = product_result.scalar_one_or_none()
if not product:
raise HTTPException(status_code=400, detail=f"产品不存在: {item_data.product_id}")
else:
if not item_data.product_sku or not item_data.product_name:
raise HTTPException(status_code=400, detail="请提供产品ID,或提供产品SKU与产品名称")
by_sku_result = await db_session.execute(
select(Product).where(Product.sku == item_data.product_sku, Product.is_active == True)
)
product = by_sku_result.scalar_one_or_none()
if not product:
product = Product(
sku=item_data.product_sku,
name=item_data.product_name,
category=item_data.product_category,
unit=item_data.product_unit or "件",
item_type="finished",
cost_price=0,
sale_price=item_data.unit_price or 0,
min_stock=0,
max_stock=0
)
db_session.add(product)
await db_session.flush()
if product.item_type != "finished":
raise HTTPException(status_code=400, detail=f"销售单仅允许成品: {product.name}")
item = SalesOrderItem(
order_id=order.id,
product_id=item_data.product_id,
product_id=product.id,
quantity=item_data.quantity,
unit_price=item_data.unit_price,
amount=item_data.quantity * item_data.unit_price,
@@ -377,7 +402,7 @@ async def create_sales_order(
delivery_date=order_data.delivery_date,
remark=order_data.remark,
operator_id=current_user.id,
status="draft"
status="manufacturing"
)
db_session.add(order)
await db_session.flush()
@@ -421,6 +446,7 @@ async def update_sales_order(
order.production_no = None
order.planned_material_cost = 0
order.actual_material_cost = 0
order.status = "manufacturing"
order.total_amount = await _apply_order_items(db_session, order, order_data)
await _issue_materials_for_order_creation(db_session, order, current_user)
@@ -433,6 +459,23 @@ async def update_sales_order(
return _build_sales_order_response(order, customer_name)
@router.patch("/{order_id}/status", response_model=SalesOrderResponse)
async def update_sales_order_status(
order_id: int,
payload: SalesOrderStatusUpdate,
db_session: AsyncSession = Depends(get_db_session),
current_user: User = Depends(get_current_active_user)
):
if payload.status not in VALID_ORDER_STATUSES:
raise HTTPException(status_code=400, detail="订单状态必须为 manufacturing、delivered、paid")
order, customer = await _get_sales_order_with_customer(db_session, order_id)
order.status = payload.status
await db_session.commit()
await db_session.refresh(order)
return _build_sales_order_response(order, customer.name)
@router.delete("/{order_id}")
async def delete_sales_order(
order_id: int,
+3 -2
View File
@@ -29,7 +29,8 @@ from .sales_order_schemas import (
ProductionMaterialPlanItemResponse,
SalesOrderProductionPlanResponse,
SalesOrderIssueRequest,
SalesOrderIssueResponse
SalesOrderIssueResponse,
SalesOrderStatusUpdate
)
from .finance_schemas import (
FinanceAllocationCreate,
@@ -59,7 +60,7 @@ __all__ = [
"PurchaseOrderItemResponse", "PurchaseOrderDetailResponse", "PurchaseOrderReceiveItem", "PurchaseOrderReceiveRequest",
"SalesOrderCreate", "SalesOrderResponse", "SalesOrderItemCreate", "SalesOrderItemResponse", "SalesOrderDetailResponse",
"ProductionMaterialPlanItemResponse", "SalesOrderProductionPlanResponse",
"SalesOrderIssueRequest", "SalesOrderIssueResponse",
"SalesOrderIssueRequest", "SalesOrderIssueResponse", "SalesOrderStatusUpdate",
"FinanceAllocationCreate", "FinanceTransactionCreate",
"ReceiptCreate", "PaymentCreate",
"FinanceAllocationResponse", "FinanceTransactionResponse",
@@ -4,7 +4,11 @@ from datetime import datetime
class SalesOrderItemCreate(BaseModel):
product_id: int
product_id: Optional[int] = None
product_sku: Optional[str] = None
product_name: Optional[str] = None
product_category: Optional[str] = None
product_unit: Optional[str] = "件"
quantity: int
unit_price: float
remark: Optional[str] = None
@@ -88,3 +92,7 @@ class SalesOrderIssueResponse(BaseModel):
cost_deviation: float
cost_deviation_rate: float
production_status: str
class SalesOrderStatusUpdate(BaseModel):
status: str