修复(收益): 纠正累计收益统计口径为真实分成收益,排除dmepa与兑换券释放干扰

这个提交包含在:
chen
2026-09-19 16:37:54 +08:00
父节点 cbac2a69f4
当前提交 bee5288e88
共有 8 个文件被更改,包括 141 次插入 和 4 次删除

查看文件

@@ -0,0 +1,115 @@
const { execSync } = require('child_process');
let passed = 0;
let failed = 0;
function assert(condition, testName, detail = '') {
if (condition) {
console.log(` [PASS] ${testName}`);
passed++;
} else {
console.error(` [FAIL] ${testName} - ${detail}`);
failed++;
}
}
console.log("========================================================");
console.log(" 累计收益口径修正测试:严格限定为真实分成收益,排除dmepa与兑换券");
console.log("========================================================\n");
// 1. 本地代码与定义合规检查
console.log("一、代码与规则定义检查:");
const fs = require('fs');
const path = require('path');
const partnerConfigPath = path.resolve(__dirname, '../../addons/shopro/service/partner/PartnerConfig.php');
const configContent = fs.readFileSync(partnerConfigPath, 'utf-8');
assert(configContent.includes('public static function cashTypes()'), 'PartnerConfig 包含统一现金分成类型定义 cashTypes()');
assert(configContent.includes('array_merge(self::instantTypes(), [\'venue_share\', \'county_share\'])'), 'cashTypes 包含即时奖与日结分红共10种现金分成类型');
const identityServicePath = path.resolve(__dirname, '../../addons/shopro/service/partner/IdentityService.php');
const identityContent = fs.readFileSync(identityServicePath, 'utf-8');
assert(identityContent.includes('whereIn(\'reward_type\', $cashTypes)'), 'IdentityService::attachAgent 严格通过 cashTypes 过滤现金分成');
const userControllerPath = path.resolve(__dirname, '../../addons/shopro/controller/user/User.php');
const userControllerContent = fs.readFileSync(userControllerPath, 'utf-8');
assert(userControllerContent.includes('whereIn(\'reward_type\', $cashTypes)'), 'User.php profile 接口严格通过 cashTypes 过滤现金分成');
// 2. 线上接口模拟测试(使用真实用户数据进行场景验证)
console.log("\n二、线上用户接口场景模拟测试:");
try {
const remoteScript = `#!/bin/bash
php -r '
define("APP_PATH", "/www/wwwroot/henglian.gynhc.com/application/");
require "/www/wwwroot/henglian.gynhc.com/thinkphp/base.php";
\\think\\App::initCommon();
\$auth = \\app\\common\\library\\Auth::instance();
\$auth->direct(10);
file_put_contents("/tmp/user10_token.txt", \$auth->getToken());
\$auth->direct(20);
file_put_contents("/tmp/user20_token.txt", \$auth->getToken());
'
TOKEN10=\$(cat /tmp/user10_token.txt)
TOKEN20=\$(cat /tmp/user20_token.txt)
curl -s -k --resolve henglian.gynhc.com:443:127.0.0.1 -H "token: \$TOKEN10" -H "platform: WechatMiniProgram" "https://henglian.gynhc.com/addons/shopro/commission.agent" > /tmp/test_user10_agent.json
curl -s -k --resolve henglian.gynhc.com:443:127.0.0.1 -H "token: \$TOKEN10" -H "platform: WechatMiniProgram" "https://henglian.gynhc.com/addons/shopro/user.user/profile" > /tmp/test_user10_profile.json
curl -s -k --resolve henglian.gynhc.com:443:127.0.0.1 -H "token: \$TOKEN10" -H "platform: WechatMiniProgram" "https://henglian.gynhc.com/addons/shopro/partner.index/index" > /tmp/test_user10_index.json
curl -s -k --resolve henglian.gynhc.com:443:127.0.0.1 -H "token: \$TOKEN20" -H "platform: WechatMiniProgram" "https://henglian.gynhc.com/addons/shopro/commission.agent" > /tmp/test_user20_agent.json
curl -s -k --resolve henglian.gynhc.com:443:127.0.0.1 -H "token: \$TOKEN20" -H "platform: WechatMiniProgram" "https://henglian.gynhc.com/addons/shopro/partner.index/rewards" > /tmp/test_user20_rewards.json
curl -s -k --resolve henglian.gynhc.com:443:127.0.0.1 -H "platform: WechatMiniProgram" "https://henglian.gynhc.com/addons/shopro/commission.agent" > /tmp/test_unauth.json
`;
fs.writeFileSync('/tmp/test_total_income_runner.sh', remoteScript);
execSync(`sshpass -p 'Bjsslxz1' scp -o StrictHostKeyChecking=no /tmp/test_total_income_runner.sh root@118.184.172.94:/tmp/runner.sh`);
execSync(`sshpass -p 'Bjsslxz1' ssh -o StrictHostKeyChecking=no root@118.184.172.94 "bash /tmp/runner.sh"`);
const fetchCmd = `sshpass -p 'Bjsslxz1' ssh -o StrictHostKeyChecking=no root@118.184.172.94 "cat /tmp/test_user10_agent.json && echo '===SEP===' && cat /tmp/test_user10_profile.json && echo '===SEP===' && cat /tmp/test_user10_index.json && echo '===SEP===' && cat /tmp/test_user20_agent.json && echo '===SEP===' && cat /tmp/test_user20_rewards.json && echo '===SEP===' && cat /tmp/test_unauth.json"`;
const fetched = execSync(fetchCmd, { timeout: 25000 }).toString();
const parts = fetched.split('===SEP===').map(p => p.trim());
const u10Agent = JSON.parse(parts[0]);
const u10Profile = JSON.parse(parts[1]);
const u10Index = JSON.parse(parts[2]);
const u20Agent = JSON.parse(parts[3]);
const u20Rewards = JSON.parse(parts[4]);
const unauth = JSON.parse(parts[5]);
// 场景 1:用户10(尚善,仅有自购订单并释放兑换券,无下级分成收益)
console.log("\n场景 1:用户10(仅自购与兑换券释放,无分成收益):");
assert(u10Agent.code === 1, 'commission.agent 返回成功');
assert(u10Agent.data.total_income === '0.00', `累计收益严格为分成收益 (0.00),实际: ${u10Agent.data.total_income}`);
assert(Number(u10Agent.data.voucher_available) > 0, `可用兑换券保持独立正常发放 (${u10Agent.data.voucher_available})`);
assert(u10Agent.data.total_income !== u10Agent.data.voucher_available, '累计收益不再与兑换券数值混淆');
assert(u10Profile.data.total_income === '0.00', `user.user/profile 累计收益同步为 0.00`);
assert(u10Index.data.total_income === '0.00', `partner.index/index 累计收益同步为 0.00`);
// 场景 2:用户20(有真实团队分成和日结现金分红)
console.log("\n场景 2:用户20(有真实团队分成与日结分红):");
assert(u20Agent.code === 1, 'user20 commission.agent 返回成功');
const u20Income = Number(u20Agent.data.total_income);
assert(u20Income > 0, `user20 累计收益正确统计真实分成收益 (>0),实际: ${u20Agent.data.total_income}`);
assert(u20Rewards.code === 1, 'user20 partner.index/rewards 列表接口成功');
assert(u20Rewards.data.total_income === u20Agent.data.total_income, 'rewards 接口累计收益与 agent 接口严格一致');
assert(u20Rewards.data.data.length > 0, `rewards 明细包含 ${u20Rewards.data.data.length} 笔真实分成收益`);
assert(u20Rewards.data.data.every(r => !['voucher_release', 'voucher_grant', 'madow_share'].includes(r.reward_type)),
'收益明细列表中绝无兑换券释放或dmepa记录混入');
// 场景 3:未登录拦截与安全防御
console.log("\n场景 3:未登录参数校验拦截测试:");
assert(unauth.code === 401, '未传 token 严格返回 401 认证拦截');
assert(unauth.msg === '请登录后操作', '返回中文友好提示“请登录后操作”');
} catch (e) {
console.error("测试执行异常:", e.message);
failed++;
}
console.log("\n========================================================");
console.log(`测试结果: 通过 ${passed} 项, 失败 ${failed} 项`);
console.log("========================================================");
if (failed > 0) {
process.exit(1);
}