本手册覆盖 DGJ2.0 秒杀/折扣商品专区从 OPS 创建、商品导入、冲突校验、服务站范围、OA 审批,到站管家列表、购物车、确认页、下单锁量、采购单、支付回调、关闭释放和定时补偿的完整链路。

适用于需求交接、前后端联调、预发数据准备、线上问题定位和补偿评审。本文以当前代码和已确认产品规则为依据;环境中的 OA、库存中心、支付中心、MQ 和定时调度配置仍需上线前实测确认。

1. 业务目标

  • 让运营能配置单品/套包活动、价格、效期、仓库和服务站范围。
  • 用 OA 审批保证活动上线前经过审核,审批结果可幂等回写。
  • 服务站只看到当前时间、范围、价格、库存都有效的商品。
  • 单品通过购物车结算,套包直接购买。
  • 下单时原子锁定活动数量,支付后把锁定量转为已用量。
  • 秒杀订单通过采购订单 30-Cxx-77 进入原采购履约链。
  • 取消、超时、采购关闭和行关闭时只释放应释放的差量。
  • 定时任务只补偿可证明的缺口,不重复生成采购单、不重复释放数量。

2. 业务边界和参与系统

flowchart LR
    OPS["OPS运营"] --> ACT["DGJ活动域"]
    ACT --> OA["OA审批"]
    ACT --> ST["站管家/移动商城"]
    ST --> STOCK["库存中心/实时库存"]
    ST --> ORDER["秒杀订单"]
    ORDER --> PO["DGJ采购单"]
    PO --> ODC["订单中心"]
    PO --> PAY["支付中心"]
    PO --> DIS["配送/入库"]
    PAY --> ORDER
    ODC --> ORDER
    ORDER --> TASK["超时/补偿任务"]
系统/模块负责不负责
OPS活动配置、商品、范围、提交审批、结束服务站实时库存最终值
OA审批流和结果商品库存、订单支付
活动域可见性、价格规则、数量账采购履约明细状态
库存中心指定仓/服务站仓可用量活动 locked_qty/used_qty
秒杀订单用户购买快照和数量锁定最终采购出入库
采购域待支付、审核、配送、入库、关闭活动配置冲突
支付中心支付结果和退款回调活动商品可见性
补偿任务修复已知状态缺口无条件覆盖人工状态

3. 适用现象和首查方向

现象首查常见原因
OPS 保存失败活动/商品参数校验第三方商品、效期缺失、套包数量/仓库错误
导入成功但活动没商品导入与保存边界导入只解析,前端未带完整 goodsList 保存
提交审批冲突跨活动冲突维度时间重叠、单品效期重叠、套包同仓重叠
OA 通过后仍审批中OA 号和模板回调summaryId/oa_no 不匹配、回调未消费
OA 报字段不存在OA payload错把审批人工号放进表单字段
单品所有站都看不到活动/商品/价格/库存未启用、无价、库存为 0、商品失效
套包指定站看不到白名单未配置或保存时被全量替换
列表有库存,加购失败库存明细去重和实时校验列表重复累加、仓库/效期口径不同
加购成功,确认页失效二次校验活动跨时点结束、价格/库存变化
提交订单提示限购单品/套包规则套包已购 1 次、锁量未释放
下单后 locked_qty 不对数量账重复提交、事务部分成功、明细关联错误
支付成功仍待支付支付回调和采购关系回调未到、PO 来源关联缺失
已支付但 used_qty 未增markPaidByPoOrder重复/漏回调、秒杀订单未找到
超时后仍占量expireWaitPayOrders任务未调度、采购关闭失败、状态不满足
采购关闭后不能再买关闭释放used_qty/locked_qty 未差量释放

4. 入口与代码地图

4.1 OPS 入口

能力Controller 方法Service
活动列表listFlashActivityFlashActivitySer
活动详情detailFlashActivity同上
商品列表listFlashActivityGoods同上
保存活动saveFlashActivity同上
单行失效invalidateFlashActivityGoods同上
导入商品importFlashActivityGoods同上
下载模板downloadFlashActivityGoodsTemplate同上
导出活动/商品exportFlashActivity*同上
复制活动copyFlashActivity同上
保存黑白名单saveFlashActivityStationScope同上
查询/删除名单get/deleteFlashActivityStationScope同上
提前结束endFlashActivity同上
转草稿convertFlashActivityToDraft同上
提交审批submitFlashActivity同上

文件:application/controllers/inner/activity/FlashActivity.php。

4.2 站管家/移动商城入口

PC:application/controllers/scm/FlashSale.php。

Inner 移动端:application/controllers/inner/moveMall/FlashSale.php。

两套入口调用同一 FlashSaleSer:

方法用途
checkStationAccess是否显示折扣商品专区入口
goodsList/goodsDetail商品列表/详情
packageGoodsList套包明细
goodsFilters/cartFilters筛选项
getCartCount购物车数量
addCart/updateCart/cartList单品购物车
orderPreview下单前快照校验
submitOrder创建订单、锁量和采购单
orderDetail秒杀订单详情
cancelOrder主动取消和释放

4.3 回调和任务

入口文件作用
OA 消息tasks/OaNotify.php模板 callback_20260526 分流
支付中心tasks/PayCenterNotify.php支付成功后标记秒杀已支付
秒杀任务tasks/FlashSaleTask.php状态刷新、超时和补偿
采购关闭FlashSaleSer::releaseByPoOrder/releaseByPoCloseItems释放活动数量

5. 核心表和关联键

表作用主要键
t_flash_activity活动主表id、oa_no、时间、类型、状态
t_flash_activity_goods活动商品规则id、activity_id、inv_id/sku_id
t_flash_activity_station_scope服务站黑白名单activity_id + sid + type
t_flash_activity_province_scope省区自动加入规则activity_id + depart_code + operate_province
t_flash_cart单品购物车sid + activity_goods_id
t_flash_order秒杀订单主表id、bill_no、sid、状态
t_flash_order_detail秒杀订单快照order_id、activity_goods_id
t_flash_activity_log活动操作日志activity_id、动作、操作者
t_scm_po_order采购主单srcOrderType=13 + srcOrderId/srcOrderNo
t_scm_po_order_info_{sid%32}采购明细秒杀订单明细来源关系
t_scm_po_order_payinfo采购支付关系billNo/orderId
Payment 相关 32 分片表支付事实采购单和支付单关联
erDiagram
    FLASH_ACTIVITY ||--o{ FLASH_ACTIVITY_GOODS : contains
    FLASH_ACTIVITY ||--o{ FLASH_ACTIVITY_STATION_SCOPE : scopes
    FLASH_ACTIVITY ||--o{ FLASH_ACTIVITY_PROVINCE_SCOPE : auto_scope
    FLASH_ACTIVITY_GOODS ||--o{ FLASH_CART : cart
    FLASH_ORDER ||--o{ FLASH_ORDER_DETAIL : contains
    FLASH_ACTIVITY_GOODS ||--o{ FLASH_ORDER_DETAIL : snapshots
    FLASH_ORDER ||--o{ SCM_PO_ORDER : creates
    SCM_PO_ORDER ||--o{ SCM_PO_ORDER_INFO : contains

5.1 关联采购的稳定条件

po.orderType = 30-Cxx-77
po.srcOrderType = 13
po.srcOrderId = flash_order.id
po.srcOrderNo = flash_order.bill_no
po.sid = flash_order.sid

6. 状态字典

6.1 活动类型和库存范围

字段值含义
activity_type1单品售卖
activity_type2套包售卖
stock_scope1服务站对应仓
stock_scope2指定仓
stock_scope3全局预留

6.2 OA 申请状态

值含义
0草稿
1审批中
2审批通过
3审批驳回

6.3 设置和页面状态

状态维度值含义
设置状态0草稿
设置状态1启用
设置状态2提前结束
页面状态1未开始
页面状态2进行中
页面状态3已结束

页面状态由设置状态和当前时间推导,不能把“审批通过”“启用”“进行中”当作同一个字段。

6.4 活动商品状态

值含义
0待开始
1进行中
2已结束
3已失效

6.5 订单状态

值含义数量账
0已创建事务中间态,需继续确认
1待支付占用 locked_qty
2已支付占用转入 used_qty
3已取消释放待支付锁量
4已关闭按采购关闭事实释放
stateDiagram-v2
    [*] --> 已创建
    已创建 --> 待支付: 创建采购待支付单
    待支付 --> 已支付: 支付成功回调
    待支付 --> 已取消: 主动取消
    待支付 --> 已关闭: 超时/采购关闭
    已支付 --> 已关闭: 采购关闭或明细关闭
    已支付 --> [*]: 正常履约
    已取消 --> [*]
    已关闭 --> [*]

7. OPS 保存规则

7.1 完整快照语义

saveFlashActivity 是活动和商品的完整快照保存:

  • 前端每次传完整活动信息。
  • goodsList 存在时表示完整商品集合,不是增量。
  • 新增、编辑、删除未正式生效商品都通过该快照完成。
  • 导入接口只解析/补充商品行,最终仍需调用保存接口落库。
  • 人工让已生效商品失效必须调用独立 invalidateFlashActivityGoods。

7.2 脱敏保存请求

{
  "id": 1001,
  "name": "夏季保养折扣专区",
  "activity_type": 1,
  "stock_scope": 1,
  "start_time": "2026-07-20 00:00:00",
  "end_time": "2026-07-31 23:59:59",
  "goodsList": [
    {
      "goods_id": 30001,
      "price_mode": 1,
      "fixed_price": "88.00",
      "date_calc_mode": 2,
      "date_from": 0,
      "date_to": 90
    }
  ]
}

站点、用户和权限来自内部网关上下文,不应把鉴权信息写进文档示例。

7.3 商品档案校验

  • goods_id 来自复用商品搜索接口。
  • 后端按 goods_id 反查并保存 inv_id/sku_id 快照。
  • sku_id 为空表示第三方商品,禁止加入秒杀。
  • 新增/导入还要校验限售档案。
  • 保存只拦截真正新增行;活动提交前对全部商品再次兜底。

7.4 单品和套包数量

类型qty 规则含义
单品后端统一存 0不限制活动总数量,购买看实时库存
套包必须大于 0套包活动可售总包数

单品的 0 是存储哨兵,不是“售罄”。详情、列表导出和模板回显应展示为空。

7.5 套包指定仓

  • stock_scope = 2 时每个套包商品行必须有 wms_location_no。
  • wms_location_name 是保存时仓库名称快照,详情优先读快照。
  • 历史名称为空可一次性回填,不能覆盖已有快照。
  • 下单创建秒杀采购单时 header.multiWarehouseFlag=true。
  • 该标记只能在 srcOrderType=13 且活动类型=套包、库存范围=指定仓时透传。

8. 效期规则

8.1 需要效期的物料属性

wmsAttributeCode 为 2/3/19/20 时:

  • date_calc_mode 必须是按月或按天。
  • 倒推起止值必须提供,允许 0。
  • 按月 0 表示当月,日期通常从月初计算。

普通物料允许不配置,也允许显式配置,后端应保留配置。

8.2 不保存绝对生产日期

活动商品表保存倒推规则,不保存 prod_date_start/prod_date_end;服务站列表和库存请求在运行时根据当前日期计算区间。

flowchart LR
    CFG["date_calc_mode/from/to"] --> NOW["当前业务日期"]
    NOW --> RANGE["计算生产日期区间"]
    RANGE --> STOCK["库存中心查询"]
    RANGE --> CONFLICT["活动冲突比较"]

9. 跨活动冲突规则

只有活动时间重叠的当前/未来已审批活动进入冲突比较。

当前类型对方类型冲突维度结论
单品套包不比较允许共存
单品单品物料 + 效期区间重复或交叉即冲突
套包套包物料 + 效期区间 + 仓库同仓冲突,不同仓可共存

补充规则:

  • package_group_no 不是冲突维度。
  • 单品仓库不是冲突维度。
  • 保存、导入和提交审批必须复用同一比较器。
  • 冲突是硬失败,不支持 ignore_conflict 或二次确认绕过。
  • 失败提交不得修改当前活动状态,也不得自动结束旧活动商品。
flowchart TD
    A["提交活动"] --> T{"活动时间重叠?"}
    T -->|否| PASS["无冲突"]
    T -->|是| TYPE{"活动类型相同?"}
    TYPE -->|否| PASS
    TYPE -->|单品| S{"物料+效期重复/交叉?"}
    TYPE -->|套包| P{"物料+效期+仓库重复/交叉?"}
    S -->|是| FAIL["硬失败,can_submit=0"]
    P -->|同仓是| FAIL
    S -->|否| PASS
    P -->|不同仓/否| PASS

10. 服务站范围

10.1 单品黑名单

  • 可配置多个服务站。
  • 未配置时默认所有符合其他条件的服务站可见。
  • 黑名单中的服务站不可见。
  • 支持按 depart_code + operate_province 对新站自动加入黑名单。

10.2 套包白名单

  • 未配置白名单时不展示。
  • 只有白名单服务站可见。
  • 当前最多一个服务站。
  • 不使用省区自动加入能力。

10.3 保存是全量替换

saveFlashActivityStationScope.stations 表示弹窗最终名单:

  • 未出现的旧记录软删。
  • 空数组表示清空。
  • 历史记录可恢复。
  • 套包最多一个站只检查本次最终名单,不与旧名单取并集。
flowchart TD
    A["活动类型"] --> B{"单品?"}
    B -->|是| BL["读取黑名单"]
    BL --> V1{"当前sid在黑名单?"}
    V1 -->|是| HIDE["不可见"]
    V1 -->|否| SHOW["继续其他校验"]
    B -->|否| WL["读取套包白名单"]
    WL --> V2{"当前sid是唯一白名单站?"}
    V2 -->|是| SHOW
    V2 -->|否| HIDE

11. OA 提交和回调

11.1 提交前置条件

  • 活动和有效商品存在。
  • 商品规则、价格、效期、限售、仓库、套包数量通过。
  • 跨活动冲突为 0。
  • 套包白名单和价格兜底校验通过。
  • 直接发布 is_oa=0 也要有 oa_no,最长 64。

11.2 OA 模板

FlashActivityEnums::OA_TEMPLATE_CODE = callback_20260526

固定审批人属于 OA 生产流程节点配置,不是 DGJ 表单字段。公开文档不记录具体员工编号;不要在活动 OA payload 的 data 中添加“审批人/审批人工号”,否则模板会报字段不存在。

11.3 回调关联

OA 回调由 OaNotify 按模板分流到 FlashActivitySer::callback20260526(),通常用回调 summaryId 匹配活动 oa_no。

sequenceDiagram
    participant O as OPS
    participant A as FlashActivitySer
    participant OA as OA
    participant Q as OA MQ
    O->>A: submitFlashActivity
    A->>A: 全量校验/冲突检查
    A->>OA: 提交 callback_20260526
    OA-->>A: oa_no/summary
    A->>A: apply_status=1
    OA->>Q: 审批结果
    Q->>A: callback20260526
    A->>A: 幂等更新通过/驳回

11.4 OA 排查

  1. 查活动 oa_no/apply_status/enable_status。
  2. 查提交请求和 OA 返回。
  3. 查 template code 是否正确。
  4. 查消息是否到 OaNotify。
  5. 查 summaryId 是否匹配。
  6. 查重复回调是否幂等。
  7. 查回调异常是否被 ACK 丢弃。

12. 服务站商品可见性

商品可见至少满足:

活动未删除
apply_status = 审批通过
enable_status = 启用
start_time <= now <= end_time
活动商品状态可售且未删除
服务站命中黑/白名单规则
价格可解析且大于0
库存/活动可售量大于0
商品档案仍允许销售
flowchart TD
    A["goodsList"] --> TIME["审批/启用/时间"]
    TIME --> SCOPE["服务站范围"]
    SCOPE --> GOODS["商品状态/档案"]
    GOODS --> PRICE["结算价格"]
    PRICE --> STOCK["库存/活动剩余量"]
    STOCK --> FORMAT["单品行或套包卡片"]

12.1 操作主键

前端所有商品动作使用 activity_goods_id 或 activity_goods_ids。不能只传 inv_id,因为同一物料可能因活动、效期、仓库或价格规则形成多条活动商品行。

13. 价格链

13.1 一口价

settlement_price = fixed_price

不得调用普通采购价或调整后结算价覆盖。

13.2 固定折扣

优先:当前服务站普通采购可买商品价 findAvailableItemList
兜底:确认活动选品限制 -> 001货主调整后结算价 findItemGlobalPrice
最终:base_price * discount_rate

普通采购不可买或价格为 0 时,必须先按当前 sid + inv_id/sku_id 精确确认物料满足活动选品核心限制,才可走 001 兜底。

13.3 无价格处理

  • 单品不在站管家列表展示。
  • 套包保存和提交时对全部白名单站校验并报错。
  • 购物车、确认页、下单再次拒绝。
  • 不能静默生成 0 元采购单。
flowchart TD
    A["价格模式"] --> F{"一口价?"}
    F -->|是| FP["fixed_price"]
    F -->|否| NORMAL["普通采购可买价"]
    NORMAL --> OK{"价格>0?"}
    OK -->|是| DISC["乘固定折扣"]
    OK -->|否| ELIGIBLE["精确校验活动选品限制"]
    ELIGIBLE -->|通过| GLOBAL["001调整后结算价"]
    ELIGIBLE -->|失败| REJECT["无价/不可售"]
    GLOBAL --> DISC

14. 库存计算

14.1 单品

单品 qty=0 不限制活动数量:

单品可售量 = 满足仓库/效期规则的实时库存可用量

仍需扣除库存中心定义的占用/不可用明细;活动 locked_qty/used_qty 用于订单生命周期审计,但不能把 qty=0 - locked - used 当作可售量。

14.2 套包

活动剩余包数 = qty - locked_qty - used_qty
仓库可组成包数 = min(每个子件可用量 / 单包用量)
最终可购包数 = min(活动剩余包数, 仓库可组成包数)

套包正式购买次数限制:

PACKAGE_PURCHASE_LIMIT = 1

14.3 同 SKU 多效期去重

库存中心批量查询同 SKU 多生产日期范围时可能返回相同明细行。按 skuCode + companyCode 归桶前必须对完全相同明细去重,否则列表会重复累加,而加购使用另一口径后提示库存不足。

flowchart LR
    REQ["SKU+多个效期请求"] --> RESP["库存中心明细"]
    RESP --> DEDUP["相同明细去重"]
    DEDUP --> BUCKET["按SKU+货主+仓库归桶"]
    BUCKET --> SUM["汇总allowQty"]
    SUM --> LIST["列表"]
    SUM --> CART["加购"]
    SUM --> ORDER["下单"]

15. 购物车

15.1 规则

  • 只有单品进入购物车;套包直接购买。
  • 购物车用 activity_goods_id 定位规则。
  • updateCart 统一处理数量、勾选、删除和批量删除。
  • 不新增单独 validateCart;预览和提交都重新校验。
  • 今日新增默认勾选,历史商品默认不勾选。
  • 单品可跨多个一口价活动一起结算。
  • 跨活动订单主表 activity_id=0,明细保存真实活动 ID。

15.2 加购请求

{
  "activity_goods_id": 50001,
  "qty": 2
}

sid 从登录服务站上下文注入,不由前端传。

15.3 加购校验

  1. 活动当前可售。
  2. 商品行可售且未人工失效。
  3. 当前站不在黑名单。
  4. 价格有效。
  5. 实时库存和效期库存足够。
  6. 数量大于 0 且符合限购。
  7. 同活动商品购物车记录幂等更新。

16. 订单预览

orderPreview 不是只读回显,它是提交前的完整重算:

  • 重新读取活动和商品。
  • 重新验证服务站范围。
  • 重新取结算价。
  • 重新查询库存。
  • 过滤失效购物车行。
  • 计算收货仓、供应商、总数量和总金额。
  • 套包按 package_group_no 展开全部子件。
sequenceDiagram
    participant U as 站管家
    participant S as FlashSaleSer
    participant A as 活动库
    participant P as 价格服务
    participant I as 库存中心
    U->>S: orderPreview(ids/立即购买)
    S->>A: 查询活动商品快照
    S->>S: 可见性/限购校验
    S->>P: 解析当前价格
    S->>I: 查询仓库效期库存
    S-->>U: 当前可提交快照

17. 提交订单和原子锁量

17.1 脱敏请求

单品购物车:

{
  "source": 2,
  "activity_goods_ids": [50001, 50002],
  "payment_type": 1
}

套包立即购买:

{
  "source": 1,
  "activity_goods_id": 60001,
  "qty": 1,
  "payment_type": 1
}

17.2 提交流程

sequenceDiagram
    participant U as 站管家
    participant F as FlashSaleSer
    participant AG as activity_goods
    participant FO as flash_order
    participant PO as 采购域
    U->>F: submitOrder
    F->>F: 重做预览全部校验
    F->>AG: 条件更新 locked_qty
    AG-->>F: 影响行数必须符合预期
    F->>FO: 写订单主表/明细快照
    F->>PO: 创建30-Cxx-77采购单
    PO-->>F: 返回采购单号/ID
    F->>FO: 订单进入待支付
    F-->>U: 秒杀单号和采购单关系

17.3 锁量原则

  • 锁量更新必须带剩余量条件,不能先查后无条件加。
  • 每条订单明细保留 activity_goods_id/activity_id/qty/price/warehouse 快照。
  • 任一商品锁量失败,整单应回滚已锁商品。
  • 客户端超时重试要按秒杀订单业务键防重复。
  • 采购单创建失败必须释放本次锁量或整体回滚。

17.4 多供应商/多采购单

一张秒杀订单可能按货主/供应商拆成多张采购单。支付和关闭补偿不能假设一对一,需按所有关联采购单判断整体状态。

18. 转采购单

18.1 固定来源

字段值
orderType30-Cxx-77
srcOrderType13
srcOrderId秒杀订单 ID
srcOrderNo秒杀订单号
paymentType在线支付为 1

前端展示文案可叫“折扣订单”,内部类型编码和来源关系不能改。

18.2 仓库透传

  • 单品不传指定仓。
  • 套包指定仓按每行 wms_location_no 传库存/采购上下文。
  • 多仓套包设置 multiWarehouseFlag=true。
  • 创建采购单解析不到普通货主,但活动商品已有有效价格且满足选品限制时,货主可按 001 兜底。

18.3 采购排查 SQL

select id, sid, billNo, billStatus, orderType, srcOrderType,
       srcOrderId, srcOrderNo, paymentType, amount, totalQty,
       createTime, modifyTime
from t_scm_po_order
where sid = :sid
  and orderType = '30-Cxx-77'
  and srcOrderType = 13
  and (srcOrderId = :flash_order_id or srcOrderNo = :flash_bill_no);

采购明细按 sid % 32 查 t_scm_po_order_info_{suffix}。

19. 支付链

19.1 支付约束

  • 不支持授信支付。
  • 支持待退款账户和现金类在线支付方式,具体可用项以支付接口返回为准。
  • 支付入口复用采购 getPayInfoNew/noPagePay。
  • 支付中心成功回调要求 payStatus = '02'。

19.2 首次成功回调

PayCenterNotify 完成采购支付落账后,对秒杀来源采购单调用:

FlashSaleSer::markPaidByPoOrder(poOrderInfo, payTime)

数量账变化:

locked_qty -= order_detail.qty
used_qty += order_detail.qty
flash_order.status: 1 -> 2

19.3 幂等要求

  • 秒杀订单已支付时重复回调不得再次转量。
  • 活动商品更新需保证 locked_qty >= qty。
  • 支付关系按采购单和支付业务号唯一。
  • 多张采购单时避免第一张成功就错误标记整张秒杀订单全部支付。
sequenceDiagram
    participant PAY as 支付中心
    participant N as PayCenterNotify
    participant PO as 采购单
    participant F as FlashSaleSer
    participant G as 活动商品
    PAY->>N: payStatus=02
    N->>PO: 支付落账/推进状态
    N->>F: markPaidByPoOrder
    F->>F: 锁秒杀订单并检查幂等
    F->>G: locked减少 used增加
    F->>F: 订单状态=已支付

20. 数量账

20.1 三个核心量

字段含义
qty套包活动总包数;单品固定 0 哨兵
locked_qty待支付订单占用
used_qty已支付使用量

20.2 派生量

ordered_qty = locked_qty + used_qty
套包 available_qty = max(0, qty - locked_qty - used_qty)
单品 available_qty = 满足仓库/效期的实时库存

20.3 生命周期变化

动作locked_qtyused_qty
提交待支付订单+q不变
支付成功-q+q
待支付取消/超时-q不变
已支付采购关闭不变按关闭量 -q
部分行关闭按原订单状态释放对应字段差量释放
flowchart LR
    FREE["可售"] -->|"提交 +q"| LOCK["locked_qty"]
    LOCK -->|"支付 -q/+q"| USED["used_qty"]
    LOCK -->|"取消/超时 -q"| FREE
    USED -->|"采购关闭 -q"| FREE

21. 主动取消、超时和关闭

21.1 主动取消

仅待支付订单可直接取消:

  1. 锁秒杀订单。
  2. 检查状态仍为 1。
  3. 关闭/取消关联采购待支付单。
  4. 按订单明细减少 locked_qty。
  5. 秒杀订单改为 3。
  6. 购物车是否恢复由产品交互决定,不自动假设。

21.2 待支付超时

expireWaitPayOrders(limit) 扫描过期状态 1 订单。优先关闭关联采购单;没有有效采购关系时直接释放锁量。必须防止支付回调和超时任务并发。

21.3 采购关闭

  • 整单关闭调用 releaseByPoOrder()。
  • 行级关闭调用 releaseByPoCloseItems()。
  • 待支付来源释放 locked_qty。
  • 已支付来源释放 used_qty。
  • 部分关闭只释放新增关闭差量,不能重复释放历史已关闭量。
flowchart TD
    C["采购关闭事件"] --> FIND["按srcOrderType=13找秒杀订单"]
    FIND --> STATUS{"秒杀订单状态"}
    STATUS -->|待支付| L["释放locked_qty"]
    STATUS -->|已支付| U["释放used_qty"]
    L --> DELTA["按整单/行关闭差量"]
    U --> DELTA
    DELTA --> CLOSE["必要时订单状态=已关闭"]

22. 补偿任务地图

命令Service处理
expireWaitPayOrdersFlashSaleSer关闭过期待支付并释放
refreshGoodsStatusFlashActivitySer按时间刷新商品状态
refreshInvalidCartsFlashSaleSer失效不可售购物车
compensatePaidOrdersFlashSaleSer采购已支付但秒杀未标记支付
compensateClosedOrdersFlashSaleSer采购已关闭但秒杀未释放
runCompensateController 汇总顺序执行以上任务

22.1 CLI 示例

php index.php tasks/FlashSaleTask/refreshGoodsStatus 500
php index.php tasks/FlashSaleTask/refreshInvalidCarts 500
php index.php tasks/FlashSaleTask/expireWaitPayOrders 100
php index.php tasks/FlashSaleTask/compensatePaidOrders 100
php index.php tasks/FlashSaleTask/compensateClosedOrders 100
php index.php tasks/FlashSaleTask/runCompensate 100

22.2 补偿原则

  • 只扫描明确状态集合和有限 limit。
  • 每单加数据库锁或条件更新。
  • 以采购/支付真实事实为依据。
  • 先查是否已经转量/释放。
  • 记录处理、跳过、失败数量。
  • 可重复运行,第二次结果应主要为跳过/0 变更。

23. 购物车失效

购物车在以下情况应失效:

  • 活动结束或提前结束。
  • 活动/商品被删除或人工失效。
  • 活动未审批通过或不再启用。
  • 当前站点不再可见。
  • 价格无法解析。
  • 商品不再满足销售条件。

库存短时不足是否永久失效要遵循当前代码;通常预览/提交实时提示,不应把可恢复库存不足等同于永久删除购物车。

24. 导入、导出和模板

24.1 导入边界

  • 模板第一列是“物料ID”。
  • 导入按物料 ID 反查档案并补 inv_id/sku_id。
  • 第三方物料报错。
  • 运行中活动不允许导入。
  • 多行错误一起返回,限售错误带物料编码。
  • 导入结果回填页面,最终仍由 saveFlashActivity 保存完整快照。

24.2 单品数量显示

单品数据库 qty=0,但以下输出应为空:

  • 活动详情。
  • 活动商品导出。
  • 活动列表导出行。
  • 导入后回显。

避免用户把导出的 0 再导入时理解成显式促销数量。

24.3 仓库名称

导出/详情优先读 wms_location_name 快照,不要每次为显示调用 OPS 仓库列表接口。

25. 常用只读 SQL

25.1 活动全景

select id, name, activity_type, stock_scope,
       apply_status, enable_status, activity_status,
       oa_no, start_time, end_time, total_qty, total_amount,
       create_time, modify_time, is_deleted
from t_flash_activity
where id = :activity_id;

select id, activity_id, package_group_no, inv_id, sku_id,
       qty, price_mode, fixed_price, discount_rate,
       date_calc_mode, date_from, date_to,
       wms_location_no, wms_location_name,
       goods_status, locked_qty, used_qty, ever_effective, is_deleted
from t_flash_activity_goods
where activity_id = :activity_id
order by package_group_no, id;

25.2 服务站范围

select activity_id, sid, type, is_deleted, create_time, modify_time
from t_flash_activity_station_scope
where activity_id = :activity_id
order by type, sid;

select activity_id, depart_code, operate_province, is_deleted
from t_flash_activity_province_scope
where activity_id = :activity_id;

25.3 购物车和订单

select *
from t_flash_cart
where sid = :sid and activity_goods_id in (:activity_goods_ids)
order by modify_time desc;

select id, bill_no, sid, activity_id, source, status,
       total_qty, total_amount, expire_time, pay_time,
       create_time, modify_time
from t_flash_order
where sid = :sid and (id = :order_id or bill_no = :flash_bill_no);

select order_id, bill_no, sid, activity_id, activity_goods_id,
       package_group_no, inv_id, sku_id, qty, price, amount,
       wms_location_no
from t_flash_order_detail
where order_id = :order_id
order by id;

25.4 数量异常候选

select id, activity_id, inv_id, sku_id, qty, locked_qty, used_qty,
       qty - locked_qty - used_qty as package_remaining
from t_flash_activity_goods
where is_deleted = 0
  and (locked_qty < 0 or used_qty < 0
       or (qty > 0 and locked_qty + used_qty > qty));

26. 按现象排查 SOP

26.1 OA 通过但活动不展示

  1. 查 apply_status=2。
  2. 查 enable_status=1。
  3. 查当前时间在窗口内。
  4. 查商品状态和人工失效。
  5. 查服务站黑/白名单。
  6. 查价格是否有效。
  7. 查库存和效期范围。
  8. 查列表筛选条件是否把商品过滤。

26.2 列表有库存但加购失败

  1. 固定 activity_goods_id/sid。
  2. 查列表返回的仓库、效期、库存明细。
  3. 查是否同 SKU 多效期重复累加。
  4. 用加购相同参数重查库存。
  5. 查价格是否在两次请求间变化。
  6. 查活动/商品是否跨时间边界。
  7. 查单品限购或已有购物车数量。

26.3 提交订单后锁量异常

  1. 查秒杀订单和明细是否唯一。
  2. 查所有关联采购单。
  3. 按明细汇总应锁数量。
  4. 查活动商品当前 locked/used。
  5. 查提交日志是否重试。
  6. 查事务是否回滚而条件更新已提交。
  7. 查取消/补偿是否已反向一次。

26.4 支付成功仍待支付

  1. 查支付中心回调 payStatus='02'。
  2. 查采购单是否秒杀来源 13。
  3. 查 Payment/PoOrderPayInfo 落账。
  4. 查 markPaidByPoOrder 日志。
  5. 查秒杀订单是否按 srcOrderId/srcOrderNo 找到。
  6. 查锁量是否足够转 used。
  7. 安全运行 compensatePaidOrders 单号候选验证。

26.5 超时仍占量

  1. 查订单状态和 expire_time。
  2. 查任务调度和最近执行结果。
  3. 查关联采购是否仍待支付或已关闭。
  4. 查支付是否恰好并发成功。
  5. 查 locked_qty 是否已释放。
  6. 再运行补偿前锁订单并复核支付事实。

26.6 采购关闭但套包不能再买

  1. 查采购整单/行关闭数量。
  2. 查秒杀订单支付状态。
  3. 决定应释放 locked 还是 used。
  4. 查此前 closed_qty 是否已处理。
  5. 查套包 PACKAGE_PURCHASE_LIMIT=1 的已购判断是否仍把关闭单计入。
  6. 运行关闭补偿并验证第二次幂等。

27. 故障树

flowchart TD
    A["秒杀交易异常"] --> B{"活动可见?"}
    B -->|否| B1["审批/启用/时间/范围/价格/库存"]
    B -->|是| C{"加购/预览通过?"}
    C -->|否| C1["库存效期/价格/限购二次校验"]
    C -->|是| D{"秒杀订单创建?"}
    D -->|否| D1["锁量事务/参数"]
    D -->|是| E{"采购单创建?"}
    E -->|否| E1["采购提交/货主/多仓标记"]
    E -->|是| F{"支付成功?"}
    F -->|否| F1["支付或超时释放"]
    F -->|是| G{"locked已转used?"}
    G -->|否| G1["支付回调/paid补偿"]
    G -->|是| H{"关闭释放正确?"}
    H -->|否| H1["整单/行关闭差量补偿"]

28. 补偿前安全门槛

  • 活动商品 ID、秒杀订单 ID、采购单 ID 全部固定。
  • 证明支付中心最终状态。
  • 证明采购单最终状态和关闭数量。
  • 证明当前 locked_qty/used_qty 与订单明细差值。
  • 确认没有并发支付、关闭或超时任务。
  • 使用条件更新,影响行数必须符合预期。
  • 保存前后快照和操作日志。
  • 首次补偿后再次执行应无变化。

29. 回归测试矩阵

29.1 OPS

  • [ ] 单品/套包新增、编辑、复制。
  • [ ] 完整 goodsList 删除未生效行。
  • [ ] 已生效行只能独立失效。
  • [ ] 第三方商品、限售商品拦截。
  • [ ] 单品 qty 空保存为 0、导出为空。
  • [ ] 套包 qty 必填且大于 0。
  • [ ] 指定仓编码和名称快照。
  • [ ] 导入多行错误聚合。

29.2 冲突和 OA

  • [ ] 单品与套包相同物料允许。
  • [ ] 两单品效期重叠硬失败。
  • [ ] 两套包同仓效期重叠失败、不同仓允许。
  • [ ] 冲突失败不改状态。
  • [ ] OA 通过、驳回、重复回调。
  • [ ] OA payload 不含不存在的审批人字段。

29.3 服务站范围

  • [ ] 单品无黑名单默认可见。
  • [ ] 单品黑名单不可见。
  • [ ] 省区新站自动加入且战区维度正确。
  • [ ] 套包无白名单不可见。
  • [ ] 套包唯一白名单可见。
  • [ ] 全量替换和空数组清空。

29.4 价格库存

  • [ ] 一口价不走普通采购价。
  • [ ] 固定折扣普通采购价和 001 兜底。
  • [ ] 无价单品隐藏、套包保存/提交失败。
  • [ ] 服务站仓、指定仓、全局预留。
  • [ ] 同 SKU 多效期库存明细去重。
  • [ ] 单品 qty=0 仍按实时库存购买。
  • [ ] 套包可组成包数取最小子件。

29.5 购物车和订单

  • [ ] 单品加购/修改/勾选/删除。
  • [ ] 套包不进购物车、直接购买。
  • [ ] 跨活动单品结算,主表 activity_id=0。
  • [ ] 预览和提交二次校验。
  • [ ] 并发最后一份库存只有一单锁定成功。
  • [ ] 客户端超时重试不重复下单。
  • [ ] 套包正式限购 1 次。

29.6 采购支付补偿

  • [ ] 采购类型 30-Cxx-77、来源 13。
  • [ ] 指定仓套包多仓标记只影响秒杀。
  • [ ] 支付成功 locked -> used。
  • [ ] 重复支付回调幂等。
  • [ ] 主动取消/超时释放 locked。
  • [ ] 已支付整单/行关闭释放 used 差量。
  • [ ] paid/closed 补偿重复执行无副作用。

30. 监控建议

指标维度告警
OA 回调失败/延迟template/oa_no超 SLA
活动商品状态刷新延迟activity_id时间边界后仍旧状态
列表与加购库存差异activity_goods_id同请求口径差异
待支付超时未关闭order_id超过 expire_time
支付成功未标记 paidpo_order_id短延迟后仍不一致
locked/used 超 qtyactivity_goods_id任意出现
采购关闭未释放po_order_id关闭后仍占量
补偿失败task/单号任意持续失败
重复采购单flash_order_id多于预期拆单数
无价商品请求activity_goods_id/sid突增

31. 已确认与待确认

31.1 静态代码和产品规则已确认

  • 活动类型 1/2,库存范围 1/2/3。
  • OA 状态 0/1/2/3,模板 callback_20260526。
  • 活动设置状态和运行页面状态是不同维度。
  • 单品 qty=0 表示不限制活动量,套包必须 qty>0。
  • 套包正式购买次数限制为 1。
  • 单品黑名单、套包唯一白名单。
  • 名单保存按最终快照全量替换。
  • 操作商品使用 activity_goods_id,不能只用 inv_id。
  • 一口价和固定折扣走不同价格链,无价不得下单。
  • 同 SKU 多效期库存响应要去重。
  • 提交订单增加 locked_qty,支付成功转 used_qty。
  • 采购类型 30-Cxx-77,来源类型 13。
  • 支付中心成功回调后调用 markPaidByPoOrder。
  • 采购关闭支持整单和明细差量释放。
  • 有超时、商品状态、购物车、支付和关闭五类任务。
  • 套包指定仓秒杀采购透传 multiWarehouseFlag=true。
  • OA 固定审批人属于流程节点,不是表单字段。

31.2 环境待确认

  • OA 生产模板字段、MQ 重试和回调 SLA。
  • 库存中心仓库/效期请求和响应唯一明细键。
  • 支付中心重复回调与迟到支付策略。
  • 秒杀任务生产 cron 频率、单次 limit 和并发实例数。
  • 活动/订单表线上唯一索引和锁等待配置。
  • 多采购单拆分时整单支付完成判断。
  • 采购整单/行关闭消息的生产所有权和重试。
  • OPS 菜单、白名单和服务站入口生产配置。
  • 前端实际字段与 Apipost 最新合同的一致性。

32. 证据来源

主题文件
OPS Controllerapplication/controllers/inner/activity/FlashActivity.php
活动管理application/Services/Activity/FlashActivitySer.php
站管家 Controllerapplication/controllers/scm/FlashSale.php
移动商城 Controllerapplication/controllers/inner/moveMall/FlashSale.php
交易 Serviceapplication/Services/Activity/FlashSaleSer.php
枚举application/KzData/Enums/FlashActivityEnums.php
采购枚举application/KzData/Enums/PoOrderEnums.php
支付回调application/controllers/tasks/PayCenterNotify.php
OA 回调application/controllers/tasks/OaNotify.php
补偿任务application/controllers/tasks/FlashSaleTask.php
表设计document/flash-sale-table-structure.md
API 合同document/flash-sale-api-mock.md
需求覆盖document/flash-sale-requirement-coverage.md
业务手册document/flash-sale-requirement-handbook.md

33. 一页式执行结论

先用 activity_id/activity_goods_id/sid 固定活动商品,不按 invId 猜规则。
可见性依次查审批、启用、时间、商品、名单、价格和库存。
单品 qty=0 是不限活动量;套包 qty>0,available=qty-locked-used,购买上限1次。
单品与套包不判冲突;单品按物料+效期,套包再加仓库。
下单先原子锁 locked,支付成功 locked 转 used;取消超时释放 locked,已支付关闭释放 used。
采购单必须是 30-Cxx-77、srcOrderType=13,并保留秒杀订单ID/单号。
列表、加购、预览、提交必须复用同一价格和库存口径。
补偿前先证明支付和采购最终事实,补偿后重复执行应为0变化。

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

多入口请求链路

场景调用方与入口请求载荷/上下文Controller/ConsumerService/Provider汇合点最终业务事实
OPS 管理/inner/activity/FlashActivity、scm/FlashSale活动、商品、站点范围、价格库存两类 ControllerFlashActivitySer活动 ID活动配置、OA 和启停状态
站端购买/inner/moveMall/FlashSalesid、活动商品、数量、购物车/地址站端 ControllerFlashSaleSer活动+站点+SKU锁量、购物车、秒杀单、采购单
OA/支付OA/PayCenter MQ活动审批;采购支付结果OaNotify、PayCenterNotify活动/秒杀 Service活动 ID;采购/秒杀关系审批生效、支付锁量转已用
定时补偿FlashSaleTask过期时间窗、订单/购物车 IDCLI task补偿方法秒杀订单/购物车关闭、释放与状态纠偏

日志证据矩阵

| 链路段 | 日志来源 | 可检索锚点 | 成功信号 | 失败信号 | 与下一段关联方式 | | --- | --- | --- | --- | --- | --- | --- | | 活动审批 | OPS + OaNotify | request_id、活动 ID、OA 单号/模板码 | 审批态单向推进 | 未知模板、重复/乱序 | 活动 ID 查主表状态 | | 加购 | FlashSaleSer::addCart | sid、活动 ID、SKU、cart ID | locked_qty +n 与购物车一致 | 库存不足、限购、活动失效 | 活动商品与购物车对账 | | 下单支付 | submitOrder、PayCenterNotify | 秒杀单、采购单、支付单 | 三单关系完整,支付转 used | 采购创建部分失败、回调漏处理 | 关系字段串联三种单号 | | 关闭补偿 | FlashSaleTask/release 方法 | task 批次、订单、采购单 | 锁量释放且重跑 0 变化 | 重复释放、locked 负数 | 数量守恒 + task 批次 |

环节数据变更台账

步骤代码位置事务读取事实写入表/缓存/MQ字段或数量变化回查证据
配置审批FlashActivitySer/OaNotify本地与 OA 异步边界当前状态、商品/范围活动三表、OA MQdraft -> pending -> approved/rejectedOA 单号、活动状态历史
原子锁量FlashSaleSer::addCart锁量事务total-locked-used、限购量FLASH_CART、活动商品cart +n;locked_qty +ntotal >= locked+used
创建三单submitOrder/采购 Service跨表事务边界需验证有效购物车和供给秒杀订单/明细、采购主明细/关系秒杀待支付;采购类型 30-Cxx-77、来源 13秒杀/采购单号和 SKU 数量
支付转换markPaidByPoOrder回调事务支付成功且未处理秒杀订单、活动商品locked -n、used +n、订单 -> paid支付单、数量守恒
关闭释放release/compensate幂等事务最终支付/采购关闭事实订单、购物车、活动商品未支付释放 locked;已支付关闭按代码释放 used重跑前后字段 0 变化

子模块追踪:flash-save-check 活动保存、效期与冲突规则

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
保存活动OPS 新建/编辑秒杀活动request ID、activity ID、商品列表、时间/效期application/controllers/inner/activity/FlashActivity.php -> application/Services/Activity/FlashActivitySer.php活动状态、商品档案、效期属性、同物料冲突范围活动本地事务全量写主表与商品快照,draft old -> savedrequest ID + activity ID + SKU/invId校验失败零写入;全量替换失败应整单回滚,不保留半份商品
冲突回查保存失败或商品重复占用activity ID、SKU、生产效期、仓库application/KzData/Enums/FlashActivityEnums.php同期活动、单品/套包类型、物料+效期+仓库冲突键查询只读 不写;冲突活动清单可回查activity IDs + conflict key单品与套包规则不同;不得通过手改活动状态绕过冲突校验

子模块追踪:flash-scope-check 站点范围与商品可见性

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
保存范围OPS 保存服务站黑/白名单activity ID、activity_goods_id、sid 集合application/Services/Activity/FlashActivitySer.php商品类型、已有范围、站点有效性本地事务全量替换范围行 old set -> new setrequest ID + activity/goods ID + sid count空集合语义按商品类型解释;替换失败整批回滚
可见查询站端秒杀商品列表sid、activity ID、时间application/controllers/inner/moveMall/FlashSale.php -> application/Services/Activity/FlashSaleSer.php审批、启用、时间、商品状态和名单查询只读 不写;按单品黑名单/套包白名单返回request ID + sid + activity/goods ID列表不可见依次查六层条件;不以库存单一条件下结论

子模块追踪:flash-oa-check OA 提交与回调

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
提交 OAOPS 对已保存活动提交审批activity ID、模板码、申请人application/controllers/inner/activity/FlashActivity.php -> application/Services/Activity/FlashActivitySer.php活动完整性、当前 OA/启用状态、商品数量本地事务 oa_status: draft -> pending 并保存关联;OA 请求在事务外request ID + activity ID + process/template codeOA 调用超时先查流程号;未受理再幂等提交,不能生成多流程
审批回调OA 20260526 等模板结果message ID、processNo、activity ID、结果application/controllers/tasks/OaNotify.php模板码、关联活动、当前申请态回调本地事务 pending -> approved/rejected,重复结果 0 变化message ID + processNo + activity ID未知模板/乱序结果不覆盖终态;缺回调按流程号补发或回查

子模块追踪:flash-price-check 秒杀价格链

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
价格计算列表、加购、预览、提交复核activity_goods_id、sid、SKU、价格类型application/Services/Activity/FlashSaleSer.php活动一口价/折扣、站点基础价、套包组成计算阶段查询只读 不写;输出统一成交价和金额request ID + activity goods ID + sid + calculated price无基础价/活动价按规则不可买;禁止各入口自行实现不同算法
下单快照提交订单保存最终价格秒杀单、采购单、商品金额application/Services/Activity/FlashSaleSer.php提交时重算价、购物车价和金额合计下单本地事务写订单/采购价格快照 none -> final priceflash/po orderNo + activity goods ID + amount列表价变化以提交复核为准;部分写入时按三单关系回滚/补偿

子模块追踪:flash-stock-check 秒杀库存计算

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
可售计算商品列表、加购、预览查询activity_goods_id、sid、SKU、效期/仓库application/Services/Activity/FlashSaleSer.php单品实时/在途/活动口径;套包 qty/locked/used 与组件约束查询只读 不写;单品 qty=0 按不限活动量,套包 available=qty-locked-usedrequest ID + activity goods ID + inventory keys同 SKU 多效期去重后计算;列表口径不能替代提交锁后事实
数量对账可售异常或 locked/used 不平活动商品、购物车、秒杀/采购单application/KzData/Enums/FlashActivityEnums.php有效购物车、待支付/已支付/关闭订单和采购最终态查询只读 不写;验证 total >= locked+used 和订单数量守恒activity/order/cart IDs负数或占量遗漏先定位生命周期步骤,再执行对应释放/转换补偿

子模块追踪:flash-cart-check 购物车与失效

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
加购修改站端添加、改量、删除购物车sid、activity_goods_id、cart ID、数量application/controllers/inner/moveMall/FlashSale.php -> application/Services/Activity/FlashSaleSer.php活动有效性、范围、价格、库存、限购和已有 cart购物车本地事务 cart old -> new,对应 locked_qty +/- diffrequest ID + sid + activity/cart ID任一校验失败零变化;并发改量用条件更新防止 locked 超限
失效释放活动/商品失效或购物车超时任务cart ID、activity ID、批次application/controllers/tasks/FlashSaleTask.phpcart 当前态、是否已转订单、locked 数量每车本地事务 cart valid -> invalid 且 locked_qty -n,重跑 0 变化task batch + cart/activity ID + affected rows已转订单购物车不得释放订单占量;失败键小批重跑

子模块追踪:flash-preview-submit 预览、提交与原子锁量

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
订单预览站端从有效购物车预览sid、cart IDs、地址/供应商上下文application/controllers/inner/moveMall/FlashSale.php -> application/Services/Activity/FlashSaleSer.php购物车、活动、价格、库存、仓库和配送信息查询只读 不写;返回分供应商预览快照request ID + sid + cart/activity IDs预览成功不占用新数量;提交必须重新校验全部条件
原子提交用户确认提交秒杀订单cart IDs、client request key、地址application/Services/Activity/FlashSaleSer.php锁后的 locked/used、限购、购物车状态、价格下单本地事务条件锁量并写秒杀主明细,cart -> ordered、order none -> wait_payrequest ID + flash orderNo + cart IDs并发条件失败整单回滚;采购创建失败按关系释放本次锁量

子模块追踪:flash-po-pay 转采购与支付

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
转采购秒杀提交按供应商创建采购flash orderNo、supplier、仓库、商品application/Services/Activity/FlashSaleSer.php -> application/KzData/Enums/PoOrderEnums.php秒杀订单明细、供应商分组、仓库透传和来源唯一性本地事务创建采购 orderType=30-Cxx-77/srcOrderType=13 并保存秒杀关系flash/po orderNos + source ID多采购部分失败按已建关系逐单回滚/关闭,不能重复建成功单
支付转换采购支付中心成功回调payOrderNo、po/flash orderNo、message IDapplication/controllers/tasks/PayCenterNotify.php -> application/Services/Activity/FlashSaleSer.php首次支付、三单关系、locked/used回调本地事务订单 wait_pay -> paid、locked -n, used +nmessage ID + pay/po/flash orderNos重复回调 0 增量;状态异常先查采购支付和数量账再补偿

子模块追踪:flash-cancel-compensate 取消、超时、关闭与补偿

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
取消关闭用户取消、待支付超时、采购关闭flash/po orderNo、当前状态、原因application/Services/Activity/FlashSaleSer.php支付最终态、采购关闭态、订单和 locked/used每单本地事务未支付释放 locked;已支付关闭按当前代码释放 used,状态到 closedorderNos + action/task + affected qty支付不确定时禁止释放;并发回调由状态条件保证仅一次
定时补偿expireWaitPayOrders、paid/closed 补偿task batch、时间窗、order IDsapplication/controllers/tasks/FlashSaleTask.php候选状态、更新时间、支付/采购/数量最终事实小批本地事务只修缺失变化;已完成 new -> new 且影响行 0task + batch + scanned/success/fail IDs保留失败清单;补偿后核对 locked/used 非负及三单状态闭环

子模块追踪:flash-import-export 秒杀导入、导出与模板

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
模板导入OPS 下载模板并导入活动商品activity ID、file/task ID、模板版本application/controllers/scm/FlashSale.php -> application/Services/Activity/FlashActivitySer.php列头版本、SKU/套包、仓库、价格、数量和效期规则解析校验阶段不写;全部通过后本地事务批量 old rows -> imported rowsrequest ID + activity/file ID + row/error counts任一行错误返回行号原因;不得部分写入后伪装全量成功
导出核对导出活动商品/错误结果activity ID、export task IDapplication/controllers/scm/FlashSale.php当前活动商品、范围、显示数量和仓库名称查询只读 不写;异步文件任务 pending -> success/failedrequest ID + activity/task ID + row count单品数量显示和套包口径不同;文件失败只重跑导出任务