客户为已签收商品申请换货,确认当前方案,主管审核通过,履约工作进程向 OMS 提交操作。沿这个场景观察资格校验、版本检查、事务、消息投递、数量预占和外部结果恢复。
图中的后端路径均相对 src/zhifu/。连续箭头表示直接函数调用,标注“框架调用”的箭头表示 FastAPI 分发;间断箭头表示 HTTP、消息或持久数据连接。数据节点使用类名,函数节点使用源码中的函数名。同一调用者的多条连续箭头表示它分别调用相关函数,执行条件写在箭头或正文中。返回路线目录。
三个操作分别来自独立 HTTP 请求。command 建立事务并认证,execute 根据 action 检查权限、读取幂等收据并选择业务方法。
flowchart TB
HTTP["FastAPI<br/>三个独立 POST 请求"]
API["modules/after_sales/api.py<br/>create_proposal / confirm / decide<br/>提供各自的 action"]
CMD["modules/after_sales/api.py<br/>command<br/>建立业务事务"]
AUTH["modules/identity/auth.py<br/>authenticate<br/>确认当前身份"]
EXEC["modules/after_sales/service.py<br/>AfterSalesService.execute<br/>权限、幂等与业务分派"]
CREATE["modules/after_sales/service.py<br/>AfterSalesService.create<br/>保存 DRAFT 方案及规则依据"]
CONFIRM["modules/after_sales/service.py<br/>AfterSalesService.confirm<br/>保存客户确认与 PENDING 审批"]
DECIDE["modules/after_sales/service.py<br/>AfterSalesService.decide<br/>校验审批人并记录决定"]
VALIDATE["modules/after_sales/service.py<br/>AfterSalesService.validate_proposal<br/>读取方案引用的规则和订单版本"]
EVALUATE["modules/after_sales/service.py<br/>AfterSalesService.evaluate → assess<br/>校验时效、签收、范围与数量"]
CHANGED["modules/after_sales/service.py<br/>AfterSalesService.changed<br/>增加工单版本"]
EMIT["modules/after_sales/service.py<br/>AfterSalesService.emit<br/>登记业务事件"]
EVENT[("modules/after_sales/models.py<br/>BusinessEvent<br/>与业务变更共同提交")]
RECEIPT[("modules/after_sales/models.py<br/>CommandReceipt<br/>保存请求摘要与响应")]
HTTP -->|框架调用| API
API --> CMD
CMD --> AUTH
CMD -->|认证成功后| EXEC
EXEC -->|action=create| CREATE
EXEC -->|action=confirm| CONFIRM
EXEC -->|action=decide| DECIDE
CREATE --> EVALUATE
CONFIRM --> VALIDATE
DECIDE --> VALIDATE
VALIDATE --> EVALUATE
CONFIRM --> CHANGED
DECIDE --> CHANGED
CREATE --> EMIT
CHANGED --> EMIT
EMIT -.->|事务内保存| EVENT
EXEC -.->|读取重试收据或保存新响应| RECEIPT
create 使用当前规则建立 ProposalVersion,保存 rule_version、order_version 和 citation。confirm、decide 使用该方案引用的版本重新检查;订单来源版本变化会要求修订。图中 evaluate → assess 表示 evaluate 直接调用 assess。
confirm 只接受订单所属客户,检查方案版本与工单版本后进入 WAITING_REVIEW。decide 检查当前审批仍为 PENDING、客户确认存在,以及审批人和方案提交者不同;通过后进入 APPROVED 并产生 after_sale.approved。execute 的当前权限检查发生在读取并返回旧收据之前。
工作进程读取已经提交的 BusinessEvent。发布循环与消费循环独立运行;消息只传递事件标识等信息,prepare_event 根据 event_id 读取数据库中的业务事件。
flowchart TB
EVENT[("modules/after_sales/models.py<br/>BusinessEvent<br/>已提交的审批事件")]
PUB["modules/integrations/worker.py<br/>publish_one<br/>领取发布租约"]
SEND["modules/integrations/worker.py<br/>Broker.publish_event<br/>等待 RabbitMQ 发布确认"]
MQ[("RabbitMQ<br/>zhifu.events / zhifu.fulfillment")]
CONSUME["modules/integrations/worker.py<br/>consume_one<br/>取得消息并管理确认"]
PRE["modules/integrations/fulfillment.py<br/>prepare_event<br/>读取事件、检查消费收据"]
ORDER["modules/integrations/client.py<br/>OmsClient.order<br/>取得最新订单快照"]
OMS["oms/api.py<br/>create_app.get_order<br/>返回凭据范围内订单"]
PREPARE["modules/integrations/fulfillment.py<br/>prepare<br/>复查审批、规则和订单,预占数量"]
OP[("modules/integrations/models.py<br/>ExternalOperation / Reservation<br/>PREPARED 操作与 HELD 数量")]
RECEIPT[("modules/integrations/models.py<br/>ConsumerReceipt<br/>已处理的事件标识")]
EVENT -.->|数据库查询 PENDING 事件| PUB
PUB --> SEND
SEND -.->|发布持久消息| MQ
MQ -.->|queue.get 取得消息| CONSUME
CONSUME --> PRE
EVENT -.->|按 event_id 读取| PRE
PRE -->|审批事件且工单仍为 APPROVED| ORDER
ORDER -.->|"HTTP GET /orders/{order_id};FastAPI 分发"| OMS
PRE -->|取得快照后建立事务| PREPARE
PREPARE -.->|检查通过后共同保存| OP
PRE -.->|与履约准备共同提交| RECEIPT
RECEIPT -.->|重复事件直接结束| PRE
prepare 重新检查租户、店铺、审批员工状态及 approvals:decide 权限,同时核对方案版本、确认记录、规则有效性、连接器配置和 OMS 订单归属。业务条件变化时,工单进入 NEEDS_REVISION;可用数量扣除当前 HELD 数量后不足时,进入 FAILED。
准备成功时,ExternalOperation、Reservation 和工单 PROCESSING 状态共同提交。consume_one 在处理事务完成后确认消息。发布确认和消费收据分别处理发布端重发与消费端重复执行。
execute_due 从数据库领取到期操作,每次增加 lease_token。首次领取提交操作;后续领取先查询同一 operation_id,查询返回 404 才提交操作。仓库使用带有 can_fulfill 权限的凭据调用完成接口。
flowchart TB
OP[("modules/integrations/models.py<br/>ExternalOperation<br/>PREPARED / UNKNOWN / ACCEPTED")]
LOOP["modules/integrations/worker.py<br/>main.executor<br/>持续领取到期操作"]
EXEC["modules/integrations/fulfillment.py<br/>execute_due<br/>取得租约并执行请求"]
CLIENT["modules/integrations/client.py<br/>OmsClient.process<br/>按领取次数提交或查询"]
SUBMIT["oms/api.py<br/>create_app.submit<br/>幂等受理并扣减数量"]
QUERY["oms/api.py<br/>create_app.query<br/>查询当前操作结果"]
EXCHANGE[("oms/models.py<br/>Exchange<br/>保存外部状态与版本")]
WAREHOUSE["仓库请求<br/>具有 can_fulfill 权限"]
COMPLETE["oms/api.py<br/>create_app.complete<br/>推进为 COMPLETED"]
RECORD["modules/integrations/fulfillment.py<br/>record_result<br/>核对租约与外部版本"]
TICKET[("modules/after_sales/models.py<br/>Ticket<br/>保存工单状态")]
VIEW["modules/after_sales/api.py<br/>get_ticket<br/>通过 ticket_view 返回当前进度"]
LOOP --> EXEC
OP -.->|数据库查询到期操作| EXEC
EXEC --> CLIENT
CLIENT -.->|HTTP PUT;首次或查询返回 404;FastAPI 分发| SUBMIT
CLIENT -.->|HTTP GET;后续领取;FastAPI 分发| QUERY
SUBMIT -.->|同一事务保存结果与订单数量| EXCHANGE
EXCHANGE -.->|读取状态与版本| QUERY
WAREHOUSE -.->|"HTTP POST /exchanges/{operation_id}/complete;FastAPI 分发"| COMPLETE
COMPLETE -.->|事务提交 COMPLETED 与新版本| EXCHANGE
EXEC -->|process 返回结果或 None 后| RECORD
RECORD -.->|保存操作状态与下次执行时间| OP
RECORD -.->|保存 PROCESSING / RESULT_UNKNOWN / COMPLETED / FAILED| TICKET
TICKET -.->|后续 GET 请求读取| VIEW
record_result 仅接受当前有效租约提交的结果,并要求外部版本递增。process 遇到传输错误、HTTP 429 或服务端错误时返回 None;尚未明确受理的操作进入 UNKNOWN,对应工单进入 RESULT_UNKNOWN,数量预占继续保持 HELD。已经确认 ACCEPTED 的操作遇到未知结果时保留已确认状态,等待后续查询。
OMS 返回 ACCEPTED 后预占状态为 CONSUMED,工单继续保持 PROCESSING;返回 COMPLETED 后工单完成;明确返回 FAILED 时预占状态为 RELEASED。完成接口由外部履约方调用,平台工作进程通过后续查询取得完成结果。
Ticket.version 控制工单并发修改;Ticket.proposal_version 标识当前方案。ProposalVersion 保存当时的规则、订单版本和规则依据。Confirmation 与 Approval 都关联具体方案版本。revise 增加方案版本,将待处理旧审批改为 INVALIDATED,工单回到 DRAFT,需要客户重新确认。CommandReceipt 使用租户、操作者、操作路径和 Idempotency-Key 组成作用域;相同标识更换参数返回 IDEMPOTENCY_CONFLICT。BusinessEvent.aggregate_version 用于确认事件仍对应当前工单。ConsumerReceipt 以消费者名称和事件标识记录处理结果。ExternalOperation.id 作为 OMS 的 operation_id 保持不变。操作的执行租约和外部结果版本分别控制当前工作进程提交权、外部状态推进。DRAFT → WAITING_REVIEW → APPROVED → PROCESSING → COMPLETED。审批可以进入 REJECTED;取消操作受当前状态和外部操作登记情况约束;履约准备可能进入 NEEDS_REVISION 或 FAILED。operation_id,并拒绝旧工作进程提交的结果?本路线只阅读测试代码,未执行下列用例。