文件
xionggeshop/addons/shopro/tests/CommissionScenarioCalculator.php

278 行
12 KiB
PHP

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<?php
namespace addons\shopro\tests;
/**
* 分销佣金预期计算器(与 Commission.php 算法一致,用于测试对照)
*/
class CommissionScenarioCalculator
{
/**
* @param array $options
* - amount float 结算金额
* - commission_level int 分销层级 1-3
* - chain array 上级链(从直推起)每项: name, agent_level, commission_1/2/3, differential_amount, management_rate
* - self_buy bool 是否自购
* - buyer_name string 买家代号(自购时用于跳过级差)
* - is_repurchase bool 是否复购
* - chain_enable / differential_enable / management_enable / repurchase_self_enable / repurchase_referrer_enable
* - repurchase_rate float 复购一级关系链比例(%),级差模式下无效
* - differential_mode bool 是否级差模式(级差模式下 repurchase_rate 不覆盖一级佣金)
* - repurchase_self_type fixed|rate
* - repurchase_self_amount / repurchase_self_rate
*/
public static function calculate(array $options)
{
$amount = floatval($options['amount'] ?? 0);
$commissionLevel = intval($options['commission_level'] ?? 3);
$chain = $options['chain'] ?? [];
$selfBuy = !empty($options['self_buy']);
$buyerName = $options['buyer_name'] ?? 'Buyer';
$isRepurchase = !empty($options['is_repurchase']);
$chainEnable = array_key_exists('chain_enable', $options) ? (bool) $options['chain_enable'] : true;
$differentialEnable = array_key_exists('differential_enable', $options) ? (bool) $options['differential_enable'] : true;
$managementEnable = array_key_exists('management_enable', $options) ? (bool) $options['management_enable'] : true;
$repurchaseSelfEnable = array_key_exists('repurchase_self_enable', $options) ? (bool) $options['repurchase_self_enable'] : true;
$repurchaseReferrerEnable = array_key_exists('repurchase_referrer_enable', $options) ? (bool) $options['repurchase_referrer_enable'] : true;
$productRepurchaseEnable = array_key_exists('product_repurchase_enable', $options) ? (bool) $options['product_repurchase_enable'] : true;
$repurchaseRate = floatval($options['repurchase_rate'] ?? 0);
$differentialMode = !empty($options['differential_mode']);
$repurchaseSelfType = $options['repurchase_self_type'] ?? 'fixed';
$repurchaseSelfAmount = floatval($options['repurchase_self_amount'] ?? 5);
$repurchaseSelfRate = floatval($options['repurchase_self_rate'] ?? 3);
$rewards = [];
$skipReferrer = $isRepurchase && !$repurchaseReferrerEnable;
if (!$skipReferrer) {
if ($chainEnable) {
$rewards = array_merge($rewards, self::calcChain(
$chain,
$amount,
$commissionLevel,
$isRepurchase,
$repurchaseRate,
$differentialMode
));
}
if ($differentialEnable) {
$rewards = array_merge($rewards, self::calcDifferential(
$chain,
$selfBuy,
$buyerName
));
}
if ($managementEnable) {
$rewards = array_merge($rewards, self::calcManagement(
$chain,
$amount
));
}
}
// 复购已优化为付款时直接减免,分销模块不再向买家发放事后返现佣金
// if ($isRepurchase && $repurchaseSelfEnable && $productRepurchaseEnable) { ... }
$total = 0;
foreach ($rewards as $row) {
$total += floatval($row['commission']);
}
return [
'rewards' => $rewards,
'total' => round($total, 2),
];
}
protected static function calcChain($chain, $amount, $commissionLevel, $isRepurchase, $repurchaseRate, $differentialMode = false)
{
$rewards = [];
$depth = 1;
foreach ($chain as $node) {
if ($depth > $commissionLevel) {
break;
}
$rateKey = 'commission_' . $depth;
$rate = floatval($node[$rateKey] ?? 0);
if ($depth === 1 && $isRepurchase && $repurchaseRate > 0 && !$differentialMode && $rate > 0) {
$rate = $repurchaseRate;
}
if ($rate > 0) {
$rewards[] = [
'name' => $node['name'],
'award_type' => 'chain',
'commission_level' => $depth,
'commission' => round($amount * $rate * 0.01, 2),
'rate' => $rate,
];
}
$depth++;
}
return $rewards;
}
protected static function calcDifferential($chain, $selfBuy, $buyerName)
{
$rewards = [];
$prevTier = 0;
if ($selfBuy && !empty($chain)) {
$buyerNode = null;
foreach ($chain as $node) {
if ($node['name'] === $buyerName) {
$buyerNode = $node;
break;
}
}
if ($buyerNode) {
$prevTier = floatval($buyerNode['differential_amount'] ?? 0);
}
}
$depth = 1;
foreach ($chain as $node) {
if ($selfBuy && $node['name'] === $buyerName) {
$depth++;
continue;
}
$tier = floatval($node['differential_amount'] ?? 0);
$payout = round(max(0, $tier - $prevTier), 2);
$prevTier = max($prevTier, $tier);
if ($payout > 0) {
$rewards[] = [
'name' => $node['name'],
'award_type' => 'differential',
'commission_level' => $depth,
'commission' => $payout,
'tier' => $tier,
];
}
$depth++;
}
return $rewards;
}
protected static function calcManagement($chain, $amount)
{
$rewards = [];
$depth = 1;
foreach ($chain as $node) {
$rate = floatval($node['management_rate'] ?? 0);
if ($rate > 0) {
$rewards[] = [
'name' => $node['name'],
'award_type' => 'management',
'commission_level' => $depth,
'commission' => round($amount * $rate * 0.01, 2),
'rate' => $rate,
];
}
$depth++;
}
return $rewards;
}
/** 内置三个标准测试场景 */
public static function builtInScenarios()
{
$levels = [
'L1' => ['commission_1' => 10, 'commission_2' => 0, 'commission_3' => 0, 'differential_amount' => 40, 'management_rate' => 5],
'L2' => ['commission_1' => 10, 'commission_2' => 5, 'commission_3' => 0, 'differential_amount' => 80, 'management_rate' => 3],
'L3' => ['commission_1' => 10, 'commission_2' => 5, 'commission_3' => 3, 'differential_amount' => 120, 'management_rate' => 2],
];
$chainNormal = [
array_merge(['name' => 'C(直推)'], $levels['L1']),
array_merge(['name' => 'B(二级)'], $levels['L2']),
array_merge(['name' => 'A(三级)'], $levels['L3']),
];
$chainSelfBuy = [
array_merge(['name' => 'C(自购)'], $levels['L1']),
array_merge(['name' => 'B(二级)'], $levels['L2']),
array_merge(['name' => 'A(三级)'], $levels['L3']),
];
return [
'scenario_1' => [
'title' => '场景1:首购 · 买家D · 上级C→B→A · 订单1000元 · 三类全开',
'steps' => [
'1. 确认分销设置:关系链/级差/管理奖/本人复购返现 均开启',
'2. 确认等级:L1档40元/5%,L2档80元/3%,L3档120元/2%;关系链 10%/5%/3%',
'3. 分销商品勾选:参与分销 + 级差 + 管理奖 + 复购返现',
'4. 建立关系:A→B→C→D(D 为普通买家或分销商均可)',
'5. D 首次下单 1000 元并支付(结算基数=商品价 1000)',
'6. 查表:SELECT * FROM fa_shopro_commission_reward WHERE order_item_id=订单明细ID',
],
'options' => [
'amount' => 1000,
'commission_level' => 3,
'chain' => $chainNormal,
'buyer_name' => 'D(买家)',
'self_buy' => false,
'is_repurchase' => false,
],
],
'scenario_2' => [
'title' => '场景2:自购 · 分销商C自买1000元 · 上级B→A · 内购开启',
'steps' => [
'1. 分销设置开启「分销内购」',
'2. C 为 L1 分销商,上级 B(L2)、A(L3)',
'3. C 自己下单 1000 元并支付',
'4. 级差应跳过 C 本人,从 C 的档位 40 作为 prevTier',
'5. 管理奖 C 本人也应获得 5%',
],
'options' => [
'amount' => 1000,
'commission_level' => 3,
'chain' => $chainSelfBuy,
'buyer_name' => 'C(自购)',
'self_buy' => true,
'is_repurchase' => false,
],
],
'scenario_3' => [
'title' => '场景3:复购 · D 第二次购买1000元 · 付款时已立减5元(不返现)',
'steps' => [
'1. D 历史已有至少一笔包含该指定商品的有效订单 (status in 1,2)',
'2. 复购推荐人分佣=继续分佣;本人复购立减=开启,类型=固定5元',
'3. 商品勾选参与复购立减',
'4. D 再次下单时直接立减 5 元,实付 995 元',
'5. 推荐人仍拿关系链+级差+管理奖;D 本人付款立减,不再产生返现佣金',
],
'options' => [
'amount' => 1000,
'commission_level' => 3,
'chain' => $chainNormal,
'buyer_name' => 'D(买家)',
'self_buy' => false,
'is_repurchase' => true,
'repurchase_self_type' => 'fixed',
'repurchase_self_amount' => 5,
],
],
'scenario_4' => [
'title' => '场景4:复购 · 推荐人不再分佣 · 买家付款立减5元(佣金奖池为0)',
'steps' => [
'1. 分销设置:复购推荐人分佣=不再分佣',
'2. D 复购付款时已直接立减 5 元',
'3. 预期:C/B/A 无分销佣金,买家已立减亦无返现佣金,总佣金为 0',
],
'options' => [
'amount' => 1000,
'commission_level' => 3,
'chain' => $chainNormal,
'buyer_name' => 'D(买家)',
'self_buy' => false,
'is_repurchase' => true,
'repurchase_referrer_enable' => false,
'repurchase_self_type' => 'fixed',
'repurchase_self_amount' => 5,
],
],
];
}
}