feat: add recharge workflow models and schema statuses

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-09-26 20:55:15 +08:00
1 parent 94dd52832b
commit bdd67d44d9
7 files changed
+147 -26

No files matched your search

+26 -3
View File
@@ -67,7 +67,16 @@ def create_workflow(
nodes_data = data.pop("nodes", []) or []
workflow = WorkflowService.create(db, data, user=user)
if nodes_data:
WorkflowService.save_nodes(db, workflow.id, nodes_data, user=user)
try:
WorkflowService.save_nodes(db, workflow.id, nodes_data, user=user)
except ValueError as exc:
db.rollback()
code = (
status.HTTP_400_BAD_REQUEST
if "发放登记" in str(exc)
else status.HTTP_404_NOT_FOUND
)
raise HTTPException(status_code=code, detail=str(exc)) from exc
db.commit()
db.refresh(workflow)
return ApiResponse(data=WorkflowDefOut.model_validate(workflow))
@@ -87,7 +96,16 @@ def update_workflow(
if not workflow:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="工作流不存在")
if nodes_data is not None:
WorkflowService.save_nodes(db, workflow_id, nodes_data, user=user)
try:
WorkflowService.save_nodes(db, workflow_id, nodes_data, user=user)
except ValueError as exc:
db.rollback()
code = (
status.HTTP_400_BAD_REQUEST
if "发放登记" in str(exc)
else status.HTTP_404_NOT_FOUND
)
raise HTTPException(status_code=code, detail=str(exc)) from exc
db.commit()
db.refresh(workflow)
return ApiResponse(data=WorkflowDefOut.model_validate(workflow))
@@ -106,7 +124,12 @@ def save_workflow_nodes(
WorkflowService.save_nodes(db, workflow_id, nodes_data, user=user)
except ValueError as exc:
db.rollback()
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
code = (
status.HTTP_400_BAD_REQUEST
if "发放登记" in str(exc)
else status.HTTP_404_NOT_FOUND
)
raise HTTPException(status_code=code, detail=str(exc)) from exc
workflow = WorkflowService.get_by_id(db, workflow_id, tenant_no, user=user)
if not workflow:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="工作流不存在")
+6
View File
@@ -73,6 +73,12 @@ class BxWorkflowNode(Base):
node_order = Column(Integer, nullable=False, default=0, comment="节点顺序")
approver_id = Column(String(64), nullable=True, comment="审批人用户ID")
approver_name = Column(String(64), nullable=True, comment="审批人姓名")
action_type = Column(
String(20),
nullable=False,
default="approve",
comment="approve-审批 disburse-发放登记",
)
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号(公共)")
remark = Column(String(512), nullable=True, comment="备注")
+35 -1
View File
@@ -1333,7 +1333,41 @@ class PlVehicleRechargeApply(Base):
odometer_km = Column(DECIMAL(10, 1), nullable=True, comment="期初公里数")
attachment_urls = Column(String(2000), nullable=True, comment="附件URL")
applicant_id = Column(String(64), nullable=False, comment="申请人ID")
status = Column(String(20), nullable=False, default="pending", comment="申请状态")
status = Column(
String(20),
nullable=False,
default="draft",
comment="draft/in_approval/rejected/disbursed/cancelled",
)
wf_id = Column(String(64), nullable=True, comment="工作流定义ID")
current_node = Column(String(64), nullable=True, comment="当前节点ID")
approval_round = Column(Integer, nullable=False, default=0, comment="当前审批轮次")
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人id")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人id")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记:0-正常 1-已删除")
class PlVehicleRechargeApproval(Base):
"""车辆充值申请审批历史 pl_vehicle_recharge_approval"""
__tablename__ = "pl_vehicle_recharge_approval"
id = Column(String(64), primary_key=True, comment="主键ID")
apply_id = Column(String(64), nullable=False, comment="申请单ID")
approval_round = Column(Integer, nullable=False, default=1, comment="审批轮次")
node_id = Column(String(64), nullable=True, comment="节点ID快照")
node_name = Column(String(128), nullable=True, comment="节点名称快照")
approver_id = Column(String(64), nullable=False, comment="审批人用户ID")
approver_name = Column(String(64), nullable=False, comment="审批人姓名")
approval_status = Column(String(32), nullable=False, comment="approved/rejected/disbursed")
approval_opinion = Column(String(1024), nullable=True, comment="审批意见")
approval_time = Column(DateTime, nullable=False, comment="审批时间")
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
+2
View File
@@ -17,6 +17,7 @@ class WorkflowNodeCreate(BaseModel):
node_order: int
approver_id: Optional[str] = None
approver_name: Optional[str] = None
action_type: Optional[str] = "approve"
@field_validator("approver_id", mode="before")
@classmethod
@@ -32,6 +33,7 @@ class WorkflowNodeOut(BaseModel):
node_order: int
approver_id: Optional[str] = None
approver_name: Optional[str] = None
action_type: Optional[str] = "approve"
class WorkflowDefCreate(BaseModel):
+51 -22
View File
@@ -1,11 +1,14 @@
"""车辆 ETC/加油充值 Schema"""
from datetime import date, datetime
from decimal import Decimal
from typing import Optional
from typing import List, Optional
from pydantic import BaseModel, Field, field_validator
RECHARGE_TYPES = {"etc", "fuel"}
APPLY_STATUSES = {"draft", "in_approval", "rejected", "disbursed", "cancelled"}
NODE_ACTION_TYPES = {"approve", "disburse"}
APPROVAL_STATUSES = {"approved", "rejected", "disbursed"}
class VehicleRechargeApplyCreate(BaseModel):
@@ -31,6 +34,42 @@ class VehicleRechargeApplyUpdate(VehicleRechargeApplyCreate):
pass
class VehicleRechargeApprovalRead(BaseModel):
id: str
apply_id: str = Field(..., alias="applyId")
approval_round: int = Field(..., alias="approvalRound")
node_id: Optional[str] = Field(default=None, alias="nodeId")
node_name: Optional[str] = Field(default=None, alias="nodeName")
approver_id: str = Field(..., alias="approverId")
approver_name: str = Field(..., alias="approverName")
approval_status: str = Field(..., alias="approvalStatus")
approval_opinion: Optional[str] = Field(default=None, alias="approvalOpinion")
approval_time: datetime = Field(..., alias="approvalTime")
model_config = {"populate_by_name": True}
class VehicleRechargeRecordRead(BaseModel):
id: str
recharge_order_no: str = Field(..., alias="rechargeOrderNo")
recharge_date: date = Field(..., alias="rechargeDate")
recharge_type: str = Field(..., alias="rechargeType")
card_no: Optional[str] = Field(default=None, alias="cardNo")
gas_station: Optional[str] = Field(default=None, alias="gasStation")
amount: Decimal
attachment_urls: Optional[str] = Field(default=None, alias="attachmentUrls")
apply_id: Optional[str] = Field(default=None, alias="applyId")
apply_no: Optional[str] = Field(default=None, alias="applyNo")
license_plate: Optional[str] = Field(default=None, alias="licensePlate")
remark: Optional[str] = None
create_by: Optional[str] = Field(default=None, alias="createBy")
create_by_name: Optional[str] = Field(default=None, alias="createByName")
create_time: Optional[datetime] = Field(default=None, alias="createTime")
update_time: Optional[datetime] = Field(default=None, alias="updateTime")
model_config = {"populate_by_name": True}
class VehicleRechargeApplyRead(BaseModel):
id: str
apply_no: str = Field(..., alias="applyNo")
@@ -42,6 +81,11 @@ class VehicleRechargeApplyRead(BaseModel):
applicant_id: str = Field(..., alias="applicantId")
applicant_name: Optional[str] = Field(default=None, alias="applicantName")
status: str
wf_id: Optional[str] = Field(default=None, alias="wfId")
current_node: Optional[str] = Field(default=None, alias="currentNode")
approval_round: int = Field(default=0, alias="approvalRound")
approvals: List[VehicleRechargeApprovalRead] = Field(default_factory=list)
record: Optional[VehicleRechargeRecordRead] = None
remark: Optional[str] = None
create_time: Optional[datetime] = Field(default=None, alias="createTime")
update_time: Optional[datetime] = Field(default=None, alias="updateTime")
@@ -67,6 +111,12 @@ class VehicleRechargeApplyOption(BaseModel):
model_config = {"populate_by_name": True}
class VehicleRechargeOpinionBody(BaseModel):
opinion: Optional[str] = None
model_config = {"populate_by_name": True}
class VehicleRechargeRecordCreate(BaseModel):
recharge_date: date = Field(..., alias="rechargeDate")
recharge_type: str = Field(..., alias="rechargeType")
@@ -99,27 +149,6 @@ class VehicleRechargeRecordUpdate(VehicleRechargeRecordCreate):
pass
class VehicleRechargeRecordRead(BaseModel):
id: str
recharge_order_no: str = Field(..., alias="rechargeOrderNo")
recharge_date: date = Field(..., alias="rechargeDate")
recharge_type: str = Field(..., alias="rechargeType")
card_no: Optional[str] = Field(default=None, alias="cardNo")
gas_station: Optional[str] = Field(default=None, alias="gasStation")
amount: Decimal
attachment_urls: Optional[str] = Field(default=None, alias="attachmentUrls")
apply_id: Optional[str] = Field(default=None, alias="applyId")
apply_no: Optional[str] = Field(default=None, alias="applyNo")
license_plate: Optional[str] = Field(default=None, alias="licensePlate")
remark: Optional[str] = None
create_by: Optional[str] = Field(default=None, alias="createBy")
create_by_name: Optional[str] = Field(default=None, alias="createByName")
create_time: Optional[datetime] = Field(default=None, alias="createTime")
update_time: Optional[datetime] = Field(default=None, alias="updateTime")
model_config = {"populate_by_name": True}
class VehicleRechargeRecordListResponse(BaseModel):
items: list[VehicleRechargeRecordRead]
total: int
+19
View File
@@ -20,6 +20,10 @@ _DEFAULT_WORKFLOWS = {
"wf_name": "报销单审批流程",
"remark": "报销申请默认审批流程",
},
"vehicle_recharge": {
"wf_name": "ETC/加油充值审批流程",
"remark": "充值申请默认审批流程",
},
}
@@ -162,6 +166,18 @@ class WorkflowService:
if not workflow:
raise ValueError("工作流不存在")
disburse_count = 0
for node_data in nodes:
action = (
node_data.get("action_type")
or node_data.get("actionType")
or "approve"
)
if action == "disburse":
disburse_count += 1
if disburse_count > 1:
raise ValueError("发放登记节点至多一个")
db.query(BxWorkflowNode).filter(
BxWorkflowNode.wf_id == wf_id,
BxWorkflowNode.tenant_no == tenant_no,
@@ -170,6 +186,7 @@ class WorkflowService:
created: List[BxWorkflowNode] = []
for node_data in nodes:
data = dict(node_data)
data.pop("actionType", None)
data["id"] = generate_uuid()
data["wf_id"] = wf_id
data["tenant_no"] = tenant_no
@@ -177,6 +194,8 @@ class WorkflowService:
data["create_dept_id"] = user.dept_id or ""
if data.get("approver_id") is not None:
data["approver_id"] = str(data["approver_id"]).strip() or None
if not data.get("action_type"):
data["action_type"] = "approve"
node = BxWorkflowNode(**data)
db.add(node)
created.append(node)