$val) { $name = 'PHP_' . strtoupper($key); if (is_array($val)) { foreach ($val as $k => $v) { $item = $name . '_' . strtoupper($k); putenv("$item=$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__ . '/../../application/common.php'; require_once __DIR__ . '/../../addons/shopro/helper/helper.php'; use think\Db; use addons\shopro\service\Withdraw as WithdrawService; use addons\shopro\exception\ShoproException; echo "========================================================\n"; echo " 方案 B 提现 API 模拟测试(正常/业务失败/参数错误)\n"; echo "========================================================\n\n"; $userId = 20; $user = \app\admin\model\shopro\user\User::get($userId); if (!$user) { echo "【错误】未找到用户 {$userId}\n"; exit(1); } $withdrawService = new WithdrawService($user); $bankInfo = [ 'account_name' => '曹静', 'account_header' => '西安文景路支行', 'account_no' => '6214832983494902', 'type' => 'bank' ]; $passCount = 0; $failCount = 0; function assertCondition($cond, $msg) { global $passCount, $failCount; if ($cond) { echo " \033[32m[PASS]\033[0m {$msg}\n"; $passCount++; } else { echo " \033[31m[FAIL]\033[0m {$msg}\n"; $failCount++; } } // ------------------------------------------------------------------- // 场景 1:参数错误场景(提现金额低于单笔最低 100 元) // ------------------------------------------------------------------- echo "--- 1. 参数错误场景:提现金额小于最低限额 --- \n"; try { $withdrawService->apply(array_merge($bankInfo, [ 'money' => 50, // 低于 100 ])); assertCondition(false, '未能拦截金额低于最低限额的请求'); } catch (ShoproException $e) { assertCondition(strpos($e->getMessage(), '不能少于') !== false, "成功拦截参数错误: " . $e->getMessage()); } // ------------------------------------------------------------------- // 场景 2:业务失败场景(提现金额超出钱包可用余额) // ------------------------------------------------------------------- echo "\n--- 2. 业务失败场景:提现金额超出钱包可用余额 --- \n"; try { $withdrawService->apply(array_merge($bankInfo, [ 'money' => 800, // 800+48=848,在单笔限额 1000 内,但当前可用余额为 554.65,必触发余额不足 ])); assertCondition(false, '未能拦截余额不足的提现请求'); } catch (ShoproException $e) { assertCondition(strpos($e->getMessage(), '钱包可用余额不足') !== false, "成功拦截超额业务拒绝: " . $e->getMessage()); } // ------------------------------------------------------------------- // 场景 3:正常提现场景(内扣模式:提现 100 元,仅扣除 100 元钱包余额,手续费内扣) // ------------------------------------------------------------------- echo "\n--- 3. 正常业务场景:提现 100 元并校验钱包余额内扣 --- \n"; // 为确保测试环境用户余额充足,临时补充 200 元测试金(测试完成后全额扣回) $originalMoney = floatval($user->money); $originalCommission = floatval($user->commission); \addons\shopro\service\Wallet::change($userId, 'money', 200, 'admin_recharge', [], 'API测试临时充值'); $user = \app\admin\model\shopro\user\User::get($userId); $withdrawService = new WithdrawService($user); $beforeMoney = floatval($user->money); $beforeCommission = floatval($user->commission); Db::startTrans(); $testWithdraw = null; try { $testWithdraw = $withdrawService->apply(array_merge($bankInfo, [ 'money' => 100, ])); Db::commit(); } catch (\Exception $e) { Db::rollback(); echo "提现异常:" . $e->getMessage() . "\n"; } if ($testWithdraw) { $afterUser = \app\admin\model\shopro\user\User::get($userId); $afterMoney = floatval($afterUser->money); $afterCommission = floatval($afterUser->commission); $expectedMoney = round($beforeMoney - 100.00, 2); assertCondition(round($afterMoney, 2) === $expectedMoney, "【内扣】钱包余额仅扣除本金 ¥100.00(¥{$beforeMoney} -> ¥{$afterMoney})"); assertCondition($afterCommission === $beforeCommission, "佣金钱包分毫不差,保持 ¥{$beforeCommission}"); assertCondition($testWithdraw->withdraw_info['wallet_type'] === 'money', "提现订单记录标记为 wallet_type: money"); assertCondition($testWithdraw->withdraw_info['提现资产'] === '钱包余额', "提现订单记录提现资产: 钱包余额"); // 校验内扣净到账金额 (amount - charge_fee = 100 - 6 = 94.00) $expectedPaid = bcsub((string)$testWithdraw->amount, (string)$testWithdraw->charge_fee, 2); assertCondition($expectedPaid === '94.00', "内扣手续费 6.00 元后实际打款金额为 ¥{$expectedPaid}"); // 测试完成后原路驳回并退还余额,恢复环境数据 echo "\n--- 4. 容灾闭环测试:审核驳回退还钱包余额本金 --- \n"; Db::startTrans(); try { $withdrawService->handleRefuse($testWithdraw, 'API自动化测试驳回退还'); Db::commit(); $restoredUser = \app\admin\model\shopro\user\User::get($userId); assertCondition(round(floatval($restoredUser->money), 2) === round($beforeMoney, 2), "驳回后钱包余额原路退还本金 ¥100.00 至 ¥{$beforeMoney}"); assertCondition(floatval($restoredUser->commission) === $beforeCommission, "佣金钱包继续保持 ¥{$beforeCommission}"); } catch (\Exception $e) { Db::rollback(); echo "驳回异常:" . $e->getMessage() . "\n"; } // 回收临时测试充值金 echo "\n--- 5. 还原测试现场:回收临时注入的测试资金 --- \n"; \addons\shopro\service\Wallet::change($userId, 'money', -200, 'admin_recharge', [], 'API测试临时充值回收'); $finalUser = \app\admin\model\shopro\user\User::get($userId); assertCondition(round(floatval($finalUser->money), 2) === round($originalMoney, 2), "测试金已完全回收,用户最终余额恢复至初始 ¥{$originalMoney}"); assertCondition(floatval($finalUser->commission) === $originalCommission, "佣金钱包最终保持 ¥{$originalCommission}"); } echo "\n========================================================\n"; echo " 测试结果: 通过 {$passCount} 项, 失败 {$failCount} 项\n"; echo "========================================================\n\n"; if ($failCount > 0) { exit(1); }