diff --git a/tests/partner/verify_real_order_full_rewards_audit.php b/tests/partner/verify_real_order_full_rewards_audit.php new file mode 100644 index 0000000..e43d63c --- /dev/null +++ b/tests/partner/verify_real_order_full_rewards_audit.php @@ -0,0 +1,575 @@ + $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());