170 行
7.4 KiB
PHP
170 行
7.4 KiB
PHP
<?php
|
||
/**
|
||
* 方案 B 提现 API 核心场景模拟测试(端到端)
|
||
* 覆盖:
|
||
* 1. 正常场景:申请提现扣除钱包余额 money,驳回原路退还 money
|
||
* 2. 业务失败场景:申请提现金额超过钱包余额,捕获【钱包可用余额不足】
|
||
* 3. 参数错误场景:申请金额低于最低限额 100 元,捕获【提现金额不能少于 100元】
|
||
*/
|
||
|
||
define('APP_PATH', __DIR__ . '/../../application/');
|
||
define('ROOT_PATH', dirname(realpath(APP_PATH)) . '/');
|
||
require_once __DIR__ . '/../../thinkphp/base.php';
|
||
require_once __DIR__ . '/../../thinkphp/helper.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) {
|
||
$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);
|
||
}
|