/** * 计奖商品收益隔离与混合下单防套利专项验证测试 * 覆盖范围: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); }