BeeX commission domain

统一佣金计算与下单结算方案

把商品返现、直接邀请佣金和营销补贴收口到唯一计算引擎,统一游客预览、登录预览与订单结算,避免公式继续散落在商品、券、活动和订单模块。

目标方案 v1.02026-07-23产品 / 后端 / App / 运营 / QA

文档定位

01 / POSITION
产品目标:所有新订单、商品返现展示和收益预览只能通过统一佣金域计算。业务子模块负责提供上下文或执行结果,不再保存自己的佣金公式。
当前实现差距:现有接口和专题文档仍保留旧公式、按归因时间取规则、公开传入 userId、新人前三单加成等过渡口径。本文描述目标方案,不代表相关服务端代码和接口已经完成改造。
上位产品规则产品范围冲突时以 BeeX PRD v2.0 为准。
关联专题商品分类参见 商品类型方案;活动动作参见 活动规则引擎
本文边界定义计算、预览、结算、钱包入账和退款处理,不重新设计平台订单归因算法、提现或平台对账。

佣金范围与资金边界

02 / SCOPE
买家基础返现USER_CASHBACK基础分配

技术服务费扣除后的可分配佣金,按商品类型和 CPS 阶梯分给买家。

直接邀请人佣金DIRECT_COMMISSION基础分配

以本单 USER_CASHBACK 为基数,只支付给订单用户的有效直接邀请人。

优惠券返现COUPON_CASHBACK营销预算

从可用券中选择本单收益最高的一张,买家专享。

返佣基金REBATE_FUND营销预算

USER_CASHBACK 为基数,从用户的返佣基金额度中核销。

活动返现ACTIVITY_CASHBACK营销预算

由订单完成事件触发的佣金加成,可命中多条并叠加。

资金边界:USER_CASHBACK + DIRECT_COMMISSION 受平台净佣金约束;优惠券、返佣基金和活动返现来自独立营销预算,因此买家最终到账可以超过本单佣金计算基数。

统一架构

03 / ARCHITECTURE
flowchart LR UI["商品列表 / 商品详情 / 收益预览"] --> F["CommissionFacade"] SYNC["平台订单完成事件"] --> F F --> R["CommissionContextResolver"] R --> DATA["订单、商品、规则、邀请关系、券和活动资格"] R --> E["CommissionCalculationEngine"] E --> PLAN["CommissionCalculationResult
确定性计算明细"] PLAN --> P["CommissionPostingService"] P --> BUDGET["原子核销券、基金和活动预算"] P --> RECORD["commission_records"] P --> WALLET["wallet Pending 账本"]
组件唯一职责禁止事项
CommissionFacade统一承接游客预览、登录预览和正式结算。不得自行计算任何佣金金额。
CommissionContextResolvercalculationAt 读取商品类型、配置版本、直接关系和营销资格。不得写钱包、消耗预算或复制公式。
CommissionCalculationEngine执行纯计算并返回基础分配和待核销营销明细。不得访问数据库、钱包、网络或系统当前时间。
CommissionPostingService锁定订单和资源,执行预算核销、佣金记录、钱包 Pending 入账与幂等控制。不得重新计算或修改引擎给出的金额。
统一入口约束:商品、券、返佣基金、活动、订单同步和钱包模块均不得调用独立公式。展示场景只调用 CommissionFacade.preview,正式结算只调用 CommissionFacade.settle

下单到结算的完整流程

04 / ORDER FLOW
flowchart TD A["用户浏览商品"] --> B{"是否登录?"} B -- 否 --> C["游客预览
只显示 USER_CASHBACK"] B -- 是 --> D["登录预览
显示买家个性化总返现"] C --> E["生成联盟链接和 tracking code"] D --> E E --> F["跳转 TikTok / Shopee / Lazada"] F --> G["平台产生订单"] G --> H["BeeX 同步 PENDING 订单
只保存订单,不记佣金"] H --> I["持续补全平台订单、商品和归因信息"] I --> J{"平台订单已完成?"} J -- 否 --> I J -- 是 --> K{"已有 order.userId?"} K -- 否 --> L["不产生佣金
不进入待认领池,不允许事后补领"] K -- 是 --> M{"platformProductId 和 productType 完整?"} M -- 否 --> N["阻断结算
补全商品信息后重试"] M -- 是 --> O["calculationAt = order.settledAt"] O --> P["统一佣金计算与单事务入账"] P --> Q["佣金记录和钱包金额进入 Pending"] Q --> R{"到达 releaseAt?"} R -- 否 --> S{"发生退款?"} R -- 是 --> T["Pending 转 Available"] S -- 否 --> R S -- 是 --> U["自动冲正 Pending"] T --> V{"后续退款?"} V -- 否 --> W["可提现 / 已支付"] V -- 是 --> X["创建运营异常任务
不自动扣款、不产生负钱包"]
点击阶段允许游客。游客点击可以先保存 tracking code;只要在平台订单完成前完成登录绑定,并最终写入 order.userId,即可按登录用户正常结算。
PENDING 阶段不记收益。平台未完成订单只保存和补全订单,不创建佣金记录,不写钱包 Pending。
完成阶段重新取规则。商品类型、阶梯、商品覆盖、邀请关系、券、基金和活动资格全部按 order.settledAt 判断,不沿用点击或预览结果。
缺关键商品信息必须阻断。不得把未知商品兜底成 NORMAL_AFFILIATE,补全后通过同一幂等入口重试。

佣金计算过程

05 / CALCULATION FLOW
flowchart TD A["接收 ResolvedCommissionContext"] --> B["校验金额、bps、币种和 calculationAt"] B --> C{"商品是否可返佣?"} C -- 否 --> Z["返回零收益结果"] C -- 是 --> D["计算 actualCpsBps"] D --> E["按 countryCode + productType + CPS 阶梯
取得默认 buyerShareBps / directShareBps"] E --> F{"活动或高返佣商品
有有效商品分成覆盖?"} F -- 是 --> G["已配置字段覆盖默认值
未配置字段继续使用默认值"] F -- 否 --> H["使用默认阶梯值"] G --> I["计算封顶佣金基数"] H --> I I --> J["扣技术服务费,得到净佣金"] J --> K["计算买家基础返现"] K --> L{"完成时间存在有效直接邀请人?"} L -- 是 --> M["直接邀请佣金 = 买家基础返现 × directShareBps"] L -- 否 --> N["直接邀请佣金 = 0,未分配部分留在 BeeX"] M --> O["校验 买家基础返现 + 直接邀请佣金 ≤ 净佣金"] N --> O O --> P["计算所有合格券金额
选择最高的一张"] P --> Q["计算 REBATE_FUND"] Q --> R["逐条计算 ACTIVITY_CASHBACK"] R --> S["返回基础明细和待核销营销明细"]

引擎只返回金额和来源,不判断数据库中的实时剩余预算。正式结算时,CommissionPostingService 对引擎输出的营销明细执行原子核销;核销失败只移除对应营销行,不改变其他金额,也不在业务模块重新计算。

统一公式与约束

06 / FORMULA
符号含义
订单金额订单佣金计价金额,minor 单位。
平台佣金平台确认给 BeeX 的佣金,minor 单位。
佣金基数经过佣金基数封顶后的计算基数。
技术服务费BeeX 技术服务费。
净佣金扣除技术服务费后的可分配净佣金。
买家基础返现买家基础返现 USER_CASHBACK
直接邀请佣金直接邀请人佣金 DIRECT_COMMISSION
实际 CPS:actualCpsBps = floor(平台佣金 × 10000 ÷ 订单金额)
佣金基数:佣金基数 = min(平台佣金, floor(订单金额 × maxCommissionBaseBps ÷ 10000))
技术服务费:技术服务费 = floor(佣金基数 × 命中阶梯.technicalServiceFeeBps ÷ 10000)
净佣金:净佣金 = 佣金基数 − 技术服务费
买家基础返现:买家基础返现 = floor(净佣金 × buyerShareBps ÷ 10000)
直接邀请佣金:直接邀请佣金 = floor(买家基础返现 × directShareBps ÷ 10000)
取整所有比例乘除都使用整数 minor 单位并向下取整,禁止先转浮点或四舍五入。
运行时约束买家基础返现 + 直接邀请佣金 ≤ 净佣金。没有有效直接邀请人时 直接邀请佣金 = 0,未分配金额留在 BeeX。
配置发布约束buyerShareBps × (10000 + directShareBps) ≤ 10000 × 10000,不满足时阻止配置发布。
基础参数订单金额 > 0平台佣金 ≥ 0,所有 bps 必须在允许区间;平台佣金 = 0 或无返佣商品直接返回零收益。
不设单笔封顶本方案没有 perOrderCap。营销金额只受自身公式、资格、余额和总预算约束。

完整计算示例

以下均为 minor 单位:订单金额 = 1,000,000平台佣金 = 180,000、佣金基数上限 40%、技术服务费 10%、买家分成 70%、直接邀请人按买家返现的 20%。

步骤计算结果
实际 CPS180,000 × 10000 ÷ 1,000,0001,800 bps
佣金基数min(180,000, 1,000,000 × 40%)180,000
技术服务费180,000 × 10%18,000
净佣金180,000 − 18,000162,000
买家基础返现162,000 × 70%113,400
直接邀请佣金113,400 × 20%22,680
最优优惠券固定 15,000、比例 10%=11,340、1.2 倍加成=22,68022,680
REBATE_FUND113,400 × 25%28,350
两条活动加成113,400 × 10% + 113,400 × 5%17,010
买家个性化总返现113,400 + 22,680 + 28,350 + 17,010181,440

基础分配 买家基础返现 + 直接邀请佣金 = 136,080 ≤ 净佣金;买家总返现超过 佣金基数 的 1,440 来自独立营销预算,符合资金边界。

商品类型、CPS 阶梯与商品覆盖

07 / SPLIT RULE

默认分成规则按 countryCode + productType + cpsTier 匹配。CPS 阶梯按 minCpsBps/maxCpsBps 匹配,每档各自携带并必填 technicalServiceFeeBpsbuyerShareBpsdirectShareBps(无全局回落,缺字段的档会被拒绝发布),本身不直接产生金额。

商品类型是否计算佣金规则
NORMAL_AFFILIATE仅使用该商品类型的默认 CPS 阶梯。
HIGH_COMMISSION默认 CPS 阶梯;运营配置商品时可选商品级分成覆盖。
BEEX_ACTIVITY默认 CPS 阶梯;运营配置活动商品时可选商品级分成覆盖。
SHORT_VIDEO_NO_COMMISSION直接返回零收益。
LIVE_NO_COMMISSION直接返回零收益。
NORMAL_NO_COMMISSION直接返回零收益。

默认 CPS 阶梯

序号actualCpsBps 区间运营展示
1[0, 200)0%–2%
2[200, 500)2%–5%
3[500, 1000)5%–10%
4[1000, 1500)10%–15%
5[1500, 2000)15%–20%
6[2000, +∞)20% 及以上
商品独立 CPS 的准确含义:运营习惯称“商品独立 CPS”,技术模型使用 ProductCommissionSplitOverride。它不是重新配置平台 CPS,而是在活动商品或高返佣商品配置时,选择性覆盖默认阶梯中的买家或直接邀请人分成。
record ProductCommissionSplitOverride(
    Integer buyerShareBps,
    Integer directShareBps
) {}
优先级无返佣场景 > BEEX_ACTIVITYHIGH_COMMISSIONNORMAL_AFFILIATE。确定商品类型后,先命中默认阶梯,再应用有效的商品覆盖。
允许部分配置只配置 buyerShareBps 时,directShareBps 沿用默认阶梯;反之亦然。
适用范围只有完成时间仍属于 HIGH_COMMISSIONBEEX_ACTIVITY,且商品覆盖记录在该时间有效时才应用。普通返佣商品不允许覆盖。
发布校验将覆盖字段与回退后的默认字段合并,再执行基础分配安全约束;校验失败时阻止配置生效。

优惠券、返佣基金与活动返现

08 / MARKETING

COUPON_CASHBACK

券类型公式
FIXEDcoupon = fixedAmountMinor
RATEcoupon = floor(买家基础返现 × rateBps ÷ 10000)
MULTIPLIERcoupon = floor(买家基础返现 × (multiplierBps − 10000) ÷ 10000)

完成时间筛出所有有效且适用本单的返现券,逐张通过统一引擎计算,选择金额最高的一张;金额相同时依次选择到期时间最早、券 ID 字典序最小的记录。预览不核销,正式结算在事务内锁定并核销。

REBATE_FUND

返佣基金:fund = floor(买家基础返现 × rebateFundRateBps ÷ 10000)

返佣基金只支付给买家。正式结算时余额或总预算不足,本单整条 REBATE_FUND 跳过,不按剩余额度部分发放,也不影响其他佣金行。

ACTIVITY_CASHBACK

单条活动返现:activity = floor(买家基础返现 × activityRateBps ÷ 10000)
维度统一规则
触发事件只接受 AFFILIATE_ORDER_DONE
活动动作只接受 GRANT_COMMISSION_BONUS
受益人固定为订单买家,不接受活动配置传入任意 beneficiary user ID。
计算基数固定为 USER_CASHBACK;旧 COMMISSIONGMV 口径不再使用。
叠加同一订单可命中多条规则,逐条计算并叠加,每条使用自己的确定性幂等键。
预算不足只跳过预算不足的活动行,不部分发放,不回滚其他已满足规则。
必须清理:新人第 1 单加成 20%、第 2 单加成 30%、第 3 单加成 50% 已取消。删除 NEW_USER_CASHBACK_MULT 种子逻辑并停用现有规则,历史已发记录不删除、不重算。
非佣金动作:GRANT_CASH 是独立现金奖励,不属于 ACTIVITY_CASHBACK,不得写入佣金记录或混入订单返现总额。

游客、登录与正式结算

09 / MODES
模式身份来源返回范围是否写数据
GUEST_PREVIEW无登录身份USER_CASHBACK;不查询直接关系、券、基金、活动或历史订单。
AUTHENTICATED_PREVIEW认证上下文买家可得的 USER_CASHBACK + COUPON_CASHBACK + REBATE_FUND + ACTIVITY_CASHBACK。直接佣金可内部试算,但不展示给买家、不计入买家总额。
ORDER_SETTLEMENT固定使用 order.userId正式生成买家收益和有效直接邀请人的 DIRECT_COMMISSION单事务写佣金、钱包和预算
身份安全登录预览只相信认证上下文,忽略 body 或 query 中的 userId。无效、过期 Token 必须返回鉴权错误,不能静默降级成游客。
预览非承诺预览使用当前可见配置和预算给出估算,不预占资源。正式金额始终以订单完成时间重新计算和原子核销结果为准。
未绑定订单订单完成时没有 order.userId,整单不产生任何佣金,不进入未认领池,也不允许事后补算直接佣金。

正式结算、预算与幂等

10 / POSTING
sequenceDiagram participant W as 订单完成 Worker participant F as CommissionFacade participant DB as MySQL participant E as CalculationEngine participant P as PostingService W->>F: settle(orderId) F->>DB: BEGIN + SELECT order FOR UPDATE DB-->>F: 完成订单与 commissionPostedAt alt 已成功入账 F-->>W: 返回已有结果 else 首次结算 F->>DB: 锁定合格券、基金和活动预算 F->>F: 按 settledAt 解析统一上下文 F->>E: calculate(context) E-->>F: 基础行 + 待核销营销行 F->>P: post(result) P->>DB: 条件更新预算和权益余额 Note over P,DB: 预算不足只跳过对应营销行 P->>DB: 插入 commission_records P->>DB: 插入 wallet Pending 账本 P->>DB: 标记 commissionPostedAt DB-->>F: COMMIT F-->>W: 返回已入账结果 end
事务范围锁订单、锁候选资源、计算、预算核销、佣金插入、钱包 Pending 入账和订单入账标记必须在同一数据库事务中完成。
异常语义任何系统异常回滚整单;“某条营销预算不足”是预期业务结果,只跳过该行并继续提交。
锁顺序订单 → 最优券 → 返佣基金 → 按规则 ID 排序的活动预算,所有实例使用同一顺序降低死锁概率。
金额冻结成功入账后不允许通过 upsert 改写金额。重复完成事件直接读取已生成记录,钱包账本与佣金金额保持一致。

确定性幂等键

收益类型幂等键组成
USER_CASHBACKorderId + type + buyerUserId
DIRECT_COMMISSIONorderId + type + inviterUserId
COUPON_CASHBACKorderId + type + couponId
REBATE_FUNDorderId + type + userCouponId
ACTIVITY_CASHBACKorderId + type + campaignRuleId

活动预算必须维护可原子更新的 usedAmountMinor,通过“当前已用 + 本次金额不超过总预算”的条件更新抢占。禁止在结算时临时汇总历史记录后再判断,否则并发订单会超发。

退款处理

11 / REFUND
flowchart TD A["收到平台退款 / 取消事件"] --> B["按 orderId 锁定订单和佣金记录"] B --> C{"佣金当前状态"} C -- Pending --> D["冲正钱包 Pending"] D --> E["佣金记录标记 INVALID"] E --> F["恢复可恢复的券、基金余额和活动预算"] F --> G["记录退款处理完成"] C -- Available或Paid --> H["不自动扣减钱包"] H --> I["创建运营异常任务"] I --> J["人工核对平台退款、用户余额和处置结果"] C -- 已INVALID --> K["幂等返回,不重复处理"]
禁止负钱包:已释放或已支付收益发生退款时,不创建负余额、不自动形成用户债务。系统保留原账本并创建可追踪的运营异常任务。

退款不重新运行佣金计算引擎。Pending 冲正必须引用原佣金记录和原钱包账本;只有原规则定义为可恢复且仍能安全恢复的营销资源才退回。

接口、模型与数据改造

12 / INTERFACES

统一应用接口

CommissionCalculationResult preview(CommissionPreviewCommand command);
CommissionCalculationResult settle(String orderId);
RefundHandlingResult handleRefund(String orderId, String platformRefundId);
接口 / 模型目标变化
POST /api/v1/order-benefits/preview保留统一预览入口;认证身份只来自 Token。游客只返回基础返现,登录用户返回买家个性化收益。
CommissionCalculationRequest包含 calculation mode、国家、商品类型、订单金额、平台佣金、规则版本结果、直接关系状态和已解析营销候选,不允许引擎内部查询。
CommissionCalculationResult返回计算基数、技术服务费、净佣金、实际 CPS、最终分成参数、基础收益行和待核销营销行。
ProductCommissionSplitOverridebuyerShareBpsdirectShareBps 均可为空,分别覆盖默认阶梯字段。

核心引擎参考实现(Java 17)

public final class CommissionCalculationEngine {

    public CommissionCalculationResult calculate(ResolvedCommissionContext context) {
        validate(context);

        if (!context.productType().commissionable()
                || context.gmvMinor() == 0
                || context.platformCommissionMinor() == 0) {
            return CommissionCalculationResult.zero(context);
        }

        long actualCpsBps = multiplyDivide(
                context.platformCommissionMinor(), 10_000, context.gmvMinor());
        CommissionSplit split = context.splitRule().resolve(
                context.productType(), actualCpsBps, context.productOverride());

        long commissionBaseMinor = Math.min(
                context.platformCommissionMinor(),
                multiplyBps(context.gmvMinor(), context.maxCommissionBaseBps()));
        long technicalFeeMinor =
                multiplyBps(commissionBaseMinor, split.technicalServiceFeeBps());
        long netCommissionMinor = commissionBaseMinor - technicalFeeMinor;
        long userCashbackMinor =
                multiplyBps(netCommissionMinor, split.buyerShareBps());
        long directCommissionMinor = context.directInviterEligible()
                ? multiplyBps(userCashbackMinor, split.directShareBps())
                : 0;

        if (userCashbackMinor + directCommissionMinor > netCommissionMinor) {
            throw new InvalidCommissionConfigurationException(
                    "USER_CASHBACK + DIRECT_COMMISSION exceeds net commission");
        }

        CommissionLine userCashback = CommissionLine.userCashback(
                context.orderId(), context.buyerUserId(), userCashbackMinor);
        Optional<CommissionLine> directCommission =
                directCommissionMinor == 0
                        ? Optional.empty()
                        : Optional.of(CommissionLine.direct(
                                context.orderId(),
                                context.directInviterUserId(),
                                directCommissionMinor));

        Optional<CommissionLine> coupon = context.coupons().stream()
                .map(candidate -> calculateCoupon(candidate, userCashbackMinor))
                .sorted(CommissionLine.bestCouponFirst())
                .findFirst();
        Optional<CommissionLine> rebateFund = context.rebateFund()
                .map(candidate -> calculateRebateFund(candidate, userCashbackMinor));
        List<CommissionLine> activities = context.activities().stream()
                .map(candidate -> calculateActivity(candidate, userCashbackMinor))
                .filter(line -> line.amountMinor() > 0)
                .toList();

        return CommissionCalculationResult.of(
                actualCpsBps,
                commissionBaseMinor,
                technicalFeeMinor,
                netCommissionMinor,
                split,
                userCashback,
                directCommission,
                coupon,
                rebateFund,
                activities);
    }

    private long multiplyBps(long amountMinor, int bps) {
        return Math.multiplyExact(amountMinor, bps) / 10_000;
    }

    private long multiplyDivide(long value, long multiplier, long divisor) {
        return Math.multiplyExact(value, multiplier) / divisor;
    }
}

生产实现应继续使用项目统一的金额溢出处理;Java 17 获取列表首项使用 get(0),不能使用更高版本才提供的 getFirst()

必要数据字段

数据对象新增或收口字段用途
联盟点击platformProductId、点击时观察到的 productType提高订单补全成功率和链路排障能力;点击类型不作为最终结算规则。
联盟订单platformProductId、完成时解析的 productTypesettledAtcommissionPostedAt支持完成时间结算、阻断补全和整单幂等。
商品运营配置可空的 buyerShareBpsdirectShareBps 及有效期承载活动商品或高返佣商品的分成覆盖。
佣金记录确定性幂等键、来源类型、来源 ID、状态、金额和 releaseAt金额只插入一次,支持钱包关联和退款冲正。
营销预算budgetAmountMinorusedAmountMinor条件更新,防止并发超发。
退款异常任务订单、原佣金、退款原因、处理状态和审计信息承接 Available/Paid 后退款的人工处理。
不增加计算快照表:本文不要求保存完整计算输入或规则快照。只保存最终佣金记录,以及订单处理、预算核销、钱包和退款所必需的业务字段。

上线策略与当前缺口

13 / MIGRATION
当前问题目标处理
佣金公式分散在商品、订单、券、基金和活动模块。全部改为调用 CommissionFacade,删除业务子模块金额计算。
部分口径按点击或归因时间取配置和邀请关系。统一改为 calculationAt = order.settledAt
直接佣金可能按净佣金而非买家返现计算。统一使用 USER_CASHBACK 作为唯一基数。
新人前三单活动仍存在种子和当前文档描述。删除种子调用,停用现有活动规则,保留历史奖励记录。
GRANT_CASH 可能被归入活动佣金。ACTIVITY_CASHBACK 完全分离。
订单缺少平台商品 ID 或商品类型时可能降级计算。阻断结算,补全成功后通过幂等入口重试。
佣金记录 upsert 可改金额,但钱包账本不会同步改写。改为 insert-once,首次成功后金额冻结。
活动预算按历史记录汇总,存在并发超发窗口。使用 usedAmountMinor 条件更新原子核销。
预览接口允许请求体传 userId登录身份固定来自认证上下文,无效 Token 不降级游客。
直接全量切换。不做 shadow 双算;所有尚未完成的订单在完成时使用新引擎和当时有效规则。
运营重新配置。直接邀请比例和已有返现券由运营按新字段、券类型与约束人工确认,不自动猜测或迁移比例。
历史数据冻结。切换前已成功入账的佣金记录不重算、不改金额;旧类型只用于历史展示和对账。
上线门禁。先完成规则校验和数据补全,再启用统一入口;任何无法解析商品类型的完成订单进入可重试阻断队列。

验收矩阵

14 / ACCEPTANCE
场景期望结果
游客预览返佣商品只返回 USER_CASHBACK,不查询或暴露任何用户权益。
携带无效 Token 预览返回鉴权错误,不降级为游客。
登录用户有直接邀请人买家总额不包含 DIRECT_COMMISSION;正式结算向邀请人单独入账。
商品只覆盖 buyerShareBps买家比例使用商品覆盖,直接比例使用商品类型默认阶梯。
商品只覆盖 directShareBps直接比例使用商品覆盖,买家比例使用商品类型默认阶梯。
普通返佣商品带商品覆盖拒绝配置或忽略非法覆盖,始终使用默认阶梯。
没有有效直接邀请人DIRECT_COMMISSION=0,不把该份额追加给买家。
多张券金额相同选择最早到期;仍相同则选择 ID 最小的一张。
返佣基金余额不足整条 REBATE_FUND 跳过,不部分发放,基础返现照常入账。
命中三条活动,其中一条预算不足发放另外两条;不足的一条不产生佣金记录。
活动动作为 GRANT_CASH不生成 ACTIVITY_CASHBACK
订单完成时仍未绑定用户整单不产生佣金,不支持后补领。
订单缺 platformProductId 或 productType阻断结算并可重试,不按普通商品兜底。
相同完成事件并发到达只生成一组佣金记录和一组钱包账本,后续请求返回已有结果。
Pending 阶段退款自动冲正并恢复可恢复资源,佣金标记 INVALID
Available/Paid 后退款不产生负钱包,创建运营异常任务。
历史已结算订单切换后金额与状态保持不变。