test(partner): 增加上线前生产级真实下单全收益与资金规范闭环终审核验脚本

这个提交包含在:
chen
2026-09-26 14:39:48 +08:00
父节点 eb507e6cb5
当前提交 773650f4f7

查看文件

@@ -0,0 +1,575 @@
<?php
namespace tests\partner;
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';
if (is_file(ROOT_PATH . '.env')) {
$env = parse_ini_file(ROOT_PATH . '.env', true);
foreach ($env as $key => $val) {
$name = 'PHP_' . strtoupper($key);
if (is_array($val)) {
foreach ($val as $k => $v) {
putenv("{$name}_" . strtoupper($k) . "={$v}");
}
} else {
putenv("{$name}={$val}");
}
}
}
\think\Config::set(\think\Config::load(APP_PATH . 'config.php'));
\think\Config::set(include APP_PATH . 'database.php', 'database');
\think\Loader::addNamespace('app', APP_PATH);
\think\Loader::addNamespace('addons', ROOT_PATH . 'addons/');
require_once __DIR__ . '/../../addons/shopro/helper/helper.php';
use think\Db;
use app\admin\model\shopro\order\Order as OrderModel;
use app\admin\model\shopro\order\OrderItem;
use app\admin\model\shopro\user\User as UserModel;
use app\admin\model\shopro\user\Address as UserAddress;
use app\admin\model\shopro\commission\Agent as AgentModel;
use app\admin\model\shopro\Pay as PayModel;
use addons\shopro\service\order\OrderCreate;
use addons\shopro\service\pay\PayOper;
use addons\shopro\service\partner\PartnerRewardService;
use addons\shopro\service\partner\DailySettleService;
use addons\shopro\service\partner\PartnerConfig;
use addons\shopro\service\partner\IdentityService;
use addons\shopro\service\partner\RateService;
use addons\shopro\service\user\NicknameService;
class RealOrderFullRewardsAudit
{
private $passed = 0;
private $failed = 0;
private $chain = [];
private $initialBalances = [];
public function run()
{
@ini_set('session.use_cookies', 0);
@\think\Session::init();
echo "====================================================================================\n";
echo " 恒联数通 · 上线前生产级【真实下单 + 全收益链路 + 资金规范】终审大闭环核验\n";
echo "====================================================================================\n\n";
// 1. 构建全收益覆盖测试关系链 (11个节点)
$this->buildFullAuditChain();
// 2. 为买家配置真实收货地址与登录会话
$address = $this->prepareBuyerSessionAndAddress();
// 3. 【真实下单第 1 单】:调用系统官方 OrderCreate 服务完整创建实付 1398.00 元白酒订单
$order1 = $this->executeRealOrderPlacement($address, '第 1 笔真实白酒订单(触发全收益矩阵与推三波峰600)');
// 4. 【真实模拟支付】:调用系统官方 PayOper 状态流转与支付事件
$this->executeRealPayment($order1);
// 5. 【执行收益结算与日结均分】
$this->executeSettlementAndPools($order1);
// 6. 【全收益精算法定核验】:逐项核查所有 15 大类收益与权益
$this->verifyAllRevenues($order1);
// 7. 【方案 B 核心资金闭环严苛审计】:所有收益必须入账用户钱包余额 money,commission 严格为零
$this->verifyWalletBalanceAndLogs($order1);
// 8. 【真实下单第 2 单】:验证推三返一循环重置为首档 398 元及多单稳定性
$this->verifySecondOrderPush3CycleReset($address);
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++;
}
}
/**
* 构建覆盖全奖项的 11 节点关系链拓扑:
* K2 (区县平级)
* └── K1 (区县统筹)
* └── V2 (酒道馆平级)
* └── V1 (酒道馆运营)
* └── M_over_2 (创客V1,越级第二层拦截)
* └── M_overtaken (创客V3,被反超创客卓越奖)
* └── M_diff2 (创客V6,极差高阶)
* └── M_diff1_peer (创客V2平级)
* └── M_diff1 (创客V2,极差低阶)
* └── C (推荐人,推三返一)
* └── D (买家本人,自购兑换券)
*/
private function buildFullAuditChain()
{
echo "【一、构建上线前生产级全收益覆盖关系链拓扑 (11 节点)】\n";
$nodesConfig = [
'k2' => ['mobile' => '18800010009', 'role' => 'county', 'level' => 1, 'is_county' => 1, 'is_venue' => 0, 'desc' => '区县代理平级 K2'],
'k1' => ['mobile' => '18800010008', 'role' => 'county', 'level' => 1, 'is_county' => 1, 'is_venue' => 0, 'desc' => '区县代理统筹 K1'],
'v2' => ['mobile' => '18800010007', 'role' => 'venue', 'level' => 1, 'is_county' => 0, 'is_venue' => 1, 'desc' => '酒道馆实体平级 V2'],
'v1' => ['mobile' => '18800010006', 'role' => 'venue', 'level' => 1, 'is_county' => 0, 'is_venue' => 1, 'desc' => '酒道馆实体运营 V1'],
'm_over_2' => ['mobile' => '18800010005', 'role' => 'maker', 'level' => 2, 'is_county' => 0, 'is_venue' => 0, 'desc' => '创客V1 (越级第2层拦截)'],
'm_overtaken' => ['mobile' => '18800010004', 'role' => 'maker', 'level' => 4, 'is_county' => 0, 'is_venue' => 0, 'desc' => '创客V3 (下级超越卓越奖)'],
'm_diff2' => ['mobile' => '18800010003', 'role' => 'maker', 'level' => 7, 'is_county' => 0, 'is_venue' => 0, 'desc' => '创客V6 (极差高水位120)'],
'm_diff1_peer' => ['mobile' => '18800010002', 'role' => 'maker', 'level' => 3, 'is_county' => 0, 'is_venue' => 0, 'desc' => '创客V2 (同级协同平级)'],
'm_diff1' => ['mobile' => '18800010001', 'role' => 'maker', 'level' => 3, 'is_county' => 0, 'is_venue' => 0, 'desc' => '创客V2 (极差低水位40)'],
'c' => ['mobile' => '18800010010', 'role' => 'taster', 'level' => 1, 'is_county' => 0, 'is_venue' => 0, 'desc' => '直推推荐人 C (品酒师待推三)'],
'd' => ['mobile' => '18800010000', 'role' => 'buyer', 'level' => 1, 'is_county' => 0, 'is_venue' => 0, 'desc' => '买家 D (自购1398白酒)'],
];
$keys = array_keys($nodesConfig);
$count = count($keys);
for ($i = 0; $i < $count; $i++) {
$key = $keys[$i];
$cfg = $nodesConfig[$key];
$mobile = $cfg['mobile'];
$user = UserModel::where('mobile', $mobile)->find();
if (!$user) {
$nickname = NicknameService::generate($mobile);
$user = UserModel::create([
'username' => 'prod_audit_' . $key,
'nickname' => $nickname,
'mobile' => $mobile,
'parent_user_id' => 0,
'status' => 'normal',
'money' => 0.00,
'commission' => 0.00,
'jointime' => time()
]);
}
// 绑定分销身份与保活状态
$agent = AgentModel::where('user_id', $user->id)->find();
$seq = ($key === 'c') ? 2 : 0; // 推荐人设为 2,第 1 单触发第 3 单波峰 600 元!
if (!$agent) {
$agent = AgentModel::create([
'user_id' => $user->id,
'level' => $cfg['level'],
'status' => 'normal',
'is_venue' => $cfg['is_venue'],
'is_county' => $cfg['is_county'],
'direct_order_seq' => $seq,
'last_self_order_time' => time(),
'createtime' => time()
]);
} else {
$agent->level = $cfg['level'];
$agent->status = 'normal';
$agent->is_venue = $cfg['is_venue'];
$agent->is_county = $cfg['is_county'];
$agent->direct_order_seq = $seq;
$agent->last_self_order_time = time();
$agent->save();
}
$this->chain[$key] = $user;
}
// 严格串联父子关系链:D -> C -> M1 -> M1_peer -> M2 -> M_over -> M_over_2 -> V1 -> V2 -> K1 -> K2 -> 0
$parentPairs = [
'd' => 'c',
'c' => 'm_diff1',
'm_diff1' => 'm_diff1_peer',
'm_diff1_peer' => 'm_diff2',
'm_diff2' => 'm_overtaken',
'm_overtaken' => 'm_over_2',
'm_over_2' => 'v1',
'v1' => 'v2',
'v2' => 'k1',
'k1' => 'k2',
'k2' => null,
];
foreach ($parentPairs as $childKey => $parentKey) {
$child = $this->chain[$childKey];
$parentId = $parentKey ? $this->chain[$parentKey]->id : 0;
Db::name('user')->where('id', $child->id)->update(['parent_user_id' => $parentId]);
$child->parent_user_id = $parentId;
}
$this->assert(count($this->chain) === 11, "成功构建覆盖全部 11 个角色的完整拓扑关系链");
echo "\n";
}
/**
* 2. 准备买家收货地址与会话
*/
private function prepareBuyerSessionAndAddress()
{
echo "【二、初始化买家登录会话与真实收货地址】\n";
$buyer = $this->chain['d'];
// 模拟前台会话登录
\app\common\library\Auth::instance()->direct($buyer->id);
$currentUser = auth_user();
$this->assert($currentUser && $currentUser->id == $buyer->id, "买家 D (#{$buyer->id}) 成功通过 Auth 登录验证");
// 确保有收货地址
$address = UserAddress::where('user_id', $buyer->id)->where('is_default', 1)->find();
if (!$address) {
$address = UserAddress::create([
'user_id' => $buyer->id,
'consignee' => '恒联验收员',
'mobile' => $buyer->mobile,
'province_name' => '北京市',
'city_name' => '北京市',
'district_name' => '朝阳区',
'province_id' => 11,
'city_id' => 1101,
'district_id' => 110101,
'address' => '恒联数通示范酒道馆A座808室',
'is_default' => 1,
'createtime' => time(),
'updatetime' => time(),
]);
}
$this->assert($address->id > 0, "买家 D 默认收货地址就绪 (#{$address->id}, {$address->address})");
echo "\n";
return $address;
}
/**
* 3. 调用系统官方 OrderCreate 下单
*/
private function executeRealOrderPlacement($address, $title)
{
echo "【三、执行系统官方 OrderCreate 真实下单: {$title}】\n";
$buyer = $this->chain['d'];
// 记录下单前各节点钱包余额,用于严格资金审计
$this->recordInitialBalances();
// 查验商品与规格
$goodsId = 34;
$skuPriceId = 94;
$goodsSku = Db::name('shopro_goods_sku_price')->where('id', $skuPriceId)->find();
$this->assert($goodsSku && $goodsSku['price'] == '1398.00', "白酒商品 34 规格 94 存在且标价 1398.00 元");
$initialStock = intval($goodsSku['stock']);
// 组装前台真实提交的请求参数
$params = [
'order_type' => 'goods',
'goods_list' => [
[
'goods_id' => $goodsId,
'goods_num' => 1,
'goods_sku_price_id' => $skuPriceId,
]
],
'address_id' => $address->id,
'remark' => '生产上线前全收益真实下单核验单',
];
// 实例化系统官方 OrderCreate 并执行价格试算与订单持久化
$orderCreate = new OrderCreate($params);
$calcResult = $orderCreate->calc('create');
$this->assert(bccomp((string)$calcResult['pay_fee'], '1398.00', 2) === 0, "OrderCreate 试算实付金额精准为 1398.00 元");
$this->assert(bccomp((string)$calcResult['dispatch_amount'], '0.00', 2) === 0, "包邮运费模板试算运费为 0.00 元");
$order = $orderCreate->create($calcResult);
$this->assert($order && $order->id > 0, "系统官方 OrderCreate::create 成功创建真实订单 (#{$order->id}, {$order->order_sn})");
// 校验订单明细真实包含白酒商品
$orderItem = Db::name('shopro_order_item')->where('order_id', $order->id)->where('goods_id', $goodsId)->find();
$this->assert($orderItem && $orderItem['goods_num'] == 1, "订单明细真实持久化包含商品 #{$goodsId} 规格 #{$skuPriceId} 共 1 件");
echo "\n";
return $order;
}
/**
* 4. 模拟真实支付回调
*/
private function executeRealPayment($order)
{
echo "【四、执行系统官方 PayOper 真实在线支付状态流转】\n";
$payOper = new PayOper();
// 写入微信预支付并支付成功的交易流水记录
$transactionId = '420000' . date('YmdHis') . mt_rand(1000, 9999);
$pay = $payOper->addPay($order, [
'order_type' => 'order',
'pay_type' => 'wechat',
'pay_fee' => $order->pay_fee,
'real_fee' => $order->pay_fee,
'transaction_id' => $transactionId,
'payment_json' => [],
'status' => PayModel::PAY_STATUS_PAID
]);
$this->assert($pay && $pay->id > 0, "生成真实微信支付流水记录 (#{$pay->id}, 交易号: {$transactionId})");
// 执行检测与确认支付
$paidOrder = $payOper->checkAndPaid($order, 'order', 'online');
$this->assert($paidOrder->status === OrderModel::STATUS_PAID, "订单状态成功流转为 STATUS_PAID (已支付)");
$this->assert(floatval($paidOrder->remain_pay_fee) == 0.00, "订单剩余待支付金额严格为 0.00 元");
$paidDisplay = is_numeric($paidOrder->paid_time) ? date('Y-m-d H:i:s', intval($paidOrder->paid_time)) : (string)$paidOrder->paid_time;
$this->assert(!empty($paidOrder->paid_time), "订单准确记录支付时间戳: {$paidDisplay}");
echo "\n";
}
/**
* 5. 执行结算与全网均分池
*/
private function executeSettlementAndPools($order)
{
echo "【五、执行即时分润结算与全网三大均分奖池】\n";
$rewardService = new PartnerRewardService();
$settleOk = $rewardService->settleOrder($order->id);
$this->assert($settleOk === true, "PartnerRewardService::settleOrder 订单即时奖结算执行成功");
// 执行日结/分钟全网均分奖池
$dailyService = new DailySettleService();
$poolResult = $dailyService->runMinute();
$this->assert(is_array($poolResult), "DailySettleService::runMinute 全网均分调度执行成功");
echo "\n";
}
/**
* 6. 全收益项深度法定核验
*/
private function verifyAllRevenues($order)
{
echo "【六、全收益中心奖项与规则全面法定核查】\n";
$orderId = $order->id;
$rewards = Db::name('shopro_partner_reward')->where('order_id', $orderId)->select();
$rewardMap = [];
foreach ($rewards as $r) {
$rewardMap[$r['reward_type']][] = $r;
echo " -> 奖项: {$r['reward_type']} | 受益人: #{$r['user_id']} | 金额: ¥{$r['amount']} | 状态: {$r['status']} | 备注: {$r['ext']}\n";
}
// ① 推三返一:C 作为推荐人(seq: 2 -> 3,获得第 3 档波峰 600 元)
$push3 = $rewardMap['push3'][0] ?? null;
$this->assert($push3 !== null, "1. 包含推荐开拓奖 (push3)");
if ($push3) {
$this->assert($push3['user_id'] == $this->chain['c']->id, " - 受益人为直推人 C (#{$this->chain['c']->id})");
$this->assert(bccomp((string)$push3['amount'], '600.00', 2) === 0, " - 推三返一第3单金额准确为 ¥600.00 (实际: ¥{$push3['amount']})");
$this->assert(intval($push3['status']) === 1, " - 奖励状态严格为已入账 (status = 1)");
$agentC = AgentModel::where('user_id', $this->chain['c']->id)->find();
$this->assert(intval($agentC->direct_order_seq) === 3, " - 推荐人 direct_order_seq 准确由 2 递增至 3");
}
// ② 创客极差奖 (maker_diff):M_diff1 (V2, 40) + M_diff2 (V6, 120 - 40 = 80)
$diffList = $rewardMap['maker_diff'] ?? [];
$paidDiffList = array_values(array_filter($diffList, function ($item) {
return intval($item['status']) === 1;
}));
$this->assert(count($paidDiffList) === 2, "2. 包含创客进阶极差入账流水 (共 " . count($paidDiffList) . " 笔)");
$diffM1 = null; $diffM2 = null;
foreach ($paidDiffList as $item) {
if ($item['user_id'] == $this->chain['m_diff1']->id) $diffM1 = $item;
if ($item['user_id'] == $this->chain['m_diff2']->id) $diffM2 = $item;
}
$this->assert($diffM1 && bccomp((string)$diffM1['amount'], '40.00', 2) === 0, " - 创客 M1 (V2) 获得基数差额 ¥40.00 (40 - 0)");
$this->assert($diffM2 && bccomp((string)$diffM2['amount'], '80.00', 2) === 0, " - 创客 M2 (V6) 获得基数差额 ¥80.00 (120 - 40)");
$totalDiff = array_sum(array_column($diffList, 'amount'));
$this->assert(bccomp((string)$totalDiff, '120.00', 2) === 0, " - 创客极差全链总额精准封顶 ¥120.00,绝无超额溢出");
// ③ 创客协同平级奖 (maker_peer):M_diff1_peer (同为 V2,获得 M1 的 40 × 10% = 4.00)
$makerPeer = $rewardMap['maker_peer'][0] ?? null;
$this->assert($makerPeer !== null, "3. 包含创客同级协同平级奖 (maker_peer)");
if ($makerPeer) {
$this->assert($makerPeer['user_id'] == $this->chain['m_diff1_peer']->id, " - 受益人为同级上位创客 M_peer (#{$this->chain['m_diff1_peer']->id})");
$this->assert(bccomp((string)$makerPeer['amount'], '4.00', 2) === 0, " - 协同奖金额精准为 40 × 10% = ¥4.00 (实际: ¥{$makerPeer['amount']})");
}
// ④ 创客卓越超越奖 (maker_overtaken):M_overtaken (V3被下级V6反超,获得 120 × 5% = 6.00)
$overtaken = $rewardMap['maker_overtaken'][0] ?? null;
$this->assert($overtaken !== null, "4. 包含创客卓越超越奖 (maker_overtaken)");
if ($overtaken) {
$this->assert($overtaken['user_id'] == $this->chain['m_overtaken']->id, " - 受益人为被反超创客 M_overtaken (#{$this->chain['m_overtaken']->id})");
$this->assert(bccomp((string)$overtaken['amount'], '6.00', 2) === 0, " - 卓越奖金额精准为 120 × 5% = ¥6.00 (实际: ¥{$overtaken['amount']})");
}
// ⑤ 卓越奖单层风控截断:M_over_2 不得再次享受卓越奖
$overtakenList = $rewardMap['maker_overtaken'] ?? [];
$this->assert(count($overtakenList) === 1, "5. 卓越奖严格限制单层,第二层创客 M_over_2 绝无重发 (总笔数: " . count($overtakenList) . ")");
// ⑥ 酒道馆运营奖 (team_venue):V1 获得 50.00
$teamVenue = $rewardMap['team_venue'][0] ?? null;
$this->assert($teamVenue !== null, "6. 包含酒道馆团队管理奖 (team_venue)");
if ($teamVenue) {
$this->assert($teamVenue['user_id'] == $this->chain['v1']->id, " - 受益人为最近酒道馆 V1 (#{$this->chain['v1']->id})");
$this->assert(bccomp((string)$teamVenue['amount'], '50.00', 2) === 0, " - 酒道馆管理奖金额精准为 ¥50.00");
}
// ⑦ 酒道馆协同平级奖 (venue_peer):V2 获得 50 × 10% = 5.00
$venuePeer = $rewardMap['venue_peer'][0] ?? null;
$this->assert($venuePeer !== null, "7. 包含酒道馆平级协同奖 (venue_peer)");
if ($venuePeer) {
$this->assert($venuePeer['user_id'] == $this->chain['v2']->id, " - 受益人为上位酒道馆 V2 (#{$this->chain['v2']->id})");
$this->assert(bccomp((string)$venuePeer['amount'], '5.00', 2) === 0, " - 酒道馆平级金额精准为 50 × 10% = ¥5.00");
}
// ⑧ 区县代理统筹奖 (team_county):K1 获得 50.00(有馆拆分)
$teamCounty = $rewardMap['team_county'][0] ?? null;
$this->assert($teamCounty !== null, "8. 包含区县代理统筹奖 (team_county)");
if ($teamCounty) {
$this->assert($teamCounty['user_id'] == $this->chain['k1']->id, " - 受益人为最近区县 K1 (#{$this->chain['k1']->id})");
$this->assert(bccomp((string)$teamCounty['amount'], '50.00', 2) === 0, " - 有馆并存时区县精准拆分为 ¥50.00");
}
// ⑨ 区县代理协同平级奖 (county_peer):K2 获得 50 × 10% = 5.00
$countyPeer = $rewardMap['county_peer'][0] ?? null;
$this->assert($countyPeer !== null, "9. 包含区县代理平级协同奖 (county_peer)");
if ($countyPeer) {
$this->assert($countyPeer['user_id'] == $this->chain['k2']->id, " - 受益人为上位区县 K2 (#{$this->chain['k2']->id})");
$this->assert(bccomp((string)$countyPeer['amount'], '5.00', 2) === 0, " - 区县平级金额精准为 50 × 10% = ¥5.00");
}
// ⑩ 产品兑换券计划 (voucher_grant):买家 D 获得 1398 × 1.5 = 2097.00 元
$plan = Db::name('shopro_partner_voucher_plan')->where('order_id', $orderId)->find();
$this->assert($plan !== null, "10. 包含产品兑换券释放计划 (voucher_grant)");
if ($plan) {
$this->assert($plan['user_id'] == $this->chain['d']->id, " - 兑换券受益人为买家本人 D (#{$this->chain['d']->id})");
$this->assert(bccomp((string)$plan['total_amount'], '2097.00', 2) === 0, " - 兑换券释放总额精准为 1398 × 1.5 = 2097.00 (实际: {$plan['total_amount']})");
$this->assert(intval($plan['total_days']) === 365, " - 释放周期严格为 365 天");
}
// ⑪ 全网加权分红池(酒道馆均分 venue_share、区县均分 county_share、DMEPA均分 madow_share)
$vShares = Db::name('shopro_partner_reward')->where('reward_type', 'venue_share')->where('ext', 'like', "%{$orderId}%")->select();
$this->assert(count($vShares) > 0, "11. 酒道馆日结分红池成功结算 (共 " . count($vShares) . " 家酒道馆获得均分)");
$cShares = Db::name('shopro_partner_reward')->where('reward_type', 'county_share')->where('ext', 'like', "%{$orderId}%")->select();
$this->assert(count($cShares) > 0, "12. 区县代理分红池成功结算 (共 " . count($cShares) . " 家区县获得均分)");
// ⑫ DMEPA 实时汇率递增
$rateService = new RateService();
$rate = $rateService->currentRate();
$this->assert($rate > 0, "13. DMEPA 实时动态汇率联动更新 (当前汇率: {$rate})");
// ⑬ 30天保活与倒计时
$agentD = AgentModel::where('user_id', $this->chain['d']->id)->find();
$attached = IdentityService::attachAgent($agentD);
$this->assert($attached['active_30d'] === true && $attached['active_status'] === 'active', "14. 买家 D 自购激活 30 天有效保活 (active_status='active')");
$this->assert($attached['days_remaining'] == 30, " - 剩余天数满额显示 30 天");
// 直推上级双向保活
$rawPaid = is_object($order) ? ($order->getData('paid_time') ?: $order['paid_time']) : ($order['paid_time'] ?? null);
$orderPaidTs = (is_numeric($rawPaid) && intval($rawPaid) > 100000000) ? intval($rawPaid) : strtotime((string)$rawPaid);
$agentC = AgentModel::where('user_id', $this->chain['c']->id)->find();
$this->assert($agentC->last_self_order_time >= $orderPaidTs, " - 直推推荐人 C 同样被直推订单双向保活激活");
echo "\n";
}
/**
* 7. 方案 B 核心资金闭环严苛审计
*/
private function verifyWalletBalanceAndLogs($order)
{
echo "【七、方案 B 一体化大余额闭环严苛资金审计】\n";
// 预期即时现金收益对照表
$expectedInstant = [
'c' => '600.00',
'm_diff1' => '40.00',
'm_diff1_peer' => '4.00',
'm_diff2' => '80.00',
'm_overtaken' => '6.00',
'm_over_2' => '0.00',
'v1' => '50.00',
'v2' => '5.00',
'k1' => '50.00',
'k2' => '5.00',
'd' => '0.00',
];
foreach ($expectedInstant as $key => $expectAmount) {
$user = $this->chain[$key];
$freshUser = Db::name('user')->where('id', $user->id)->find();
$moneyDiff = bcsub((string)$freshUser['money'], (string)$this->initialBalances[$key]['money'], 2);
// 包含均分池时大于等于即时预期,无均分池时严格相等
if (in_array($key, ['v1', 'v2', 'k1', 'k2'])) {
$this->assert(floatval($moneyDiff) >= floatval($expectAmount), "节点 {$key} (#{$user->id}) 钱包余额增加包含即时 {$expectAmount} + 均分池分润 (实际净增: {$moneyDiff})");
} else {
$this->assert(bccomp((string)$moneyDiff, (string)$expectAmount, 2) === 0, "节点 {$key} (#{$user->id}) 钱包余额 (money) 严格净增 ¥{$expectAmount} (实际净增: ¥{$moneyDiff})");
}
// 资金合规硬约束:commission 必须严格为 0.00
$this->assert(bccomp((string)$freshUser['commission'], '0.00', 2) === 0, "节点 {$key} (#{$user->id}) commission 严格为 0.00,杜绝走入废弃钱包");
// 查验钱包流水表 shopro_user_wallet_log 字段结构
if (floatval($expectAmount) > 0) {
$log = Db::name('shopro_user_wallet_log')
->where('user_id', $user->id)
->where('type', 'money')
->order('id', 'desc')
->find();
$this->assert($log !== null && floatval($log['amount']) > 0, "节点 {$key} 成功记录合法钱包变动流水 (事件: {$log['event']}, 金额: +{$log['amount']}, type: {$log['type']})");
}
}
echo "\n";
}
/**
* 8. 真实下单第 2 单:验证推三返一循环重置为首档 398 元
*/
private function verifySecondOrderPush3CycleReset($address)
{
echo "【八、真实下单第 2 单:验证推荐提成 3 档循环重置为首档 398 元】\n";
// 买家 D 再次下单实付 1398.00 元白酒
$order2 = $this->executeRealOrderPlacement($address, '第 2 笔真实白酒订单(验证推三返一循环重置为 398 元)');
$this->executeRealPayment($order2);
$this->executeSettlementAndPools($order2);
// 查验该单推三返一
$push3Order2 = Db::name('shopro_partner_reward')
->where('order_id', $order2->id)
->where('reward_type', 'push3')
->find();
$this->assert($push3Order2 !== null, "第 2 单成功生成推三返一奖励");
if ($push3Order2) {
$this->assert(bccomp((string)$push3Order2['amount'], '398.00', 2) === 0, "推三返一成功循环重置回第 1 档 ¥398.00 (实际: ¥{$push3Order2['amount']})");
$this->assert($push3Order2['user_id'] == $this->chain['c']->id, "推三返一受益人仍为推荐人 C (#{$this->chain['c']->id})");
}
$agentC = AgentModel::where('user_id', $this->chain['c']->id)->find();
$this->assert(intval($agentC->direct_order_seq) === 4, "推荐人 C direct_order_seq 成功累加至 4 (第 2 轮第 1 单)");
echo "\n";
}
private function recordInitialBalances()
{
$this->initialBalances = [];
foreach ($this->chain as $k => $u) {
$fresh = Db::name('user')->where('id', $u->id)->find();
$this->initialBalances[$k] = [
'money' => floatval($fresh['money'] ?? 0),
'commission' => floatval($fresh['commission'] ?? 0)
];
}
}
}
$audit = new RealOrderFullRewardsAudit();
exit($audit->run());