147 行
7.1 KiB
JavaScript
147 行
7.1 KiB
JavaScript
/**
|
||
* 计奖商品收益隔离与混合下单防套利专项验证测试
|
||
* 覆盖范围:PartnerRewardService, VoucherService, RateService, DailySettleService, ActiveService
|
||
*/
|
||
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
let passCount = 0;
|
||
let failCount = 0;
|
||
|
||
function assert(condition, message) {
|
||
if (condition) {
|
||
console.log(` \x1b[32m[PASS]\x1b[0m ${message}`);
|
||
passCount++;
|
||
} else {
|
||
console.error(` \x1b[31m[FAIL]\x1b[0m ${message}`);
|
||
failCount++;
|
||
}
|
||
}
|
||
|
||
console.log('========================================================');
|
||
console.log(' 计奖商品收益隔离与混合下单防套利专项测试');
|
||
console.log('========================================================\n');
|
||
|
||
// 1. PartnerRewardService.php 验证
|
||
const partnerRewardServicePath = path.resolve(__dirname, '../addons/shopro/service/partner/PartnerRewardService.php');
|
||
assert(fs.existsSync(partnerRewardServicePath), 'PartnerRewardService.php 文件存在');
|
||
if (fs.existsSync(partnerRewardServicePath)) {
|
||
const content = fs.readFileSync(partnerRewardServicePath, 'utf-8');
|
||
assert(content.includes('public function getQualifiedPayFee'), '包含 getQualifiedPayFee() 方法');
|
||
assert(content.includes('CommissionGoods::GOODS_COMMISSION_STATUS_ON'), 'getQualifiedPayFee 校验商品计奖启用状态');
|
||
assert(content.includes("isset($ext['is_commission']) && !$ext['is_commission']"), 'getQualifiedPayFee 排除活动不可计奖商品项');
|
||
assert(content.includes('$qualifiedPayFee = $this->getQualifiedPayFee($order)'), 'isQualified() 复用 getQualifiedPayFee()');
|
||
assert(content.includes("PartnerConfig::get('partner_order_min_amount'"), 'isQualified() 支持配置订单最低计奖金额门槛');
|
||
assert(content.includes('$isCommissionItem'), 'refundPartial() 判定子商品是否为计奖商品');
|
||
assert(content.includes('if ($itemPayFee > 0 && $isCommissionItem)'), 'refundPartial() 仅对计奖商品缩减兑换券');
|
||
}
|
||
|
||
// 2. VoucherService.php 验证
|
||
const voucherServicePath = path.resolve(__dirname, '../addons/shopro/service/partner/VoucherService.php');
|
||
assert(fs.existsSync(voucherServicePath), 'VoucherService.php 文件存在');
|
||
if (fs.existsSync(voucherServicePath)) {
|
||
const content = fs.readFileSync(voucherServicePath, 'utf-8');
|
||
assert(content.includes('$rewardService->getQualifiedPayFee($order)'), 'grant() 使用 getQualifiedPayFee 获取计奖实付金额');
|
||
assert(content.includes('$total = round((float) $qualifiedPayFee * $times, 2)'), '兑换券总额基于计奖实付金额而非整单实付');
|
||
assert(content.includes("计奖实付{$qualifiedPayFee}"), '兑换券日志 formula 明确标记计奖实付基数');
|
||
assert(content.includes("'qualified_pay_fee' => $qualifiedPayFee"), '兑换券日志 ext 记录 qualified_pay_fee');
|
||
}
|
||
|
||
// 3. RateService.php 验证
|
||
const rateServicePath = path.resolve(__dirname, '../addons/shopro/service/partner/RateService.php');
|
||
assert(fs.existsSync(rateServicePath), 'RateService.php 文件存在');
|
||
if (fs.existsSync(rateServicePath)) {
|
||
const content = fs.readFileSync(rateServicePath, 'utf-8');
|
||
assert(content.includes('public function qualifiedGmv'), 'RateService 包含 qualifiedGmv() 方法');
|
||
assert(content.includes('CommissionGoods::GOODS_COMMISSION_STATUS_ON'), 'qualifiedGmv 关联计奖状态表');
|
||
assert(content.includes('"is_commission":false'), 'qualifiedGmv SQL 排除非分销活动项');
|
||
assert(content.includes("$query->sum('oi.pay_fee')"), 'qualifiedGmv 针对 oi.pay_fee 单品金额求和');
|
||
}
|
||
|
||
// 4. DailySettleService.php 验证
|
||
const dailySettleServicePath = path.resolve(__dirname, '../addons/shopro/service/partner/DailySettleService.php');
|
||
assert(fs.existsSync(dailySettleServicePath), 'DailySettleService.php 文件存在');
|
||
if (fs.existsSync(dailySettleServicePath)) {
|
||
const content = fs.readFileSync(dailySettleServicePath, 'utf-8');
|
||
assert(content.includes('$gmv = $rateService->qualifiedGmv($start, $end)'), 'DailySettleService 日结 GMV 改用 qualifiedGmv 计算');
|
||
assert(!content.includes("bcadd((string) $gmv, (string) $order['pay_fee']"), 'DailySettleService 彻底移除按整单累加 GMV 的漏洞逻辑');
|
||
}
|
||
|
||
// 5. ActiveService.php 验证
|
||
const activeServicePath = path.resolve(__dirname, '../addons/shopro/service/partner/ActiveService.php');
|
||
assert(fs.existsSync(activeServicePath), 'ActiveService.php 文件存在');
|
||
if (fs.existsSync(activeServicePath)) {
|
||
const content = fs.readFileSync(activeServicePath, 'utf-8');
|
||
assert(content.includes('$rateService->qualifiedOrderQuery($start, $end)'), 'ActiveService 兜底保活查询复用 qualifiedOrderQuery');
|
||
}
|
||
|
||
// 6. 算法逻辑模拟运行断言
|
||
console.log('\n--- 场景模拟算法断言 ---');
|
||
|
||
function mockGetQualifiedPayFee(order, commissionGoodsMap) {
|
||
let total = 0;
|
||
const items = order.items || [];
|
||
for (const item of items) {
|
||
if (item.ext && item.ext.is_commission === false) {
|
||
continue;
|
||
}
|
||
if (commissionGoodsMap[item.goods_id] && commissionGoodsMap[item.goods_id].status === 1) {
|
||
total += Number(item.pay_fee || 0);
|
||
}
|
||
}
|
||
return Math.round(total * 100) / 100;
|
||
}
|
||
|
||
const mockCommissionGoods = {
|
||
101: { status: 1 }, // 指定计奖酒水
|
||
102: { status: 0 }, // 未开启计奖
|
||
// 103 不在映射表中,相当于新添加未配置的商品
|
||
};
|
||
|
||
// 场景 A:纯非计奖新品下单(商品 103,实付 500 元)
|
||
const pureNewOrder = {
|
||
id: 1,
|
||
pay_fee: 500,
|
||
items: [
|
||
{ goods_id: 103, pay_fee: 500, ext: {} }
|
||
]
|
||
};
|
||
const pureFee = mockGetQualifiedPayFee(pureNewOrder, mockCommissionGoods);
|
||
assert(pureFee === 0, '模拟场景 A:纯新品订单计奖实付金额为 0');
|
||
assert(pureFee > 0 === false, '模拟场景 A:纯新品订单无法通过 isQualified 校验');
|
||
|
||
// 场景 B:混合下单(商品 101 计奖 100 元,商品 103 新品 900 元,整单实付 1000 元)
|
||
const mixedOrder = {
|
||
id: 2,
|
||
pay_fee: 1000,
|
||
items: [
|
||
{ goods_id: 101, pay_fee: 100, ext: {} },
|
||
{ goods_id: 103, pay_fee: 900, ext: {} }
|
||
]
|
||
};
|
||
const mixedFee = mockGetQualifiedPayFee(mixedOrder, mockCommissionGoods);
|
||
assert(mixedFee === 100, '模拟场景 B:混合订单精确提取计奖实付 100 元(排除新品 900 元)');
|
||
const voucherTimes = 1.5;
|
||
const voucherTotal = Math.round(mixedFee * voucherTimes * 100) / 100;
|
||
assert(voucherTotal === 150, '模拟场景 B:兑换券按 100 * 1.5 = 150 发放(修复前会发 1500,成功堵住漏洞)');
|
||
|
||
// 场景 C:活动标记不参与分销(商品 101 秒杀特惠 is_commission=false)
|
||
const promoOrder = {
|
||
id: 3,
|
||
pay_fee: 100,
|
||
items: [
|
||
{ goods_id: 101, pay_fee: 100, ext: { is_commission: false } }
|
||
]
|
||
};
|
||
const promoFee = mockGetQualifiedPayFee(promoOrder, mockCommissionGoods);
|
||
assert(promoFee === 0, '模拟场景 C:即便属于计奖商品,活动标记 is_commission=false 亦被正确排除');
|
||
|
||
console.log('\n--------------------------------------------------------');
|
||
console.log(`测试执行结果: 通过 ${passCount} 项, 失败 ${failCount} 项`);
|
||
console.log('========================================================');
|
||
|
||
if (failCount > 0) {
|
||
process.exit(1);
|
||
}
|