from pydantic import BaseModel, Field from typing import Optional, List from datetime import datetime, date from decimal import Decimal class SalesOrderItemCreate(BaseModel): 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 = Field(gt=0) unit_price: Decimal = Field(ge=0) remark: Optional[str] = None class SalesOrderCreate(BaseModel): customer_id: int delivery_date: Optional[date] = None remark: Optional[str] = None items: List[SalesOrderItemCreate] = Field(min_length=1) class SalesOrderResponse(BaseModel): id: int order_no: str customer_name: str order_date: datetime delivery_date: Optional[date] manufacturing_date: Optional[date] 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 actual_material_cost: Decimal total_amount: Decimal received_amount: Decimal remark: Optional[str] created_at: datetime class Config: from_attributes = True class SalesOrderItemResponse(BaseModel): id: int product_id: int quantity: int delivered_quantity: int unit_price: Decimal amount: Decimal remark: Optional[str] = None class SalesOrderDetailResponse(SalesOrderResponse): customer_id: int items: List[SalesOrderItemResponse] class ProductionMaterialPlanItemResponse(BaseModel): material_id: int material_sku: str material_name: str required_quantity: Decimal available_quantity: Decimal shortage_quantity: Decimal unit_cost: Decimal required_cost: Decimal class SalesOrderProductionPlanResponse(BaseModel): sales_order_id: int order_no: str customer_name: str production_no: str planned_material_cost: Decimal items: List[ProductionMaterialPlanItemResponse] class SalesOrderIssueRequest(BaseModel): warehouse_id: int production_no: Optional[str] = None remark: Optional[str] = None class SalesOrderIssueResponse(BaseModel): sales_order_id: int order_no: str production_no: str movement_count: int planned_material_cost: Decimal actual_material_cost: Decimal cost_deviation: Decimal cost_deviation_rate: Decimal production_status: str class SalesOrderStatusUpdate(BaseModel): status: str