Files
shanxia2.0/backend/app/schemas/pl/freight.py
T
2026-08-27 14:23:18 +08:00

232 lines
11 KiB
Python

"""运输计划管理 - 运费结算 Schema"""
from datetime import date, datetime
from decimal import Decimal
from typing import Any, Optional
from pydantic import BaseModel, Field, model_validator
# =============================================================================
# 运费结算 Schema
# =============================================================================
class FreightSettlementBase(BaseModel):
total_freight: Decimal = Field(default=Decimal("0.00"), alias="totalFreight", description="运费合计")
invoice_amount: Optional[Decimal] = Field(default=None, alias="invoiceAmount", description="发票金额")
invoice_no: Optional[str] = Field(default=None, max_length=50, alias="invoiceNo", description="发票号")
invoice_date: Optional[date] = Field(default=None, alias="invoiceDate", description="开票日期")
invoice_attachment_urls: Optional[str] = Field(
default=None, alias="invoiceAttachmentUrls", description="发票附件URLs,逗号分隔"
)
settlement_status: str = Field(default="pending", alias="settlementStatus", description="结算状态")
remark: Optional[str] = None
class FreightSettlementCreate(BaseModel):
transport_ids: Optional[list[str]] = Field(default=None, alias="transportIds", description="运输ID列表")
plan_ids: Optional[list[str]] = Field(default=None, alias="planIds", description="计划ID列表")
model_config = {"populate_by_name": True}
@model_validator(mode="after")
def check_ids(self):
if not self.transport_ids and not self.plan_ids:
raise ValueError("transportIds 或 planIds 至少提供一个")
return self
class FreightSettlementUpdate(BaseModel):
invoice_amount: Optional[Decimal] = Field(default=None, alias="invoiceAmount")
invoice_no: Optional[str] = Field(default=None, max_length=50, alias="invoiceNo")
invoice_date: Optional[date] = Field(default=None, alias="invoiceDate")
invoice_attachment_urls: Optional[str] = Field(default=None, alias="invoiceAttachmentUrls")
remark: Optional[str] = None
transport_ids: Optional[list[str]] = Field(
default=None, alias="transportIds", description="关联运输ID全量列表,仅草稿可更新"
)
model_config = {"populate_by_name": True}
class FreightSettlementRead(FreightSettlementBase):
id: str
settlement_no: str = Field(alias="settlementNo")
tenant_no: str = Field(alias="tenantNo")
order_num: Optional[int] = Field(default=None, alias="orderNum")
create_by: Optional[str] = Field(default=None, alias="createBy")
create_dept_id: Optional[str] = Field(default=None, alias="createDeptId")
create_time: datetime = Field(alias="createTime")
update_by: Optional[str] = Field(default=None, alias="updateBy")
update_time: datetime = Field(alias="updateTime")
del_flag: int = Field(default=0, alias="delFlag")
model_config = {"from_attributes": True, "populate_by_name": True}
class FreightSettlementListItem(FreightSettlementRead):
plan_count: int = Field(default=0, alias="planCount")
license_plate_summary: Optional[str] = Field(default=None, alias="licensePlateSummary")
current_approver_name: Optional[str] = Field(default=None, alias="currentApproverName")
can_approve: bool = Field(default=False, alias="canApprove")
can_withdraw: bool = Field(default=False, alias="canWithdraw")
current_approval_id: Optional[str] = Field(default=None, alias="currentApprovalId")
approval_finished_time: Optional[datetime] = Field(default=None, alias="approvalFinishedTime")
disburse_time: Optional[datetime] = Field(default=None, alias="disburseTime")
disburse_amount: Optional[Decimal] = Field(default=None, alias="disburseAmount")
submitter_name: Optional[str] = Field(default=None, alias="submitterName")
model_config = {"from_attributes": True, "populate_by_name": True}
class FreightSettlementTransportRead(BaseModel):
id: str
settlement_id: str = Field(alias="settlementId")
transport_id: str = Field(alias="transportId")
freight_amount: Decimal = Field(alias="freightAmount")
tenant_no: str = Field(alias="tenantNo")
create_time: datetime = Field(alias="createTime")
model_config = {"from_attributes": True, "populate_by_name": True}
class UnsettledPlanItem(BaseModel):
id: str
plan_no: str = Field(alias="planNo")
plan_date: Optional[date] = Field(default=None, alias="planDate")
plan_type: str = Field(alias="planType")
customer_name: Optional[str] = Field(default=None, alias="customerName")
supplier_name: Optional[str] = Field(default=None, alias="supplierName")
license_plate: Optional[str] = Field(default=None, alias="licensePlate")
transport_company: Optional[str] = Field(default=None, alias="transportCompany")
freight_amount: Decimal = Field(default=Decimal("0"), alias="freightAmount")
freight_remark: Optional[str] = Field(default=None, alias="freightRemark")
archive_time: Optional[datetime] = Field(default=None, alias="archiveTime")
transport_id: str = Field(alias="transportId")
transport_no: Optional[str] = Field(default=None, alias="transportNo")
driver_name: Optional[str] = Field(default=None, alias="driverName")
transport_medium: Optional[str] = Field(default=None, alias="transportMedium")
start_point: Optional[str] = Field(default=None, alias="startPoint")
end_point: Optional[str] = Field(default=None, alias="endPoint")
model_config = {"populate_by_name": True}
class UnsettledPlanListResponse(BaseModel):
total: int
list: list[UnsettledPlanItem]
class SettlementPlanSummary(BaseModel):
id: str
plan_no: str = Field(alias="planNo")
plan_date: Optional[date] = Field(default=None, alias="planDate")
license_plate: Optional[str] = Field(default=None, alias="licensePlate")
freight_amount: Optional[Decimal] = Field(default=None, alias="freightAmount")
freight_remark: Optional[str] = Field(default=None, alias="freightRemark")
model_config = {"populate_by_name": True}
class SettlementApprovalFlowItem(BaseModel):
id: str
step: int
step_name: Optional[str] = Field(default=None, alias="stepName")
approver_id: str = Field(alias="approverId")
approver_name: Optional[str] = Field(default=None, alias="approverName")
approval_type: Optional[str] = Field(default=None, alias="approvalType")
approval_result: str = Field(alias="approvalResult")
approval_opinion: Optional[str] = Field(default=None, alias="approvalOpinion")
approval_time: Optional[datetime] = Field(default=None, alias="approvalTime")
is_current: int = Field(default=0, alias="isCurrent")
model_config = {"populate_by_name": True}
class FreightSettlementWithTransports(FreightSettlementRead):
transports: list = []
plans: list[SettlementPlanSummary] = []
approval_flow: list[SettlementApprovalFlowItem] = Field(default_factory=list, alias="approvalFlow")
approval_history: list[SettlementApprovalFlowItem] = Field(default_factory=list, alias="approvalHistory")
vouchers: list = []
plan_count: int = Field(default=0, alias="planCount")
license_plate_summary: Optional[str] = Field(default=None, alias="licensePlateSummary")
current_approver_name: Optional[str] = Field(default=None, alias="currentApproverName")
can_approve: bool = Field(default=False, alias="canApprove")
can_withdraw: bool = Field(default=False, alias="canWithdraw")
current_approval_id: Optional[str] = Field(default=None, alias="currentApprovalId")
approval_finished_time: Optional[datetime] = Field(default=None, alias="approvalFinishedTime")
disburse_time: Optional[datetime] = Field(default=None, alias="disburseTime")
disburse_amount: Optional[Decimal] = Field(default=None, alias="disburseAmount")
submitter_name: Optional[str] = Field(default=None, alias="submitterName")
class FreightSettlementSubmitApprovalBody(BaseModel):
approval_type: str = Field(default="sequential", alias="approvalType")
approver_ids: list[str] = Field(..., alias="approverIds", min_length=1)
remark: Optional[str] = None
model_config = {"populate_by_name": True}
class FreightSettlementApprovalActionBody(BaseModel):
action: str = Field(..., description="approve|reject")
comment: Optional[str] = None
class FreightSettlementDisburseBody(BaseModel):
remittance_date: date = Field(..., alias="remittanceDate")
remittance_amount: Decimal = Field(..., alias="remittanceAmount", gt=0)
voucher_urls: list[str] = Field(..., alias="voucherUrls", min_length=1)
remark: Optional[str] = None
model_config = {"populate_by_name": True}
# =============================================================================
# 汇款凭证 Schema
# =============================================================================
class RemittanceVoucherCreate(BaseModel):
settlement_id: str = Field(..., alias="settlementId", description="结算单ID")
remittance_date: Optional[date] = Field(default=None, alias="remittanceDate", description="汇款日期")
remittance_amount: Optional[Decimal] = Field(default=None, alias="remittanceAmount", description="汇款金额")
voucher_urls: Optional[list[str]] = Field(default=None, alias="voucherUrls", description="凭证文件URLs")
remark: Optional[str] = None
model_config = {"populate_by_name": True}
class RemittanceVoucherRead(BaseModel):
id: str
settlement_id: str = Field(alias="settlementId")
voucher_no: Optional[str] = Field(default=None, alias="voucherNo")
remittance_date: Optional[date] = Field(default=None, alias="remittanceDate")
remittance_amount: Optional[Decimal] = Field(default=None, alias="remittanceAmount")
voucher_urls: Optional[str] = Field(default=None, alias="voucherUrls")
remark: Optional[str] = None
tenant_no: str = Field(alias="tenantNo")
create_by: Optional[str] = Field(default=None, alias="createBy")
create_time: datetime = Field(alias="createTime")
model_config = {"from_attributes": True, "populate_by_name": True}
# =============================================================================
# 列表查询
# =============================================================================
class FreightSettlementListQuery(BaseModel):
q: Optional[str] = Field(default=None, description="模糊搜索")
settlement_status: Optional[str] = Field(default=None, alias="settlementStatus", description="结算状态")
tab: Optional[str] = Field(default=None, description="bills|disburse|settled")
page: int = Field(default=1, ge=1)
page_size: int = Field(default=20, ge=1, le=500, alias="pageSize")
model_config = {"populate_by_name": True}
class FreightSettlementListResponse(BaseModel):
total: int
list: list[FreightSettlementListItem]
class FreightSettlementByTransportRead(BaseModel):
id: str
settlement_no: str = Field(alias="settlementNo")
invoice_amount: Optional[Decimal] = Field(default=None, alias="invoiceAmount")
invoice_no: Optional[str] = Field(default=None, alias="invoiceNo")
invoice_date: Optional[date] = Field(default=None, alias="invoiceDate")
invoice_attachment_urls: Optional[str] = Field(default=None, alias="invoiceAttachmentUrls")
settlement_status: str = Field(alias="settlementStatus")
model_config = {"populate_by_name": True}