文件
Henglianshutong/tests/partner/MakerPeerTest.php

392 行
15 KiB
PHP

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

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

<?php
namespace tests\partner;
// 引导 ThinkPHP 环境
define('APP_PATH', __DIR__ . '/../../application/');
define('ROOT_PATH', dirname(realpath(APP_PATH)) . '/');
require_once __DIR__ . '/../../thinkphp/base.php';
require_once __DIR__ . '/../../thinkphp/helper.php';
require_once __DIR__ . '/../../application/common.php';
\think\Config::set(include APP_PATH . 'database.php', 'database');
\think\Loader::addNamespace('app', APP_PATH);
require_once __DIR__ . '/../../addons/shopro/helper/helper.php';
use addons\shopro\service\partner\MakerPeerReward;
use addons\shopro\service\partner\ActiveService;
use addons\shopro\service\partner\PartnerRewardService;
use addons\shopro\service\partner\PartnerConfig;
use think\Db;
/**
* 模拟活跃度服务,便于单元测试任意用户的自购状态
*/
class MockActiveService extends ActiveService
{
private $activeMap = [];
public function setActive($userId, $isActive)
{
$this->activeMap[$userId] = $isActive;
}
public function isActive($agent, $atTime = null)
{
$userId = is_array($agent) ? ($agent['user_id'] ?? 0) : ($agent->user_id ?? 0);
if (isset($this->activeMap[$userId])) {
return $this->activeMap[$userId];
}
return true; // 默认均活跃
}
}
class MakerPeerTest
{
private $passed = 0;
private $failed = 0;
public function run()
{
echo "========================================================\n";
echo " 创客多代平级级联至少于0.10元截断测试 (Maker Peer) \n";
echo "========================================================\n\n";
$this->testThreePeerCascade();
$this->testV3CutoffAtTenCent();
$this->testV6ThreeGenerationsCascade();
$this->testInactiveIntermediaryCascade();
$this->testV1PeerCascade();
$this->testMultiSegmentPeers();
echo "\n--------------------------------------------------------\n";
echo "测试执行结果: 通过 {$this->passed} 项, 失败 {$this->failed} 项\n";
echo "========================================================\n";
return $this->failed === 0 ? 0 : 1;
}
private function assert($condition, $testName, $detail = '')
{
if ($condition) {
echo " [PASS] {$testName}\n";
$this->passed++;
} else {
echo " [FAIL] {$testName} - {$detail}\n";
$this->failed++;
}
}
/**
* 测试 1:经典 3 平级创客(A -> B -> C,均为基数 60 的 V3)
* 规则验证:
* A(2): 实拿极差全额 60.00
* B(3): 第1代平级 60 * 10% = 6.00
* C(4): 第2代平级 6 * 10% = 0.60
*/
public function testThreePeerCascade()
{
$testName = "场景1: 3个平级创客(A->B->C, V3) 第1代拿6元,第2代拿0.60元";
Db::startTrans();
try {
$order = ['id' => 9901, 'user_id' => 7];
$buyerId = 7;
// 关系链:买家(7) -> A(2, V3/level 4) -> B(3, V3/level 4) -> C(4, V3/level 4)
$chain = [
['user_id' => 2, 'level' => 4], // Level 4 基数 60 (V3)
['user_id' => 3, 'level' => 4],
['user_id' => 4, 'level' => 4],
];
$diffResult = [
'seen' => 60.0,
'paid' => [
['user_id' => 2, 'level' => 4, 'cap' => 60.0, 'amount' => 60.0]
]
];
$active = new MockActiveService();
$reward = new MakerPeerReward();
$reward->run($order, $buyerId, $chain, $diffResult, $active);
$bReward = Db::name('shopro_partner_reward')->where('order_id', 9901)->where('user_id', 3)->find();
$cReward = Db::name('shopro_partner_reward')->where('order_id', 9901)->where('user_id', 4)->find();
$bAmount = $bReward ? floatval($bReward['amount']) : 0;
$cAmount = $cReward ? floatval($cReward['amount']) : 0;
$bExt = $bReward ? json_decode($bReward['ext'], true) : [];
$cExt = $cReward ? json_decode($cReward['ext'], true) : [];
$bPass = ($bAmount == 6.00) && (($bExt['generation'] ?? 0) == 1);
$cPass = ($cAmount == 0.60) && (($cExt['generation'] ?? 0) == 2);
$this->assert($bPass && $cPass, $testName, "B金额={$bAmount}(期6.00), C金额={$cAmount}(期0.60)");
} catch (\Exception $e) {
$this->assert(false, $testName, "异常: " . $e->getMessage());
} finally {
Db::rollback();
}
}
/**
* 测试 2:V3 创客少于 0.10 元截断(A -> B -> C -> D -> E,均为 V3,基数 60)
* 规则验证:
* A: 极差 60.00
* B(3): 第1代 60 * 10% = 6.00
* C(4): 第2代 6 * 10% = 0.60
* D(5): 第3代 0.6 * 10% = 0.06 < 0.10 -> 截断!D 不发放
* E(6): 截断!E 不发放
*/
public function testV3CutoffAtTenCent()
{
$testName = "场景2: V3创客第3代(0.06元 < 0.10元)触发截断,D与E均不发放";
Db::startTrans();
try {
$order = ['id' => 9902, 'user_id' => 7];
$buyerId = 7;
$chain = [
['user_id' => 2, 'level' => 4],
['user_id' => 3, 'level' => 4],
['user_id' => 4, 'level' => 4],
['user_id' => 5, 'level' => 4],
['user_id' => 6, 'level' => 4],
];
$diffResult = [
'seen' => 60.0,
'paid' => [
['user_id' => 2, 'level' => 4, 'cap' => 60.0, 'amount' => 60.0]
]
];
$active = new MockActiveService();
$reward = new MakerPeerReward();
$reward->run($order, $buyerId, $chain, $diffResult, $active);
$b = Db::name('shopro_partner_reward')->where('order_id', 9902)->where('user_id', 3)->find();
$c = Db::name('shopro_partner_reward')->where('order_id', 9902)->where('user_id', 4)->find();
$d = Db::name('shopro_partner_reward')->where('order_id', 9902)->where('user_id', 5)->find();
$e = Db::name('shopro_partner_reward')->where('order_id', 9902)->where('user_id', 6)->find();
$bAmt = $b ? floatval($b['amount']) : 0;
$cAmt = $c ? floatval($c['amount']) : 0;
$pass = ($bAmt == 6.00) && ($cAmt == 0.60) && empty($d) && empty($e);
$this->assert($pass, $testName, "B={$bAmt}(6), C={$cAmt}(0.6), D=" . (empty($d) ? '已截断' : '未截断') . ", E=" . (empty($e) ? '已截断' : '未截断'));
} catch (\Exception $e) {
$this->assert(false, $testName, "异常: " . $e->getMessage());
} finally {
Db::rollback();
}
}
/**
* 测试 3:V6 创客(基数 120 元)3 代级联实发(12.00 -> 1.20 -> 0.12 >= 0.10),第4代截断
*/
public function testV6ThreeGenerationsCascade()
{
$testName = "场景3: V6创客(基数120)实发3代(12.00->1.20->0.12),第4代(0.01<0.10)截断";
Db::startTrans();
try {
$order = ['id' => 9903, 'user_id' => 7];
$buyerId = 7;
$chain = [
['user_id' => 2, 'level' => 7], // Level 7 基数 120 (V6)
['user_id' => 3, 'level' => 7],
['user_id' => 4, 'level' => 7],
['user_id' => 5, 'level' => 7],
['user_id' => 6, 'level' => 7],
];
$diffResult = [
'seen' => 120.0,
'paid' => [
['user_id' => 2, 'level' => 7, 'cap' => 120.0, 'amount' => 120.0]
]
];
$active = new MockActiveService();
$reward = new MakerPeerReward();
$reward->run($order, $buyerId, $chain, $diffResult, $active);
$b = Db::name('shopro_partner_reward')->where('order_id', 9903)->where('user_id', 3)->find();
$c = Db::name('shopro_partner_reward')->where('order_id', 9903)->where('user_id', 4)->find();
$d = Db::name('shopro_partner_reward')->where('order_id', 9903)->where('user_id', 5)->find();
$e = Db::name('shopro_partner_reward')->where('order_id', 9903)->where('user_id', 6)->find();
$bAmt = $b ? floatval($b['amount']) : 0;
$cAmt = $c ? floatval($c['amount']) : 0;
$dAmt = $d ? floatval($d['amount']) : 0;
$pass = ($bAmt == 12.00) && ($cAmt == 1.20) && ($dAmt == 0.12) && empty($e);
$this->assert($pass, $testName, "B={$bAmt}(12), C={$cAmt}(1.2), D={$dAmt}(0.12), E=" . (empty($e) ? '已截断' : '未截断'));
} catch (\Exception $e) {
$this->assert(false, $testName, "异常: " . $e->getMessage());
} finally {
Db::rollback();
}
}
/**
* 测试 4:中间创客未自购场景(A -> B(不活跃) -> C(活跃))
*/
public function testInactiveIntermediaryCascade()
{
$testName = "场景4: 中间平级B 30日无自购被跳过,上级C仍正常获得第2代平级0.60元";
Db::startTrans();
try {
$order = ['id' => 9904, 'user_id' => 7];
$buyerId = 7;
$chain = [
['user_id' => 2, 'level' => 4],
['user_id' => 3, 'level' => 4],
['user_id' => 4, 'level' => 4],
];
$diffResult = [
'seen' => 60.0,
'paid' => [
['user_id' => 2, 'level' => 4, 'cap' => 60.0, 'amount' => 60.0]
]
];
$active = new MockActiveService();
$active->setActive(3, false); // B 不活跃
$active->setActive(4, true); // C 活跃
$reward = new MakerPeerReward();
$reward->run($order, $buyerId, $chain, $diffResult, $active);
$bSkip = Db::name('shopro_partner_reward')
->where('order_id', 9904)
->where('user_id', 3)
->where('status', -1)
->find();
$cReward = Db::name('shopro_partner_reward')
->where('order_id', 9904)
->where('user_id', 4)
->where('status', 1)
->find();
$bSkipped = !empty($bSkip) && floatval($bSkip['amount']) == 0;
$cReceived = !empty($cReward) && floatval($cReward['amount']) == 0.60;
$this->assert($bSkipped && $cReceived, $testName, "B被跳过记录, C正常结算0.60元");
} catch (\Exception $e) {
$this->assert(false, $testName, "异常: " . $e->getMessage());
} finally {
Db::rollback();
}
}
/**
* 测试 5:V1 等级(level 2,基数 20 元)级联实发2代(2.00 -> 0.20),第3代(0.02 < 0.10)截断
*/
public function testV1PeerCascade()
{
$testName = "场景5: V1等级(基数20元)实发2代(2.00->0.20),第3代(0.02<0.10)截断";
Db::startTrans();
try {
$order = ['id' => 9905, 'user_id' => 7];
$buyerId = 7;
$chain = [
['user_id' => 2, 'level' => 2], // Level 2 基数 20 (V1)
['user_id' => 3, 'level' => 2],
['user_id' => 4, 'level' => 2],
['user_id' => 5, 'level' => 2],
];
$diffResult = [
'seen' => 20.0,
'paid' => [
['user_id' => 2, 'level' => 2, 'cap' => 20.0, 'amount' => 20.0]
]
];
$active = new MockActiveService();
$reward = new MakerPeerReward();
$reward->run($order, $buyerId, $chain, $diffResult, $active);
$b = Db::name('shopro_partner_reward')->where('order_id', 9905)->where('user_id', 3)->find();
$c = Db::name('shopro_partner_reward')->where('order_id', 9905)->where('user_id', 4)->find();
$d = Db::name('shopro_partner_reward')->where('order_id', 9905)->where('user_id', 5)->find();
$bAmt = $b ? floatval($b['amount']) : 0;
$cAmt = $c ? floatval($c['amount']) : 0;
$pass = ($bAmt == 2.00) && ($cAmt == 0.20) && empty($d);
$this->assert($pass, $testName, "B={$bAmt}(2), C={$cAmt}(0.2), D=" . (empty($d) ? '已截断' : '未截断'));
} catch (\Exception $e) {
$this->assert(false, $testName, "异常: " . $e->getMessage());
} finally {
Db::rollback();
}
}
/**
* 测试 6:多段平级并存(V1平级 + V3平级在同一推荐链)
*/
public function testMultiSegmentPeers()
{
$testName = "场景6: 混合等级链条多段平级互不干扰独立级联";
Db::startTrans();
try {
$order = ['id' => 9906, 'user_id' => 7];
$buyerId = 7;
$chain = [
['user_id' => 2, 'level' => 2], // V1
['user_id' => 3, 'level' => 2], // V1
['user_id' => 4, 'level' => 4], // V3
['user_id' => 5, 'level' => 4], // V3
['user_id' => 6, 'level' => 4], // V3
];
$diffResult = [
'seen' => 60.0,
'paid' => [
['user_id' => 2, 'level' => 2, 'cap' => 20.0, 'amount' => 20.0],
['user_id' => 4, 'level' => 4, 'cap' => 60.0, 'amount' => 40.0]
]
];
$active = new MockActiveService();
$reward = new MakerPeerReward();
$reward->run($order, $buyerId, $chain, $diffResult, $active);
$bReward = Db::name('shopro_partner_reward')->where('order_id', 9906)->where('user_id', 3)->find();
$dReward = Db::name('shopro_partner_reward')->where('order_id', 9906)->where('user_id', 5)->find();
$eReward = Db::name('shopro_partner_reward')->where('order_id', 9906)->where('user_id', 6)->find();
$bAmount = $bReward ? floatval($bReward['amount']) : 0;
$dAmount = $dReward ? floatval($dReward['amount']) : 0;
$eAmount = $eReward ? floatval($eReward['amount']) : 0;
$this->assert(
$bAmount == 2.00 && $dAmount == 6.00 && $eAmount == 0.60,
$testName,
"B(V1平级1)={$bAmount}(期2.00), D(V3平级1)={$dAmount}(期6.00), E(V3平级2)={$eAmount}(期0.60)"
);
} catch (\Exception $e) {
$this->assert(false, $testName, "异常: " . $e->getMessage());
} finally {
Db::rollback();
}
}
}
// 执行测试
if (php_sapi_name() === 'cli') {
$tester = new MakerPeerTest();
exit($tester->run());
}