$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 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\user\NicknameService; use addons\shopro\service\user\UserAuth; class FullOrderRewardVerification { private $passed = 0; private $failed = 0; private $logs = []; public function run() { echo "========================================================\n"; echo " 恒联数通 · 上线前全收益链路与规范核算终审验收\n"; echo "========================================================\n\n"; // 1. 验证规范昵称生成 $this->verifyNicknameGeneration(); // 2. 准备验收测试关系链 (A: 顶级馆兼县 -> B: 创客V2 -> C: 品酒师推三返一 -> D: 买家) $chain = $this->prepareTestChain(); // 3. 执行下单与支付 $order = $this->createAndPayOrder($chain); // 4. 验证即时奖励 (推三返一、创客极差、团队管理奖、兑换券计划) $this->verifyInstantRewards($order, $chain); // 5. 验证 30 天保活与秒级倒计时恢复 (方案 A) $this->verifyActiveCountdown($order, $chain); // 6. 执行并验证日结/分钟均分奖池 (酒道馆均分、区县均分、DMEPA均分) $this->verifyShareRewards($order, $chain); // 7. 方案 B 核心规范校验:所有收益必须入账用户钱包余额 money $this->verifySchemeBWalletIntegrity($chain); 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. 验证新规范昵称生成 (HL+手机尾号,若重复追加数字) */ private function verifyNicknameGeneration() { echo "【一、新用户注册规范昵称规则校验】\n"; $mobileTest = '18900005758'; $nickname1 = NicknameService::generate($mobileTest); $this->assert(strpos($nickname1, 'HL5758') === 0, "手机号尾号 5758 生成规范前缀 HL5758 (实际: {$nickname1})"); // 模拟已存在重名 $existing = Db::name('user')->where('nickname', 'HL5758')->value('id'); if (!$existing) { Db::name('user')->insert([ 'username' => 'test_dummy_5758', 'nickname' => 'HL5758', 'mobile' => '13000005758', 'status' => 'normal', 'jointime' => time() ]); } $nickname2 = NicknameService::generate($mobileTest); $this->assert($nickname2 === 'HL57581' || $nickname2 === 'HL57582', "重名时自动追加递增数字 (实际: {$nickname2})"); echo "\n"; } /** * 2. 构建或复用测试关系链 */ private function prepareTestChain() { echo "【二、检查与构建全收益验收关系链】\n"; // 顶级 A (用户 20): 创客V5, is_venue=1, is_county=1 (馆兼县) $userA = UserModel::get(20); $this->assert($userA !== null, "顶级节点用户 20 存在"); // B: 创客 (用户 22): level=3 (创客V2), parent=20 $userB = UserModel::get(22); $this->assert($userB !== null, "中间创客节点用户 22 存在"); // C: 品酒师 (直推人,用于推三返一测试): 确保 parent=22 $userC = UserModel::where('mobile', '13800009991')->find(); if (!$userC) { $userC = UserModel::create([ 'username' => 'tester_push3_c', 'nickname' => '推三推荐人C', 'mobile' => '13800009991', 'parent_user_id' => 22, 'status' => 'normal', 'money' => 0.00, 'commission' => 0.00, 'jointime' => time() ]); } $agentC = Db::name('shopro_commission_agent')->where('user_id', $userC->id)->find(); if (!$agentC) { Db::name('shopro_commission_agent')->insert([ 'user_id' => $userC->id, 'level' => 1, 'status' => 'normal', 'direct_order_seq' => 2, // 设为 2,下一单正好是第 3 单触发推三返一! 'last_self_order_time' => time(), 'createtime' => time() ]); } else { Db::name('shopro_commission_agent')->where('user_id', $userC->id)->update([ 'direct_order_seq' => 2, 'last_self_order_time' => time() ]); } $this->assert(true, "直推人 C (#{$userC->id}) 已就绪,direct_order_seq=2,等待第3单触发返还"); // D: 买家 (新下单用户): parent=C $userD = UserModel::where('mobile', '13800009992')->find(); if (!$userD) { $nicknameD = NicknameService::generate('13800009992'); $userD = UserModel::create([ 'username' => 'tester_buyer_d', 'nickname' => $nicknameD, 'mobile' => '13800009992', 'parent_user_id' => $userC->id, 'status' => 'normal', 'money' => 0.00, 'commission' => 0.00, 'jointime' => time() ]); } else { $userD->parent_user_id = $userC->id; $userD->save(); } $this->assert($userD->nickname === 'HL9992', "买家 D (#{$userD->id}) 规范昵称符合 HL+尾号: {$userD->nickname}"); echo "\n"; return [ 'a' => $userA, 'b' => $userB, 'c' => $userC, 'd' => $userD, ]; } /** * 3. 创建并支付 1398.00 元合格白酒订单 */ private function createAndPayOrder($chain) { echo "【三、模拟真实合格订单下单与支付】\n"; $buyer = $chain['d']; $orderSn = 'HLTEST' . date('YmdHis') . mt_rand(100, 999); $payFee = '1398.00'; $paidTime = time(); $order = OrderModel::create([ 'order_sn' => $orderSn, 'user_id' => $buyer->id, 'type' => 'goods', 'status' => 'paid', 'pay_fee' => $payFee, 'goods_amount' => $payFee, 'dispatch_amount' => '0.00', 'pay_mode' => 'online', 'paid_time' => $paidTime, 'createtime' => $paidTime, 'updatetime' => $paidTime, 'ext' => json_encode(['from_app' => 'online_acceptance']) ]); OrderItem::create([ 'order_id' => $order->id, 'user_id' => $buyer->id, 'goods_id' => 34, 'goods_title' => '莫高飞天(持花飞天)2瓶', 'goods_image' => '/uploads/20260921/9ff2018f2d99a2134c36066e88c8b073.png', 'goods_sku_price_id' => 94, 'goods_price' => $payFee, 'goods_num' => 1, 'pay_fee' => $payFee, 'dispatch_fee' => '0.00', 'dispatch_type' => 'express', 'dispatch_status' => 0, 'aftersale_status' => 0, 'createtime' => $paidTime, 'updatetime' => $paidTime, 'ext' => json_encode(['is_commission' => 1]) ]); $this->assert($order->id > 0, "成功生成实付 1398.00 元白酒合格订单 (#{$order->id}, {$orderSn})"); // 记录结算前各用户钱包余额 $this->recordBeforeBalances($chain); // 触发即时收益结算 $rewardService = new PartnerRewardService(); $settleResult = $rewardService->settleOrder($order->id); $this->assert($settleResult === true, "PartnerRewardService::settleOrder 结算执行成功"); echo "\n"; return $order; } private function recordBeforeBalances($chain) { $this->chainBalances = []; foreach ($chain as $k => $u) { $fresh = Db::name('user')->where('id', $u->id)->find(); $this->chainBalances[$k] = [ 'money' => floatval($fresh['money']), 'commission' => floatval($fresh['commission']) ]; } } /** * 4. 验证即时奖励与收益明细 */ private function verifyInstantRewards($order, $chain) { echo "【四、核查订单产生的所有即时奖项明细】\n"; $orderId = $order->id; $rewards = Db::name('shopro_partner_reward')->where('order_id', $orderId)->select(); $this->assert(count($rewards) >= 4, "订单产生完整的即时奖励流水(共 " . count($rewards) . " 笔)"); $rewardMap = []; foreach ($rewards as $r) { $rewardMap[$r['reward_type']][] = $r; echo " -> 奖项: {$r['reward_type']} | 受益人: #{$r['user_id']} | 金额: ¥{$r['amount']} | 状态: {$r['status']} | 备注: {$r['ext']}\n"; } // ① 验证推三返一 (push3) $push3 = $rewardMap['push3'][0] ?? null; $this->assert($push3 !== null, "包含推三返一奖项"); if ($push3) { $this->assert($push3['user_id'] == $chain['c']->id, "推三返一受益人为直推人 C (#{$chain['c']->id})"); $this->assert(floatval($push3['amount']) == 600.00, "推三返一第3单返还金额准确为 ¥600.00 (实际: ¥{$push3['amount']})"); $this->assert($push3['status'] == 1, "推三返一状态为已入账 (status=1)"); } // ② 验证酒道馆团队管理奖 (team_venue) 及 平级奖 (venue_peer) $venueReward = $rewardMap['team_venue'][0] ?? null; $this->assert($venueReward !== null, "包含酒道馆团队管理奖"); if ($venueReward) { $this->assert(floatval($venueReward['amount']) == 50.00, "酒道馆管理奖金额为 ¥50.00 (实际: ¥{$venueReward['amount']})"); $this->assert($venueReward['user_id'] == $chain['b']->id, "酒道馆受益人为链上最近酒道馆 B (#{$chain['b']->id})"); } $venuePeerReward = $rewardMap['venue_peer'][0] ?? null; $this->assert($venuePeerReward !== null, "包含酒道馆平级奖 (上级同级酒道馆触发平级分润)"); if ($venuePeerReward) { $this->assert(floatval($venuePeerReward['amount']) == 5.00, "酒道馆第1代平级奖 50×10% = ¥5.00 (实际: ¥{$venuePeerReward['amount']})"); $this->assert($venuePeerReward['user_id'] == $chain['a']->id, "酒道馆平级受益人为上级酒道馆 A (#{$chain['a']->id})"); } // ③ 验证创客极差奖 (maker_diff) $diffRewards = $rewardMap['maker_diff'] ?? []; $this->assert(count($diffRewards) >= 2, "包含至少2级创客极差奖流水 (共 " . count($diffRewards) . " 笔)"); $diffTotal = array_sum(array_column($diffRewards, 'amount')); $this->assert($diffTotal == 100.00, "创客极差逐级瓜分总额准确为 ¥100.00 (40+60, 实际: ¥{$diffTotal})"); // ④ 验证区县团队管理奖 (team_county) $countyReward = $rewardMap['team_county'][0] ?? null; $this->assert($countyReward !== null, "包含区县团队管理奖"); if ($countyReward) { $this->assert(floatval($countyReward['amount']) == 50.00, "区县管理奖金额为 ¥50.00 (实际: ¥{$countyReward['amount']})"); $this->assert($countyReward['user_id'] == $chain['a']->id, "区县受益人为链上最近区县 A (#{$chain['a']->id})"); } // ④ 验证兑换券释放计划 (voucher_grant) $plan = Db::name('shopro_partner_voucher_plan')->where('order_id', $orderId)->find(); $this->assert($plan !== null, "兑换券释放计划已生成"); if ($plan) { $this->assert($plan['user_id'] == $chain['d']->id, "兑换券受益人为买家本人 D (#{$chain['d']->id})"); $this->assert(floatval($plan['total_amount']) == 2097.00, "1398 实付 × 1.5倍 释放兑换券总额为 2097.00 (实际: {$plan['total_amount']})"); $this->assert(intval($plan['total_days']) == 365, "兑换券释放周期为 365 天"); } echo "\n"; } /** * 5. 验证 30 天保活与秒级倒计时恢复 */ private function verifyActiveCountdown($order, $chain) { echo "【五、核验 30 天保活与秒级倒计时恢复 (方案 A)】\n"; $buyerId = $chain['d']->id; $agentD = Db::name('shopro_commission_agent')->where('user_id', $buyerId)->find(); $this->assert(!empty($agentD['last_self_order_time']), "买家 D last_self_order_time 已成功激活"); // 调用 IdentityService 检查输出的时间戳与天数 $agentModelD = \app\admin\model\shopro\commission\Agent::where('user_id', $buyerId)->find(); $attached = IdentityService::attachAgent($agentModelD); $this->assert($attached['active_30d'] === true, "买家 D active_30d 为 true (活跃有效)"); $this->assert($attached['active_status'] === 'active', "买家 D active_status 为 'active' (正常活跃)"); $this->assert($attached['days_remaining'] == 30, "买家 D 剩余天数满额显示 30 天 (实际: {$attached['days_remaining']})"); // 校验到期时间戳:订单支付时刻 + 30 * 86400 (方案 A 精确顺延) $rawPaidOrder = is_object($order) ? ($order->getData('paid_time') ?: $order['paid_time']) : ($order['paid_time'] ?? null); $paidTimestamp = (is_numeric($rawPaidOrder) && intval($rawPaidOrder) > 100000000) ? intval($rawPaidOrder) : strtotime((string)$rawPaidOrder); $expectedExpire = $paidTimestamp + 30 * 86400; $this->assert($attached['expire_time'] == $expectedExpire, "到期时间戳精确顺延720小时,绝无零点截断 (实际: {$attached['expire_time']}, 期望: {$expectedExpire})"); // 验证直推人 C 也获得双向保活更新 $agentC = Db::name('shopro_commission_agent')->where('user_id', $chain['c']->id)->find(); $this->assert($agentC['last_self_order_time'] >= $paidTimestamp, "直推上级 C 同样被直推订单双向激活保活"); echo "\n"; } /** * 6. 执行并验证日结/分钟均分奖池 (酒道馆均分、区县均分、DMEPA均分) */ private function verifyShareRewards($order, $chain) { echo "【六、执行并验证平台均分奖池 (分钟结算/日结)】\n"; $dailyService = new DailySettleService(); $minuteRes = $dailyService->runMinute(); $this->assert(is_array($minuteRes), "DailySettleService::runMinute 分钟清算执行成功"); // 检查均分奖池中是否包含当前订单的贡献 $venueShares = Db::name('shopro_partner_reward') ->where('reward_type', 'venue_share') ->where('ext', 'like', "%{$order->id}%") ->select(); $this->assert(count($venueShares) > 0, "酒道馆均分奖池成功包含本单贡献 (共 " . count($venueShares) . " 家酒道馆获得均分)"); $countyShares = Db::name('shopro_partner_reward') ->where('reward_type', 'county_share') ->where('ext', 'like', "%{$order->id}%") ->select(); $this->assert(count($countyShares) > 0, "区县代理均分奖池成功包含本单贡献 (共 " . count($countyShares) . " 家区县获得均分)"); echo "\n"; } /** * 7. 方案 B 核心规范校验:所有收益必须入账用户钱包余额 money */ private function verifySchemeBWalletIntegrity($chain) { echo "【七、方案 B 一体化大余额闭环校验 (严禁走废弃 commission)】\n"; // 校验直推人 C $freshC = Db::name('user')->where('id', $chain['c']->id)->find(); $moneyDiffC = bcsub((string)$freshC['money'], (string)$this->chainBalances['c']['money'], 2); $this->assert(bccomp($moneyDiffC, '600.00', 2) === 0, "推荐人 C 钱包余额 (money) 严格净增 600.00 元 (实际增加: {$moneyDiffC})"); $this->assert(bccomp((string)$freshC['commission'], '0.00', 2) === 0, "推荐人 C commission 保持为 0.00,绝不走废弃钱包"); // 校验钱包流水日志 $moneyLogC = Db::name('shopro_user_wallet_log') ->where('user_id', $chain['c']->id) ->where('type', 'money') ->order('id', 'desc') ->find(); $this->assert($moneyLogC !== null && floatval($moneyLogC['amount']) == 600.00, "生成对应的 money 变动流水: 变更 +" . floatval($moneyLogC['amount'] ?? 0) . ", 事件: " . ($moneyLogC['event'] ?? '') . ", 备注: " . ($moneyLogC['memo'] ?? '')); // 校验酒道馆/区县 A 的钱包增加 (50 + 50 + 均分) $freshA = Db::name('user')->where('id', $chain['a']->id)->find(); $moneyDiffA = bcsub((string)$freshA['money'], (string)$this->chainBalances['a']['money'], 2); $this->assert(floatval($moneyDiffA) >= 100.00, "节点 A 钱包余额严格增加至少 100.00 元 (管理奖 50+50 + 均分分润,实际增加: {$moneyDiffA})"); echo "\n"; } } $verifier = new FullOrderRewardVerification(); exit($verifier->run());