1. 文档目标

财务、报表、MQ、OA 和同步任务不是一个单独业务模块,而是采购、销售、库存、活动、渠道和移动商城共同依赖的横向能力。本文要回答四个容易被混淆的问题:

  1. 钱有没有支付成功:以支付中心回调及其状态为依据。
  2. DGJ 财务事实有没有落库:看付款主单、付款明细、账户流水和采购支付扩展。
  3. 业务状态和下游系统有没有推进:看采购/预订单状态、活动状态和 MQ 消费结果。
  4. 报表什么时候可见、口径是否一致:区分实时业务表和 Hologres DWD 数据。

本文适用于:

  • 采购或预订单显示支付成功,但采购状态、付款单或账户余额不对;
  • 支付中心重复回调、异常回调或退款回调排查;
  • 报表与业务页面金额、数量或状态不一致;
  • OA 已审批但 DGJ 活动、额度或费用状态没有变化;
  • 销售单、出库单已经完成,但 SaaS/APP/其他下游没有收到消息;
  • MQ 队列无积压,但业务仍没有推进;
  • 修改 MqSer、支付回调、报表或同步 Builder 前做影响评估。
本文结论来自当前代码静态核对。支付中心、OA、Hologres、RabbitMQ 和下游系统的生产重试、唯一键、数据延迟及网关合同仍需对应环境证据确认。

2. 先建立四层事实模型

flowchart LR
    EXT["外部事实\n支付中心 / OA / 订单中心"]
    MQ["消息事实\ndestination + routing key"]
    BIZ["DGJ 业务事实\n订单状态、活动状态、库存"]
    FIN["DGJ 财务事实\n付款单、明细、账户流水"]
    DWD["分析事实\nHologres DWD"]
    DOWN["下游事实\nSaaS / APP / OA / OPS"]

    EXT --> MQ
    MQ --> BIZ
    MQ --> FIN
    BIZ --> DWD
    FIN --> DWD
    BIZ -->|"dgj_notify 等"| DOWN

这四层不能相互替代:

现象能证明什么不能证明什么
支付中心返回成功外部支付结果成功DGJ 已完成财务落账和订单推进
MQ 已 ACK消费者确认了消息所有业务分支都成功,部分代码会记录异常后 ACK
采购单已更新业务状态已推进付款主明细、账户流水一定完整
付款单存在部分财务事实存在采购状态、活动、下游同步一定成功
业务库有数据事务事实已落库Hologres DWD 已同步并可查询
报表有数据分析层已有快照当前实时业务状态与报表完全一致

排查必须沿“外部回调 -> 消息 -> 业务表/财务表 -> 下游/报表”逐层取证。

3. 代码入口地图

3.1 财务与支付

业务入口核心实现
PC 收付款application/controllers/scm/Payment.php传统收付款单操作和 PaymentSer
财务控制器application/controllers/financial/财务查询和专项能力
账户管理application/controllers/saleAccount/Account.php账户及流水展示
支付中心回调application/controllers/tasks/PayCenterNotify.php支付、调额、提现、授信、退款等事件
全车件结算回调application/controllers/tasks/QPayCenterNotify.phpqpaycenter_notify 回调
收付款领域application/Services/Payment/PaymentSer.php收付款业务 Service
还款领域application/Services/Payment/RepaymentSer.php授信还款单
账户缓存application/Services/BaseData/AccountSer.php系统账户创建后的缓存刷新

3.2 报表

业务控制器Service/Provider
采购订单、采退、入库controllers/reports/PurchaseReport.phpPurchaseReportSer -> PurchaseProvider
销售明细、商品销售、对账controllers/reports/SaleReport.phpSaleReportSer / SaleProvider
库存进销存controllers/reports/InventoryReport.phpInventoryReportSer
利润controllers/reports/ProfitReport.phpProfitReportSer / 报表 Provider
客户分析controllers/reports/CustomerReport.phpCustomerReportSer 并行请求多个指标
应收/应付报表和旧控制器入口AccountReceiveSer, AccountPaySer
旧报表application/controllers/Report.php直接模型或历史实现

3.3 MQ、OA 和同步

业务文件职责
MQ 常量application/KzData/Enums/MqEventEnums.phpdestination、routing key 和部分关系表
通用生产者application/Services/Mq/MqSer.php库存、采购、APP、活动、OA、渠道、对账等事件
消费者任务application/controllers/tasks/*Notify.php按目标队列注册回调并 ACK/NACK
OA 回调tasks/OaNotify.php按模板码分发额度、费用、活动和秒杀审批
OA 结果回传tasks/OaResultNotify.php调用 OA Provider 同步结果
销售同步Services/SyncOrder/SyncOrderSer.php将销售和出库事件发布到 dgj_notify
同步报文Services/SyncOrder/SyncOrderBuilder.php把 DGJ 单据转换为下游合同字段

4. 财务数据模型

4.1 核心表

常量/模型物理表用途关键字段
SCM_PAYMENT / PaymentModelt_scm_payment_{sid % 32}收款、付款、其他收入/支出主单id, billNo, billType, transType, buId, totalAmount, billStatus, sid
SCM_PAYMENT_INFO / PaymentInfoModelt_scm_payment_info_{sid % 32}收付款业务、账户和来源单明细iid, billNo, amount, accId, wayId, paymentType, stlId, stlNo
SCM_ACCOUNTt_scm_account账户流水/当月账户事实来源单、账户、方向和金额
SCM_PO_ORDER_PAYINFOt_scm_po_order_payinfo采购/预订单在线支付拆分信息iid, billNo, amount, type, discount, rebate, refund, service_amount
SCM_REPAYMENT_ORDERt_scm_repayment_order授信还款单还款单号、状态、金额和支付关系
SCM_PAYMENT_LOGt_scm_payment_log付款操作日志业务单和操作记录
SCM_PO_ORDERt_scm_po_order采购状态和支付时间id, billNo, billStatus, paymentTime, srcOrderType

SCM_PAYMENT_SUB_NUM = 32,主表和明细表都按:

payment_table      = t_scm_payment_{sid % 32}
payment_info_table = t_scm_payment_info_{sid % 32}

因此只查无后缀旧表或错误分片,可能误判为“没有付款单”。

4.2 主单、明细和账户流水关系

erDiagram
    PO_ORDER ||--o{ PO_PAYINFO : "iid / billNo"
    PAYMENT ||--o{ PAYMENT_INFO : "iid"
    PAYMENT_INFO ||--o{ ACCOUNT_FLOW : "业务来源与账户"
    PO_ORDER ||--o{ PAYMENT_INFO : "stlId / stlNo"

    PO_ORDER {
      int id
      string billNo
      int billStatus
      datetime paymentTime
    }
    PAYMENT {
      bigint id
      string billNo
      string billType
      decimal totalAmount
      int sid
    }
    PAYMENT_INFO {
      bigint iid
      decimal amount
      int accId
      int stlId
      string stlNo
    }
    PO_PAYINFO {
      int iid
      string billNo
      int amount
      string type
      int rebate
      int refund
    }

一笔在线支付可能产生:

  • 一张付款主单和多条付款明细;
  • 多个支付账户对应的账户流水;
  • 一条采购支付扩展记录;
  • 若使用授信,额外生成“其他收入”主单、明细和账户流水;
  • 若是预订单,每个支付账户分别生成一张其他支出单。

5. 支付中心消费者

5.1 队列和事件

目标队列:paycenter_notify。

routing key回调方法主要业务
paycenter_pay_resultpaycenterPayResult()采购/预订单支付成功落账和状态推进
paycenter_balance_adjustpaycenterBalanceAdjust()账户额度调增/调减及其他收入/支出
paycenter_refund_account_withdraw_resultpaycenterRefundWithdrawResult()待退款账户提现结果
paycenter_baitiao_return_pay_resultpaycenterBaitiaoReturnPayResult()授信还款支付
paycenter_baitiao_expirepaycenterBaitiaoExpire()授信到期提醒
paycenter_pay_exceptionpaycenterPayException()支付抵扣异常,关闭待支付采购单
paycenter_installment_expirepaycenterInstallmentExpire()分期到期处理
paycenter_refund_resultpaycenterRefundResult()退款结果
paycenter_baitiao_offline_returnpaycenterBaitiaoOfflineReturnPayResult()线下授信还款结果
paycenter_baitiao_service_overdue_changepaycenterBaitiaoServiceOverdueChange()服务站授信逾期变化

本文重点展开 paycenter_pay_result;其他事件在第 18 篇财务和支付排查手册继续按请求字段逐项展开。

6. 支付成功回调合同

6.1 代表性请求

回调由 MQ 直接传入数组,不是普通 HTTP 控制器请求。代表性结构:

{
  "sourceOrderNo": "PO...",
  "sourceOrderType": "01",
  "payOrderNo": "支付中心单号",
  "mainPayTypeCode": "02",
  "payStatus": "02",
  "payStatusMsg": "支付成功",
  "existsCashDiscount": "1",
  "cashDiscountRate": "99.7",
  "cashDiscountAmount": 70,
  "detailTotalAmount": 345000,
  "payTime": "2026-07-15 10:00:00",
  "details": [
    {
      "payAccountTypeCode": "02",
      "payAccountTypeDesc": "个人付款账户",
      "payAmount": 340000,
      "serviceAmount": 0
    },
    {
      "payAccountTypeCode": "06",
      "payAccountTypeDesc": "待退款账户",
      "payAmount": 5000,
      "serviceAmount": 0
    }
  ]
}

重要字段:

字段当前代码用法
sourceOrderNo查采购单或预订单的业务主键
sourceOrderType04 表示预订单;其他分支按采购单处理
payStatus仅字符串 02 视为成功
mainPayTypeCode主支付账户类型,影响混合支付和授信逻辑
detailTotalAmount支付中心金额,代码按分处理并除以 100 落付款主单
details按 payAccountTypeCode 重建映射,同类型重复行可能被后行覆盖
serviceAmount支付服务费,回调单位与 payAmount 相同
折扣/返利/退款字段写采购支付扩展,用于采购详情和可优惠金额

6.2 支付账户类型

代码含义特殊处理
01企业付款账户主支付或混合支付组成
02个人付款账户主支付或混合支付组成
05返利账户写 rebate
06待退款账户写 refund;若作为主支付类型会转换为 00
07快准授信账户生成授信借款“其他收入”单
08他行融资账户混合支付组成
10工行 E 贷描述中拆订单金额和服务费
12银联付款账户系统在线账户
15专属返利账户写 exclusive_rebate
18网商付款账户混合支付组成
20预充值账户系统在线账户
990 元订单跳过财务单据创建,直接推进订单状态
100混合支付DGJ 计算出的展示类型,不是普通明细账户

系统账户号使用前缀 10 + payAccountTypeCode 避免与已有账户编号冲突。账户不存在时会创建,再调用 AccountSer::updateAccountCache() 刷新缓存。

7. 支付成功完整数据流

7.1 总流程

sequenceDiagram
    participant PC as 支付中心
    participant MQ as paycenter_notify
    participant C as PayCenterNotify
    participant O as 采购单/预订单
    participant P as 付款主表/明细
    participant A as 账户流水
    participant PI as po_order_payinfo
    participant ACT as 活动/秒杀

    PC->>MQ: paycenter_pay_result
    MQ->>C: 回调报文
    C->>C: payStatus 必须为 02
    C->>O: 按 sourceOrderType 查询并校验状态
    C->>C: 开启数据库事务
    C->>P: 创建付款或其他支出主单/明细
    C->>A: saveAccounts()
    C->>PI: 写支付方式、折扣、返利、退款、服务费
    opt 授信支付
        C->>P: 创建其他收入主单和明细
        C->>A: 写授信账户流水
    end
    C->>O: 更新支付时间和业务状态
    opt 秒杀采购单
        C->>ACT: markPaidByPoOrder()
    end
    C->>C: 提交事务
    C-->>MQ: ACK;异常时 NACK

7.2 来源订单分支

flowchart TD
    A["sourceOrderType"] --> B{"是否 04 预订单"}
    B -->|是| PRE["查询 preOrder"]
    PRE --> PREST["允许待支付、取消、自动取消"]
    PREST --> PREPAY["每个账户生成一张 QTZC 其他支出单"]
    PREPAY --> PRESTATE["payedPreOrder() 推进预订单"]

    B -->|否| PO["按 sourceOrderNo 查询采购单"]
    PO --> POST["仅允许 wait_pay 或 pay_overtime"]
    POST --> ZERO{"mainPayTypeCode 是否 99"}
    ZERO -->|是| STATE["跳过财务单,采购状态改 submitted"]
    ZERO -->|否| PAY["一张 FKD 付款主单 + 多条明细"]
    PAY --> STATE
    STATE --> FLASH{"srcOrderType 是否秒杀"}
    FLASH -->|是| MARK["markPaidByPoOrder"]

7.3 采购单分支落账

采购单支付生成:

  1. 付款主单 FKD,billType=PAYMENT。
  2. 每个支付账户一条 PaymentInfo。
  3. AccountService::saveAccounts() 统一写账户事实。
  4. 一条 PoOrderPayInfo 记录主支付、混合支付、折扣、返利、退款和服务费。
  5. 授信支付额外生成其他收入主单和明细。
  6. 采购单状态更新为 BILLSTATUS_SUBMITED,写 paymentTime 和支付意见。
  7. 秒杀来源调用 FlashSaleSer::markPaidByPoOrder()。

7.4 预订单分支落账

预订单使用其他支出单:

  • billType=QTZC;
  • 每个支付账户单独生成一张付款主单;
  • 明细金额先以元写 PaymentInfo,写账户流水前转换为负数;
  • 最后调用 PreOrderService::payedPreOrder() 推进预订单。

8. 金额单位和计算

这是财务排查最容易出错的地方。

8.1 支付回调到财务表

付款主单 totalAmount = detailTotalAmount / 100
付款明细 amount       = (payAmount + serviceAmount) / 100
含服务费主单总额      = (detailTotalAmount + 所有 serviceAmount) / 100

Payment 和 PaymentInfo 以“元”落库。

8.2 采购支付扩展

PoOrderPayInfo 直接保存支付中心原始数值:

amount              = 主支付及部分混合支付 payAmount
discount            = cashDiscountAmount
rebate              = 返利账户 payAmount
exclusive_rebate    = 专属返利 payAmount
refund              = 待退款账户 payAmount
service_amount      = serviceAmount 汇总
can_disc_amount     = 可参与优惠的原始金额

这些值没有在回调中除以 100,应按支付中心原始单位理解。跨表对账时不能直接把 po_order_payinfo.amount 与 payment_info.amount 相加比较,应先统一单位。

8.3 混合支付判定

代码先把主账户金额放入 paymentPayInfo,再遍历明细:

  • 若发现企业、个人、授信、融资或网商账户不是主支付方式,则类型改为 100 混合支付并累加金额;
  • 如果组合中包含授信和退款/返利/专属返利,为采购详情展示会强制把类型改为授信;
  • 主方式为 00、专属返利或待退款账户时,初始实付金额按 0 处理;
  • 主方式最终为待退款账户 06 时,写入类型 00。

因此“展示支付类型”和“实际支付账户明细”不是同一口径,真实拆分应查 PaymentInfo 和账户 ID。

9. 支付状态和幂等边界

9.1 收付款单状态

值含义
0已确认
1已提交
2已确认,V2 兼容值
6已撤销

报表和应收应付查询通常排除 billStatus=6 和软删除数据。

9.2 支付成功回调的当前幂等方式

当前主要依赖来源订单状态:

  • 采购单只接受待支付或支付超时;
  • 预订单只接受待支付、取消或自动取消;
  • 处理后状态改变,重复消息会因状态不允许而抛错。

需要注意:状态不允许时回调返回 NACK,不是把“已处理的重复成功消息”识别为 ACK。若 MQ 对 NACK 持续重投,可能形成重复告警或重试循环,必须确认生产重试和死信策略。

payOrderNo 在当前核心成功分支中没有被写成显式幂等键。应核对表唯一索引和支付中心回调合同,不能仅靠代码推断为强幂等。

9.3 事务边界

支付主流程在采购模型数据库连接上开启事务,付款、明细、账户、采购支付信息、订单状态和秒杀标记都在提交前执行。

事务提交后还会查询任务记录并调用 TaskSer::execute()。该调用仍位于 try 内:若它在事务已经提交后抛异常,catch 会尝试回滚并返回 NACK,但已提交的财务和订单数据无法真正回滚。重复投递时可能再次进入回调。这是必须重点回归的“提交后副作用”风险。

10. 支付异常回调

paycenter_pay_exception 代表账户抵扣等支付异常:

{
  "sourceOrderNo": "PO...",
  "exceptionDesc": "支付中心异常说明"
}

处理:

  1. 按采购单号查询 ID。
  2. 调用 PoOrderSer::cancelWaitPayOrder(orderId, true, message)。
  3. 成功返回 ACK。
  4. 订单不存在或关闭失败返回 NACK。

秒杀待支付采购单关闭时,释放锁定量和购物车/秒杀订单状态的具体逻辑由采购取消及 FlashSaleSer 共同完成,应同时对照第 05、17 篇。

11. 额度调整回调

paycenter_balance_adjust 先用 adjustNo 在付款明细中查重:

  • type=01:调增,生成其他收入;
  • 其他值:调减,生成其他支出,写账户时金额转负;
  • 授信账户调整不在这里生成收入单,授信收入改在实际支付时生成;
  • 账户不存在时自动创建并刷新缓存;
  • 完成后发送账户主题站内信。
flowchart TD
    MSG["balance_adjust"] --> IDEM{"adjustNo 是否已处理"}
    IDEM -->|是| NACK["抛重复异常并 NACK"]
    IDEM -->|否| TYPE{"type 是否 01"}
    TYPE -->|是| IN["其他收入"]
    TYPE -->|否| OUT["其他支出,账户金额取负"]
    IN --> DETAIL["逐账户创建付款主明细"]
    OUT --> DETAIL
    DETAIL --> SKIP{"是否授信账户"}
    SKIP -->|是| NO["跳过本次收入/支出生成"]
    SKIP -->|否| ACC["saveAccounts"]
    ACC --> NOTICE["发送站内信"]

重复调额当前也抛错并返回 NACK,需确认是否会被无限重投。

12. 报表系统架构

12.1 两类报表来源

flowchart LR
    UI["报表页面"] --> CTRL["reports/* Controller\n权限 + 参数校验"]
    CTRL --> TYPE{"数据来源"}
    TYPE -->|实时/历史本地| MODEL["MySQL 分片表/业务表"]
    TYPE -->|分析报表| SER["Report Service 生成 SQL"]
    SER --> PROVIDER["Report Provider"]
    PROVIDER --> HOLO["CENTER_API\n/devcenter/report/hologres/query"]
    HOLO --> DWD["Hologres DWD"]
    MODEL --> FORMAT["格式化/汇总/导出"]
    DWD --> FORMAT
    FORMAT --> UI

第一类直接查 DGJ 业务表或分片财务表,第二类由 DGJ 生成 SQL,再把 SQL、offset、size 发给中心报表接口查询 Hologres。

12.2 代表性采购报表请求

应用内入口:reports/PurchaseReport/purchaseOrderDetailReport。

{
  "beginDate": "2026-07-01",
  "endDate": "2026-07-15",
  "page": 1,
  "rows": 100,
  "JXCSID": 10001,
  "billNo": "可选采购单号",
  "skuId": "可选SKU"
}

基础校验:

  • 开始、结束日期必须为 Y-m-d;
  • page、rows 必须为数字;
  • rows <= 1000;
  • JXCSID > 0;
  • 先检查报表查询权限;导出使用独立导出权限。

返回统一结构:

{
  "records": 120,
  "page": 1,
  "total": 2,
  "limit": 100,
  "rows": [],
  "sum": []
}

12.3 Hologres 请求

{
  "sql": "select ... from dwd_... where ...",
  "offset": 0,
  "size": 100
}

标准流程:

  1. 生成 count SQL 和列表 SQL。
  2. 请求 count,得到 total。
  3. 根据 page/rows 计算 offset 和总页数。
  4. 请求当前页。
  5. 汇总可能循环请求全部分页,再在 DGJ 内计算合计。
  6. 把 DWD 字段转换成页面字段。

导出通常循环拉取所有分页,数据量大时会产生多次远程请求,应关注超时、内存和导出时间。

12.4 主要 DWD 表

报表DWD 表主要口径
采购订单明细dwd_bbyh_dgj_scm_po_order采购数量、发货、待入、已入、关闭、金额
采购退货dwd_bbyh_dgj_scm_po_order_return采购退货单和明细
采购入库dwd_bbyh_dgj_scm_pu_invoice入库数量、金额、供应商和商品
应收应付余额dwd_dgj_home_arrears客户/供应商余额
DGJ 出库dwd_dgj_out_bound出库单和商品事实
赠品活动dwd_dgj_activity_gift 等活动订单采购退货和站点
销售对账dwd_bbyh_dgj_sa_invoice_payment_info销售出库与收款对账
销售历史dwd_dgj_sale_history历史销售搜索和分析
库存进销存dwd_bbyh_dgj_scm_inventory_all入库、出库、期末库存等

12.5 采购报表部分计算

采购订单明细把 DWD 字段转换为:

采购金额 = amount
已发数量 = outqty
待入数量 = waitqty
已入数量 = inqty
关闭数量 = closeqty
入库金额 = price * inqty - deduction * inqty / qty

当原采购 qty=0 时,入库金额公式存在除零风险;正常业务应不产生零数量采购明细,但历史/修复数据仍需防御。

13. 报表延迟和对账方法

13.1 正确排查顺序

flowchart TD
    A["页面/业务表已更新,报表没有"] --> B["确认业务主表和明细真实落库"]
    B --> C["确认状态、软删除、日期、sid 和分片"]
    C --> D["确认对应 DWD 表是否已有业务键"]
    D --> E{"DWD 是否存在"}
    E -->|否| F["查同步任务/SLA/数据平台"]
    E -->|是| G["对照报表 SQL where 和字段转换"]
    G --> H["检查权限、日期边界、分页和汇总"]

不要为了解决报表延迟直接修改业务表;先判断是业务事实错误、ETL 未同步、报表 SQL 过滤还是展示计算错误。

13.2 时间口径

报表常见时间字段不统一:

  • 业务单据日期 billDate;
  • 创建时间 create_time;
  • DWD 业务日期 dw_billdate;
  • 支付时间 paymentTime/payTime;
  • 入库/出库实际发生时间。

同一业务单按不同时间过滤可能落在不同日期范围。排查必须确认页面使用的具体字段,而不是只看用户选择的“日期”。

14. MQ 拓扑

14.1 主要 destination

destination方向典型业务
dgjDGJ 内部异步库存事件、采购关闭、延时取消、搜索日志、OPS 订单
ordercenter_notify订单中心 -> DGJ采购审核、售后、取消、关闭、自制订单
dispatchcenter_notify配送/调拨中心 -> DGJ发货出库、物流、自提、退货关闭
paycenter_notify支付中心 -> DGJ支付、退款、授信、提现、调额
itemcenter_notify商品中心 -> DGJ限购、套包、价格、生效失效、敏感词
oa_notifyOA -> DGJ审批结果
oa_result_notifyDGJ -> OA/费用系统OA 结果同步
dgj_notifyDGJ -> 下游销售、出库、APP、活动和其他业务通知
dgj_channelDGJ 渠道内部/OPS渠道人工单、审核、发货、退货
dgj_statement*DGJ 对账任务策略、生成、收款状态和发送

14.2 常见生产者

方法destination / routing key代表 payload
sendInventoryEvent()dgj / inventory_eventsid, 库存变动、流水 ID、单据和采购 ID
sendInStorageEvent()dgj_notify / dgj_po_in_storagedetails
sendPoCloseOrderConfirm()dgj / po_close_order_confirm关闭确认参数
sendPauseCancel()dgj / dispatch_pause_cancel_delay_60token
sendSaOrderOutToMq()dgj_notify / app_sa_order_out销售出库通知参数
sendSaOrderStatusToMq()dgj_notify / app_sa_order_status配送状态参数
sendActivityStartToSaas()dgj_notify / activity_startsids
sendActivityEndToSaas()dgj_notify / activity_endsids
sendOAResult()oa_result_notify / oa_result_notify_syncid, status
sendStatementStrategySync()dgj_statement_strategy / statement_strategy_sync对账策略参数
sendStatementBillCreate()dgj_statement / statement_bill_create对账单生成参数
sendStatementSend()dgj_statement_send / statement_send发送任务参数

14.3 主要消费者

任务destination主要回调
OrderCenterNotifyordercenter_notify采购审核、售后、取消、关闭、预订单、自制订单
DispatchCenterNotifydispatchcenter_notify出库、物流、自提、退货关闭、标签变化
PayCenterNotifypaycenter_notify支付、退款、授信、调额、提现
ItemCenterNotifyitemcenter_notifySKU 限购、套包、价格、敏感词
OaNotifyoa_notifyoa_audit
OaResultNotifyoa_result_notifyoa_result_notify_sync
SaasOrderNotifydgj库存、采购关闭、OPS 订单、搜索和站点事件
ChannelOrderNotifydgj_channel渠道人工创建、发货、退货、审核
StatementNotifydgj_statement对账单生成和收款状态同步

14.4 消息不等于事务

sequenceDiagram
    participant B as 业务 Service
    participant DB as MySQL
    participant MQ as RabbitMQ
    participant C as Consumer
    participant D as 下游/副作用

    B->>DB: 写业务表
    B->>MQ: publish
    Note over DB,MQ: 多数代码不是标准 Outbox 原子提交
    MQ->>C: deliver
    C->>D: 执行业务
    alt 成功
        C-->>MQ: ACK
    else 可重试异常
        C-->>MQ: NACK
    else 参数/业务不匹配
        C-->>MQ: ACK 丢弃
    end

当前代码大量采用“业务提交后直接发 MQ”或“事务中调用外部 Service”的方式。若 DB 成功而 publish 失败、MQ 成功而 DB 回滚、消费者部分成功后 NACK,都可能产生不一致。排查和设计补偿时必须明确每个动作发生在事务前、事务内还是提交后。

15. OA 审批链路

15.1 OA 回调合同

目标队列:oa_notify,routing key:oa_audit。

代表性报文:

{
  "templateCode": "业务模板码",
  "summaryId": "业务或OA关联标识",
  "status": 2,
  "reason": "审批意见"
}

OA 状态:

值含义
2审批成功
3审批失败

OaNotify::oaAudit() 先按 templateCode 分流,再调用具体业务 Service:

  • 授信资金池;
  • 专属授信活动申请;
  • 业务/费用同步;
  • 授信额度调整、总额度和顾问额度申请;
  • 活动申请和活动变更;
  • 秒杀活动。

未知模板进入 default 后不执行任何业务,最终返回 ACK。这意味着模板配置错误可能表现为“队列消费正常但业务完全没变化”。

15.2 通用 OA 分流

flowchart TD
    MQ["oa_notify / oa_audit"] --> CODE["读取 templateCode"]
    CODE --> BT["授信/额度"]
    CODE --> EXP["业务/费用同步"]
    CODE --> ACT["活动申请/变更"]
    CODE --> FLASH["秒杀 callback_20260526"]
    EXP --> RESULT["sendOAResult"]
    RESULT --> OAOUT["oa_result_notify"]
    OAOUT --> PROVIDER["OaProvider::oaStatusSync"]

业务/费用模板不会直接在 OaNotify 调外部接口,而是发送 oa_result_notify_sync,由 OaResultNotify 调 OaProvider::oaStatusSync();异常返回 NACK。

15.3 秒杀 OA

秒杀模板码:FlashActivityEnums::OA_TEMPLATE_CODE = callback_20260526。

sequenceDiagram
    participant OPS as OPS
    participant F as FlashActivitySer
    participant OA as OA Provider
    participant MQ as oa_notify
    participant N as OaNotify
    participant DB as flash_activity

    OPS->>F: 提交秒杀活动
    F->>OA: submit(payload)
    OA-->>F: id / oa_no / requestId
    F->>DB: apply_status=WAIT, oa_status=WAIT, oa_no
    OA->>MQ: oa_audit(templateCode, summaryId, status)
    MQ->>N: oaAudit
    N->>F: callback20260526(message)
    F->>DB: 按 oa_no 查询活动
    alt 通过
        F->>DB: PASS + 按时间计算 enable_status + 商品提交状态
    else 拒绝
        F->>DB: REJECT + reject_reason
    end

回调兼容多个字段:

  • OA 号:oa_no、oa_number、requestId、summaryId;
  • 结果:status、result、auditResult;
  • 通过:2、1、PASS、AGREE、SUCCESS;
  • 拒绝:3、0、REJECT、FAIL。

找不到 OA 号、找不到活动或结果未知会抛异常,OaNotify 返回 NACK。

16. 销售和出库同步下游

16.1 事件字典

目标:dgj_notify。

routing key触发方法业务事实
garage_repair_order_createdsyncOrderCreate()销售单创建
garage_repair_order_updatedsyncOrderUpdate()销售单修改
garage_repair_order_cancelledsyncOrderCancel()销售单关闭
garage_repair_order_stoppedsyncOrderStop()销售单结单
garage_repair_order_completed枚举保留销售单完成
garage_repair_order_expired枚举保留销售单过期
garage_repair_outbound_createdsyncOutboundCreate()销售出库创建
garage_repair_outbound_updatedsyncOutboundUpdate()出库编辑
garage_repair_outbound_cancelledsyncOutboundCancel()出库撤销

SyncOrderSer::publish() 每次创建 Topic Producer,发布后关闭 channel,并记录 eventType + data 日志。

16.2 销售单创建报文

{
  "stationId": 10001,
  "orderScene": "z_offline",
  "orderType": 7,
  "orderId": 123,
  "orderNo": "SO...",
  "orderStatus": 2,
  "contactId": 456,
  "contactName": "客户名称",
  "totalQty": 2,
  "totalAmount": "200.00",
  "payMode": "CASH",
  "storeId": 10,
  "source": 5,
  "entries": [
    {
      "skuId": "SKU001",
      "invId": 100,
      "goodsType": 1,
      "isGift": 0,
      "qty": 2,
      "price": 100,
      "amount": 200
    }
  ]
}

当前 buildOrderEvent() 对创建和更新都固定:

  • orderScene=z_offline;
  • orderType=7;
  • orderStatus=2 待出库;
  • source=5;
  • 挂账映射 payMode=CHARGE,其他为 CASH;
  • 明细金额近似零时视为赠品;
  • 空 skuId 视为三方物料。

虽然 Builder 定义了 ORDER_TYPE_MAP,创建报文没有按来源使用该映射,而是固定线下订单 7。如果此 Service 被 E站、活动、机器人等来源复用,下游来源分类可能失真,需核对真实调用范围。

16.3 出库报文

{
  "sid": "10001",
  "contactId": 456,
  "outOrderNumber": 2,
  "saInvoiceOrderId": 123,
  "saInvoiceOrderNo": "SO...",
  "saInvoiceBillNo": "XSCK...",
  "submitTime": "2026-07-15 10:00:00",
  "outTime": "2026-07-15 10:00:00",
  "detail": [
    {
      "invId": "100",
      "skuId": "SKU001",
      "goodsOutPrice": 200,
      "goodsOutNumber": 2,
      "isGift": 0,
      "locationId": 10,
      "locationAreaId": 100
    }
  ]
}

仓库和货位从每个明细的 qtyGrid 中提取;如果同一明细跨多个货位,循环最终只保留最后一个非零出库网格的 locationId/locationAreaId,下游无法从该报文还原多货位拆分。这是合同精度风险。

16.4 同步不应反推业务提交

flowchart LR
    SAVE["销售/出库业务提交"] --> DB["业务表 + 库存"]
    SAVE --> SYNC["SyncOrderSer"]
    SYNC --> MQ["dgj_notify"]
    MQ --> DOWN["SaaS/维修厂下游"]

    DOWN -. "收到消息" .-> ACK["下游事实"]

下游没收到时先确认 DGJ 业务事实是否完成,再查同步调用、生产日志和 MQ;不要通过重做销售出库来补消息,否则可能重复扣库存。

17. 常用只读 SQL

17.1 查采购单支付状态

SELECT id, sid, billNo, billStatus, srcOrderType,
       totalAmount, paymentTime, auditOpinion, createTime
FROM t_scm_po_order
WHERE billNo = 'PO...';

17.2 查采购支付扩展

SELECT id, sid, iid, billNo, amount, type,
       discount, disRate, rebate, refund,
       exclusive_rebate, service_amount
FROM t_scm_po_order_payinfo
WHERE billNo = 'PO...'
ORDER BY id;

注意这里金额可能仍为支付中心原始“分”单位。

17.3 查付款主单和明细

先计算:

shard = sid % 32

然后查询对应分片:

SELECT id, billNo, billType, transType, transTypeName,
       buId, totalAmount, billStatus, sid, billDate, createTime
FROM t_scm_payment_{shard}
WHERE sid = 10001
  AND (billNo = 'FKD...' OR id = 付款主单ID);

SELECT id, iid, billNo, transType, amount,
       accId, wayId, paymentType, stlId, stlNo,
       description, createTime
FROM t_scm_payment_info_{shard}
WHERE sid = 10001
  AND (stlNo = 'PO...' OR iid = 付款主单ID)
ORDER BY id;

17.4 查是否重复调额

SELECT id, iid, billNo, stlNo, amount, accId, createTime
FROM t_scm_payment_info_{shard}
WHERE sid = 10001
  AND stlNo = 'adjustNo';

17.5 业务库与 DWD 对账

业务库先查真实单号、业务日期、状态和数量;Hologres 使用内部报表查询工具按业务键执行只读 SQL,例如:

SELECT *
FROM dwd_bbyh_dgj_scm_po_order
WHERE station_code = '10001'
  AND bill_code = 'PO...';

不要把 Hologres SQL 直接拼入生产业务接口;应通过既有 Provider 或数据平台工具执行,并记录查询时间。

18. 日志和代码检索

rg -n "支付消息通知|支付异常消息通知|价格调整单消息通知" application/controllers/tasks/PayCenterNotify.php
rg -n "sourceOrderNo|payStatus|detailTotalAmount|payAccountTypeCode" application/controllers/tasks/PayCenterNotify.php
rg -n "createTopicConsumer|createDirectConsumer|registryCallback" application/controllers/tasks
rg -n "createTopicProducer|createDirectProducer" application/Services/Mq application/Services/SyncOrder
rg -n "hologres/query|dwd_" application/Services/Report application/Providers/ReportService
rg -n "oa_audit|templateCode|callback20260526" application/controllers/tasks application/Services/Activity
rg -n "garage_repair_order_|garage_repair_outbound_" application/Services/SyncOrder

日志分类:

链路Logger/关键字
支付成功PayCenterNotify/payCenterPayResult
支付异常PayCenterNotify/paycenterPayException
调额cron/paycenterBalanceAdjust
OAOaNotify/oaAudit, OaNotify/oaResultSync
销售同步Services/syncData,关键字 SyncOrder发送消息
报表控制器异常返回、Provider 请求日志和中心报表日志

19. 按现象排查

19.1 支付中心成功,采购单仍待支付

flowchart TD
    A["支付成功但采购单未推进"] --> B{"PayCenterNotify 是否收到 pay_result"}
    B -->|否| C["查 paycenter_notify 路由和生产端"]
    B -->|是| D{"payStatus 是否字符串 02"}
    D -->|否| E["当前代码 NACK,查支付中心状态"]
    D -->|是| F{"sourceOrderNo 是否存在"}
    F -->|否| G["核对环境和订单号"]
    F -->|是| H{"原状态是否 wait_pay/pay_overtime"}
    H -->|否| I["重复消息或状态已被其他流程改变"]
    H -->|是| J["查事务异常、财务表和回调日志"]

19.2 采购单已支付,但没有付款单

  1. 确认 mainPayTypeCode 是否为 99 零元订单;该分支有意不创建付款单。
  2. 用 sid % 32 查正确付款分片。
  3. 查 t_scm_po_order_payinfo 是否存在。
  4. 查 PaymentModel/PaymentInfoModel 写入日志和事务异常。
  5. 对预订单按 QTZC 和来源单号查询,不要只找 FKD。
  6. 确认是否主付款单存在但某账户明细或账户流水缺失。

19.3 付款主单金额和采购支付金额差 100 倍

  1. 确认比较的是哪两张表。
  2. Payment/PaymentInfo 通常为元。
  3. PoOrderPayInfo 的支付、返利、退款、服务费通常保留回调原始分。
  4. 统一转换后再核对。
  5. 区分 detailTotalAmount 是否包含服务费;主单最后会把服务费加回。

19.4 同一支付消息反复消费

  1. 查采购/预订单是否已被第一次回调推进。
  2. 查第一次是否已提交财务事务。
  3. 查回调是否在提交后执行任务时抛错并返回 NACK。
  4. 查 MQ 重试次数、重新入队和死信策略。
  5. 不要手工删除已落财务数据来“让重试通过”;应先确定幂等补偿方案。

19.5 报表查不到刚完成的业务单

  1. 查业务主表、明细和状态。
  2. 确认业务日期字段和查询日期范围。
  3. 查目标 DWD 表是否已有业务单号。
  4. 没有 DWD:查 ETL/同步 SLA。
  5. 有 DWD:复现 Service 生成的 SQL 和过滤条件。
  6. 检查权限、站点、分页、软删除和状态排除。

19.6 报表数量正确但金额不一致

  1. 对照 DWD 原始 price/amount/deduction/qty。
  2. 检查 DGJ 格式化公式和单位。
  3. 检查退货是否用负数或单独交易类型。
  4. 检查服务费、优惠、返利是否在不同报表分开体现。
  5. 检查汇总是否循环拉取了全部页,远程请求是否中途超时。

19.7 OA 显示通过,DGJ 没变化

  1. 查 oa_notify/oa_audit 是否收到消息。
  2. 核对 templateCode 是否精确匹配当前环境配置或枚举。
  3. 未匹配模板会直接 ACK,无业务动作。
  4. 秒杀按 OA 号查活动 oa_no。
  5. 检查 status 是否是受支持值。
  6. 查 OaNotify 回调日志和 NACK。

19.8 销售/出库已完成,下游没收到

  1. 查业务表和库存事实,确认不是主业务失败。
  2. 查调用点是否执行 SyncOrderSer。
  3. 搜索 SyncOrder发送消息 日志和事件类型。
  4. 查 dgj_notify 的 routing key、消费方和死信。
  5. 对照 Builder 报文字段,检查下游是否因缺字段拒绝。
  6. 只补发消息,不重复创建销售或出库单。

20. 当前代码风险与待确认项

20.1 库存进销存报表固定查询站点 1017

InventoryReportSer::getGoodsTravelSql() 当前有效代码固定:

where station_code=1017

使用请求 JXCSID 的代码被注释。其他服务站查询可能返回错误站点数据,这是明确的当前代码风险。修复前必须回归权限、SQL 参数化和历史依赖。

20.2 支付成功重复消息返回 NACK

当前用订单状态做幂等,已处理消息再次到达会进入“状态错误或者消息重复”异常并返回 NACK。需要确认 MQ 是否有限次重试和死信;更稳妥的合同应区分“已成功处理的重复消息”和真正失败。

20.3 details 按账户类型绑定会覆盖重复类型

array_bind_key(details, payAccountTypeCode) 把同一账户类型变成一个键。如果支付中心允许同类型多行,前面的金额可能被覆盖。需确认上游合同保证类型唯一,或改成按类型汇总。

20.4 事务提交后任务异常可能导致重复投递

TaskSer::execute() 在事务提交后、try 结束前执行。它失败会返回 NACK,但主事务已提交。必须补自动化测试和明确幂等策略。

20.5 报表 SQL 是应用拼接并发送给中心接口

输入虽然经过部分校验,但具体过滤字段仍应审计参数化和转义;中心报表接口还需要权限、超时、最大行数和 SQL 白名单保护。

20.6 报表汇总可能重复拉全量

采购和库存报表为了 sum 循环请求分页,再在 PHP 汇总。大时间范围可能产生高延迟和内存压力。导出还会全量拉取,应设置业务范围、超时和导出上限。

20.7 销售同步创建类型固定为线下单

SyncOrderBuilder::buildOrderEvent() 固定 orderType=7、source=5,没有使用已定义的来源映射。需确认该同步只用于线下 DGJ 开单,避免 E站、活动、机器人来源被错误分类。

20.8 出库多货位信息被压成一个货位

Builder 遍历 qtyGrid 时只保留最后一个非零货位。下游如果需要每个货位的数量明细,现有报文无法表达。

20.9 未知 OA 模板会静默 ACK

模板码不匹配 switch 任一分支时,回调仍 ACK。应至少有未知模板日志和告警,否则配置错误难以发现。

20.10 MqEventEnums::DEST_TYPE_RELATION 不是完整注册事实

部分消费者实际注册的 routing key 没有出现在关系数组中。排查和文档不能只读取 DEST_TYPE_RELATION,还必须检查具体消费者的 registryCallback()。

21. 改动影响面

修改位置直接影响必须回归
PayCenterNotify::paycenterPayResult()采购、预订单、授信、秒杀、账户单/混合/零元/授信支付、重复、超时、回滚
PaymentModel/PaymentInfoModel 分片所有财务查询和写入32 分片、老表兼容、跨站点查询
AccountService::saveAccounts()账户余额和流水收入/支出方向、撤销、混合账户
PoOrderPayInfoModel采购支付展示和优惠单位、返利、退款、服务费
MqSer多业务生产者destination、routing key、payload、channel 关闭
*Notify 消费者跨系统回调ACK/NACK、重复、缺参数、部分成功
Report Service报表查询、导出和口径权限、站点、日期、分页、汇总、DWD 延迟
OaNotify授信、费用、活动和秒杀所有模板分支、通过/拒绝、未知模板
SyncOrderBuilderSaaS/下游订单合同各来源、赠品、挂账、多货位、撤销

22. 回归测试清单

22.1 支付

  • 普通采购单单一账户支付成功,主单、明细、账户、payinfo 和采购状态一致。
  • 混合支付金额和展示类型正确。
  • 授信主支付和授信作为混合明细都生成正确其他收入。
  • 返利、专属返利、待退款账户和服务费单位正确。
  • 零元订单只推进业务状态,不生成错误付款单。
  • 预订单每个账户生成一张其他支出并推进预订单。
  • 秒杀采购支付后秒杀订单正确变已支付。
  • 支付失败状态、异常回调、支付超时、重复成功消息行为明确。
  • 财务事务中任一写入失败全部回滚。
  • 事务提交后任务失败不会重复落账。

22.2 财务分片和账户

  • 代表性 sid 覆盖不同 sid % 32 分片。
  • 新系统账户创建后缓存立即可读。
  • 收入为正、支出账户流水为负,撤销口径正确。
  • 页面、报表和 SQL 都查询同一分片。
  • 老表兼容读取不会重复统计。

22.3 报表

  • 查询和导出权限分别生效。
  • 日期、分页、每页 1000 上限正确。
  • 当前页和汇总结果使用同一过滤条件。
  • 采购、采退、入库、销售、库存代表业务单可从业务表追到 DWD。
  • DWD 延迟期间页面有合理提示或排查依据。
  • 大数据量导出不会无限请求、超时或内存溢出。
  • 库存报表使用请求 JXCSID,不再固定站点。
  • 零数量、负数退货、优惠和服务费公式有边界测试。

22.4 MQ 和 OA

  • 每个消费者的 destination 和 routing key 与生产者一致。
  • 成功 ACK、可重试 NACK、不可处理 ACK 丢弃均有测试和日志。
  • 重复消息不会重复写业务或财务事实。
  • OA 所有模板通过和拒绝分支可执行。
  • 未知模板产生告警。
  • 秒杀 OA 能兼容多种 OA 号和结果字段,重复回调幂等。

22.5 销售同步

  • 创建、修改、关闭、结单、出库、出库撤销事件完整。
  • 订单来源和类型与真实来源一致。
  • 挂账/现金支付方式映射正确。
  • 快准物料、三方物料、赠品字段正确。
  • 多仓位/多货位出库合同满足下游需求。
  • publish 失败可补发消息,不重复业务单据。

23. 代码证据索引

结论证据文件
支付中心事件注册和完整回调application/controllers/tasks/PayCenterNotify.php
支付账户类型application/KzData/Enums/AccountEnums.php
收付款状态application/KzData/Enums/PaymentEnums.php
付款 32 分片application/models/payment/PaymentModel.php, PaymentInfoModel.php, application/config/tables.php
采购支付扩展字段application/models/orders/PoOrderPayInfoModel.php
MQ destination/routing keyapplication/KzData/Enums/MqEventEnums.php
通用 MQ 生产者application/Services/Mq/MqSer.php
订单/配送/商品/渠道消费者application/controllers/tasks/*Notify.php
OA 模板分流application/controllers/tasks/OaNotify.php
OA 结果同步application/controllers/tasks/OaResultNotify.php
秒杀 OA 状态application/Services/Activity/FlashActivitySer.php, FlashActivityEnums.php
报表接口和权限application/controllers/reports/*.php
Hologres 查询和 DWDapplication/Services/Report/*.php
报表请求校验application/Validate/Reports/*.php
销售/出库同步生产者application/Services/SyncOrder/SyncOrderSer.php
下游报文转换application/Services/SyncOrder/SyncOrderBuilder.php

24. 仍需环境确认

  1. 支付中心 payOrderNo、来源订单号和回调消息 ID 的唯一性保证。
  2. paycenter_notify 对 NACK 的重试次数、退避、死信和人工补偿方式。
  3. 付款、账户、采购状态是否始终使用同一数据库连接和事务。
  4. 生产中各支付金额字段的官方单位合同,尤其 PoOrderPayInfo。
  5. Hologres 各 DWD 表的同步频率、延迟 SLA、重跑和数据负责人。
  6. 中心报表 SQL 接口的鉴权、SQL 白名单、最大扫描量和超时。
  7. 所有 OA 模板码在各环境的实际值及未知模板告警。
  8. OA 和秒杀重复回调的消息唯一键与重试策略。
  9. dgj_notify 的真实消费者、消息保留、死信和手工补发入口。
  10. 销售同步 Service 的真实调用范围是否只包含线下 DGJ 订单。

环境确认结果应写回本文或对应第 13、18、22、23 篇专项文档,不能只保留在群聊和临时排查记录中。

请求-日志-数据变更追踪卡

多入口请求链路

场景调用方与入口请求载荷/上下文Controller/ConsumerService/Provider汇合点最终业务事实
支付回调支付中心 DEST_PAYCENTER_NOTIFYpayOrderNo、来源单号、payStatus、金额、支付方式tasks/PayCenterNotify.php支付、采购和活动 Service/Model支付单号 + 来源订单号支付主明细、业务支付关系和订单状态更新
OA 回调OA DEST_OA_NOTIFY/结果通知模板码、业务 ID、审批状态、意见OaNotify.php、OaResultNotify.php模板对应业务 Service模板码 + 业务 ID + OA 单号活动/业务审批状态推进并回传结果
业务 MQ 同步销售、采购、库存、渠道等 Servicerouting key、业务单号、业务快照MqSer 生产;各 *Notify 消费SyncOrderSer、领域 Service业务单号 + 消息业务键下游系统获得创建/变更/关闭事实
报表查询PC 报表页面/APIsid、日期、组织、过滤条件、权限controllers/reports/*.phpServices/Report/*报表口径字段和数据日期查询 Hologres/DWD,通常不写 OLTP 业务表
定时补偿调度系统批次、时间窗、游标/状态controllers/tasks/*Task.php领域补偿 Service业务主键 + task 批次将漏处理记录推进到应有状态或重新发消息

日志证据矩阵

链路段日志来源可检索锚点成功信号失败信号与下一段关联方式
支付消费PayCenterNotify::paycenterPayResultpayOrderNo、来源单号、消息 ID、payStatus=02支付/业务关系落库并 ACK非成功态、金额不符、重复、NACK支付单号查 SCM_PAYMENT* 和来源关系
OA 消费OaNotify/OaResultNotifytemplate code、business ID、OA 单号命中模板并推进业务状态未知模板、找不到业务、回调乱序模板码 + 业务 ID 查业务主表
MQ 生产/消费MqSer 与目标 *Notifydestination、routing key、业务单号、消息 ID生产成功且消费者 ACK发送失败、NACK、死信/重复同一业务键贯穿生产、消费和业务表
报表请求reports Controller/Service/数据源日志报表方法、sid、日期范围、查询 ID返回行数和数据日期明确权限拒绝、超时、数据源延迟查询条件与 DWD 最大数据日期对照
补偿任务具体 Task 方法日志task 名、批次、开始结束时间、业务 ID扫描/成功/跳过/失败数可对账任务中断、失败数增长、重复副作用批次业务 ID 回查主表和消息记录

环节数据变更台账

步骤代码位置事务读取事实写入表/缓存/MQ字段或数量变化回查证据
接收支付结果PayCenterNotify单消息本地事务payStatus、来源订单、既有支付单SCM_PAYMENT、SCM_PAYMENT_INFO、来源业务支付表首次成功 insert/累计;重复成功不得重复记账;订单状态按来源推进payOrderNo 唯一性、金额合计、来源单状态
账户/应收核销财务 Service财务事务应付/应收余额和账户余额SCM_ACCOUNT、SCM_ACCOUNT_INFO、SCM_REPAYMENT_ORDER 等余额和已核销金额按分录增减,借贷/来源总额保持平衡业务单、分录号、前后余额
OA 状态推进OaNotify -> 模板业务 Service消费事务;OA 外部系统已在边界外当前业务状态、审批结果业务主表、OA 结果 MQstatus: pending -> approved/rejected,旧/重复结果不回退OA 单号、模板码、状态更新时间
生产下游消息MqSer、SyncOrderSer、SyncOrderBuilder常在业务 commit 后已提交订单/出库/库存事实dgj_notify 等 destination本地业务事实 -> 消息快照;不直接改变本地业务状态或仅记同步标记routing key、单号、生产结果、消费 ACK
报表查询reports/* -> Services/Report/*只读,无 OLTP 写事务Hologres/DWD 数据、权限和筛选条件通常无业务表写入数据不变;仅聚合、分组、分页和口径转换SQL/查询 ID、最大数据日期、抽样单据
补偿执行tasks/*Task.php每条/每批事务由具体任务决定待支付、待同步、超时或不一致记录业务表、MQ、缓存仅把满足条件的记录推进/重发;已完成记录跳过执行前后状态、影响行数、重复运行零副作用

子模块级独立追踪

子模块追踪:pay-success 支付成功落账

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
消费DEST_PAYCENTER_NOTIFY 成功事件message ID、payOrderNo、来源单号、payStatus=02、金额application/controllers/tasks/PayCenterNotify.php::paycenterPayResult来源订单、当前支付状态、已有支付主明细/关系回调事务 insert/update SCM_PAYMENT/INFO 和来源支付关系;paid amount old -> old+n,来源状态推进message ID + payOrderNo + source billNo非 02 不按成功落账;同 payOrderNo 重复消费 0 增量
来源联动支付记录 commit 前后按来源分流payOrderNo、source type/id、业务单号application/controllers/tasks/PayCenterNotify.php -> 采购/活动/授信 Service来源当前态和是否已处理本地事务或后置边界将 order/status/locked/used old -> newpayOrderNo + 来源单 + Service 方法支付已落账、来源失败只补来源动作,不重复支付分录

子模块追踪:pay-exception 支付异常与退款回调

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
异常事件PayCenter exception eventmessage ID、payOrderNo、source bill、exception typeapplication/controllers/tasks/PayCenterNotify.php 对应 handler原支付、来源订单状态和异常是否已登记单消息事务异常/支付状态 old -> failed/exception 或 insert 异常记录event + payOrderNo + source bill + message ID未知类型告警;不能因异常消息直接回滚已确认成功支付
退款refund result eventrefund order、original payOrderNo、amount、statusapplication/controllers/tasks/PayCenterNotify.php -> Refund/Exclusive Service原成功支付、已退金额、业务退货/关闭事实退款事务 refunded old -> old+n,账户/额度按合同 old -> old+n;重复为 0original/refund pay IDs + source bill外部成功本地失败按 refund ID 补账;普通退款与专属授信分支分开核对

子模块追踪:credit-adjust 额度调整与授信回调

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
调整回调PayCenter/额度事件message ID、adjust ID、station/account、source order、amount/typeapplication/controllers/tasks/PayCenterNotify.php -> ExclusiveBaitiao/Account Service可用、冻结、已用额度和原业务流水额度事务按类型 available/frozen/used old +/- n,insert 调整流水adjust ID + source order + station + message ID同 adjust/source key 只记一次;余额不足或上下级不守恒 rollback
关闭返还订单关闭/退款联动order/pay/refund ID、release amountapplication/controllers/tasks/OrderCenterNotify.php / PayCenterNotify -> 授信 Service原占额、已返额、外部账本最终态frozen/used old -> old-n、available old -> old+n;不超过原占用original order/pay + adjust ledger ID外部本地非原子时只补差额,不能新建无原单的额度调整

子模块追踪:report-query 报表查询与离线数据

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
查询/reports/* 页面/APIrequest ID、sid/组织、日期、状态、分页、report nameapplication/controllers/reports/*.php -> application/Services/Report/* -> Provider权限、Hologres/DWD 数据和最大数据日期只读,不写 OLTP;原始明细 -> 过滤/聚合/分页结果request/query ID + report method + date/sid空/少数据先查权限、口径和数据日期,不以报表结果反改业务表
导出/对账报表导出或抽样核对export/query ID、同列表筛选、business IDsReport Service -> Export;OLTP 只读查询列表主键集合、源业务主明细DB 不变;生成文件,或比较 DWD 与 OLTP 快照export ID + query condition hash + sample billNo页面/导出不一致用同条件比主键集合;同步延迟交 ETL 重跑,不重做业务单

子模块追踪:oa-callback OA 模板分流与结果回调

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
OA 通知DEST_OA_NOTIFYmessage ID、template code、business ID、OA form、resultapplication/controllers/tasks/OaNotify.php -> 模板对应 Service模板映射、业务当前审批态、回调是否已处理单消息事务 status pending -> approved/rejected,结果/意见写入template + business ID + OA form + message ID未知模板/找不到业务告警;旧回调不得回退终态
结果回传本地业务结果发 OA/消费结果队列business ID、OA form、result eventapplication/controllers/tasks/OaResultNotify.php / application/Services/Mq/MqSer.php本地已提交审批结果本地 DB 通常不写或同步标记 old -> sent;MQ/外部为异步边界business/OA ID + routing key + message ID发送失败只补 OA 结果消息,不重复执行业务审批

子模块追踪:order-sync 销售和出库下游同步

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
构建发送销售/出库/撤销 commit 后sale/invoice billNo、source type、event/versionapplication/Services/SyncOrder/SyncOrderSer.php -> SyncOrderBuilder.php -> MqSer已提交主明细、状态、数量、金额和来源本地核心表 DB 不变;构造 dgj_notify 消息,派生状态无 -> 待消费billNo + routing key + message ID + payload version发送失败按业务键补发;不重做销售/出库事务
下游确认App/SAAS 消费或回调message ID、business bill、downstream status下游消费者;本地回调在 application/controllers/tasks/*Notify.php下游当前态和消息版本下游 old -> new,本地仅按合同写同步状态两端用 billNo/source order 关联ACK 丢失重复消息零副作用;下游已成不因本地重试再建单

子模块追踪:mq-compensation MQ 消费与定时补偿

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
消费application/controllers/tasks/*Notify.phpdestination、event、message ID、稳定业务键Consumer -> 领域 Service/Provider消息版本、当前业务状态、幂等事实单消息事务 status/qty/amount old -> new;commit 后 ACKdestination + event + business key + message ID业务异常 NACK/告警;已完成重复消息 ACK 且 DB 不变
补偿任务application/controllers/tasks/*Task.php CLItask、batch、time window、cursor、business IDTask -> 领域幂等方法 / MqSer待处理状态和支付/订单/外部最终事实每条事务仅把差异 old -> expected 或重发 MQ;已完成跳过task/batch + business IDs + scan/success/skip/fail counts小批、可续跑;补偿前取 before 快照,重跑必须 0 副作用