订单支付自动分佣 -> 佣金结算 -> 申请提现与打款 */ class FcVerifyDist extends Command { protected function configure() { $this->setName('fc:verify-dist') ->setDescription('验证分销与分佣核心链路闭环'); } protected function execute(Input $input, Output $output) { $output->writeln('==> 开始执行分销全链路闭环自动化测试'); $now = time(); // 1. 创建 3 个临时测试用户 $rand = mt_rand(1000, 9999); $userAId = (int)$this->createMockUser('test_dist_a_' . $rand, '推广员A'); $userBId = (int)$this->createMockUser('test_dist_b_' . $rand, '推广员B'); $userCId = (int)$this->createMockUser('test_dist_c_' . $rand, '消费者C'); $extA = Db::name('fc_user_ext')->where('user_id', $userAId)->find(); $codeA = $extA['invite_code']; $extB = Db::name('fc_user_ext')->where('user_id', $userBId)->find(); $codeB = $extB['invite_code']; $output->writeln(" [+] 创建测试用户: A(#{$userAId}, code:{$codeA}), B(#{$userBId}, code:{$codeB}), C(#{$userCId})"); // 2. 绑定关系:B 绑定 A (1级) $resB = DistributionService::bindRelation($userBId, 0, $codeA); if (!$resB) { $output->writeln(' [x] B 绑定 A 失败'); return; } $relB = Db::name('fc_dist_relation')->where('user_id', $userBId)->select(); $output->writeln(' [+] B 绑定 A 成功,关系数: ' . count($relB)); // 3. 绑定关系:C 绑定 B (B为1级,A为2级) $resC = DistributionService::bindRelation($userCId, 0, $codeB); if (!$resC) { $output->writeln(' [x] C 绑定 B 失败'); return; } $relC1 = Db::name('fc_dist_relation')->where('user_id', $userCId)->where('level', 1)->find(); $relC2 = Db::name('fc_dist_relation')->where('user_id', $userCId)->where('level', 2)->find(); if (!$relC1 || (int)$relC1['parent_id'] !== $userBId) { $output->writeln(' [x] C 的 1 级推荐人不是 B'); return; } if (!$relC2 || (int)$relC2['parent_id'] !== $userAId) { $output->writeln(' [x] C 的 2 级推荐人不是 A'); return; } $output->writeln(" [+] 递归关系链路校验通过: C(#{$userCId}) -> 1级 B(#{$userBId}) -> 2级 A(#{$userAId})"); // 4. 模拟消费:C 购买了 100 元的会员套餐订单 $orderNo = 'TEST' . date('YmdHis') . $userCId; $orderId = Db::name('fc_order')->insertGetId([ 'order_no' => $orderNo, 'user_id' => $userCId, 'type' => 'member', 'title' => '测试年卡会员', 'amount' => 100.00, 'pay_type' => 'balance', 'status' => 'paid', 'paytime' => $now, 'related_id' => 1, 'createtime' => $now, 'updatetime' => $now, ]); $order = Db::name('fc_order')->where('id', $orderId)->find(); $output->writeln(" [+] 模拟生成已支付订单: #{$orderId}, 订单号: {$orderNo}, 金额: 100.00元"); // 5. 触发分销分佣结算 $settled = DistributionService::settleOrder($order); $output->writeln(' [+] 触发分佣结算,生成分佣记录条数: ' . count($settled)); $commB = Db::name('fc_commission')->where('order_no', $orderNo)->where('user_id', $userBId)->find(); $commA = Db::name('fc_commission')->where('order_no', $orderNo)->where('user_id', $userAId)->find(); if (!$commB || (float)$commB['amount'] <= 0) { $output->writeln(' [x] B 的 1 级分佣未正确生成'); return; } if (!$commA || (float)$commA['amount'] <= 0) { $output->writeln(' [x] A 的 2 级分佣未正确生成'); return; } $output->writeln(" [+] 分佣金额精确校验通过: 1级推广员B 获得 ¥{$commB['amount']} (比例 {$commB['rate']}%),2级推广员A 获得 ¥{$commA['amount']} (比例 {$commA['rate']}%)"); // 6. 检查分销商站内信通知 $msgB = Db::name('fc_message')->where('user_id', $userBId)->where('type', 'interact')->find(); if ($msgB) { $output->writeln(" [+] 推广员B 收到分销收益站内信: 「{$msgB['title']}」- {$msgB['content']}"); } // 7. 提现流程验证(B 发起提现申请) $withdrawableB = (float)Db::name('fc_commission')->where('user_id', $userBId)->where('status', 1)->sum('amount'); $output->writeln(" [+] 推广员B 当前可提现佣金: ¥{$withdrawableB}"); $withdrawNo = 'WD' . date('YmdHis') . $userBId; $withdrawId = Db::name('fc_withdraw')->insertGetId([ 'withdraw_no' => $withdrawNo, 'user_id' => $userBId, 'amount' => $withdrawableB, 'channel' => 'wxpay', 'status' => 'auditing', 'createtime' => $now, 'updatetime' => $now, ]); $output->writeln(" [+] 推广员B 提交全额提现申请 #{$withdrawId}, 提现单号: {$withdrawNo}, 状态: auditing"); // 模拟管理员打款操作 Db::name('fc_withdraw')->where('id', $withdrawId)->update([ 'status' => 'paid', 'paytime' => time(), 'updatetime' => time(), ]); Db::name('fc_finance_flow')->insert([ 'user_id' => $userBId, 'flow_no' => 'WD' . date('YmdHis') . $withdrawId, 'type' => 'expense', 'scene' => '佣金提现', 'amount' => $withdrawableB, 'balance' => 0, 'related_id' => $withdrawId, 'remark' => '自动化测试打款', 'createtime' => time(), ]); $output->writeln(" [+] 后台管理员审核打款完成,记入资金流水支出 ¥{$withdrawableB}"); // 8. 清理本次测试产生的测试数据 Db::name('user')->where('id', 'in', [$userAId, $userBId, $userCId])->delete(); Db::name('fc_user_ext')->where('user_id', 'in', [$userAId, $userBId, $userCId])->delete(); Db::name('fc_dist_relation')->where('user_id', 'in', [$userAId, $userBId, $userCId])->delete(); Db::name('fc_order')->where('id', $orderId)->delete(); Db::name('fc_commission')->where('order_no', $orderNo)->delete(); Db::name('fc_message')->where('user_id', 'in', [$userAId, $userBId, $userCId])->delete(); Db::name('fc_withdraw')->where('id', $withdrawId)->delete(); Db::name('fc_finance_flow')->where('related_id', $withdrawId)->delete(); $output->writeln(' [+] 测试数据自动清理完毕'); $output->writeln('==> 【验证成功】分销拓客 -> 订单消费 -> 自动分润 -> 收益通知 -> 申请提现 -> 财务打款 全链路 100% 打通!'); } /** * 创建用于测试的模拟用户 * @param string $username 用户名 * @param string $nickname 昵称 * @return int 用户ID */ protected function createMockUser($username, $nickname) { $now = time(); $uid = Db::name('user')->insertGetId([ 'group_id' => 1, 'username' => $username, 'nickname' => $nickname, 'password' => md5('123456'), 'salt' => 'mock', 'email' => $username . '@mock.local', 'mobile' => '188' . mt_rand(10000000, 99999999), 'avatar' => '', 'level' => 1, 'money' => 500.00, 'score' => 0, 'status' => 'normal', 'jointime' => $now, 'createtime' => $now, 'updatetime' => $now, ]); Db::name('fc_user_ext')->insert([ 'user_id' => $uid, 'openid' => 'mock_' . $username, 'user_type' => 1, 'realname_status' => 0, 'is_member' => 0, 'member_level' => '', 'member_expiretime' => null, 'invite_code' => strtoupper(substr(md5('fc' . $uid . mt_rand()), 0, 6)), 'inviter_id' => 0, 'free_view_date' => date('Y-m-d'), 'free_view_used' => 0, 'createtime' => $now, 'updatetime' => $now, ]); return $uid; } }