330 行
16 KiB
JavaScript
330 行
16 KiB
JavaScript
/**
|
|
* dmepa 余额银行卡提现功能端到端全链路规格测试
|
|
* 覆盖范围:
|
|
* 1. PartnerConfig.php 开关与最小金额读取方法、奖励字典
|
|
* 2. Config.php 控制器白名单、默认值、自愈与入参校验
|
|
* 3. config/index.html & config.js 后台表单项与初始化
|
|
* 4. partner_v2.sql 数据库升级配置行
|
|
* 5. Withdraw.php 服务层 applyMadow 提现发起、持仓校验、扣减流水、审核拒绝退款与失败退还闭环
|
|
* 6. partner/Index.php madow() 接口返回提现开关与最低金额
|
|
* 7. madow.vue 资产卡片提现按钮及动态显隐控制
|
|
* 8. withdraw.vue 路由参数、银行卡模式锁定、全部提现、实时汇率扣除估算与提现提交
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
let passCount = 0;
|
|
let failCount = 0;
|
|
|
|
function assert(condition, testName, detail = '') {
|
|
if (condition) {
|
|
console.log(` \x1b[32m[PASS]\x1b[0m ${testName}`);
|
|
passCount++;
|
|
} else {
|
|
console.error(` \x1b[31m[FAIL]\x1b[0m ${testName} - ${detail}`);
|
|
failCount++;
|
|
}
|
|
}
|
|
|
|
console.log('========================================================');
|
|
console.log(' dmepa 余额银行卡提现功能端到端规格测试');
|
|
console.log('========================================================\n');
|
|
|
|
// 1. 验证 PartnerConfig.php
|
|
console.log('--- 1. PartnerConfig 配置读取与字典注册 ---');
|
|
const partnerConfigPath = path.resolve(__dirname, '../../addons/shopro/service/partner/PartnerConfig.php');
|
|
assert(fs.existsSync(partnerConfigPath), 'PartnerConfig.php 文件存在');
|
|
const partnerConfigContent = fs.readFileSync(partnerConfigPath, 'utf-8');
|
|
|
|
assert(
|
|
partnerConfigContent.includes('function isMadowWithdrawEnabled'),
|
|
'PartnerConfig 包含 isMadowWithdrawEnabled() 读取方法'
|
|
);
|
|
assert(
|
|
partnerConfigContent.includes('function madowWithdrawMin'),
|
|
'PartnerConfig 包含 madowWithdrawMin() 最低提现金额读取方法'
|
|
);
|
|
assert(
|
|
partnerConfigContent.includes("'madow_withdraw' => 'dmepa提现扣除'") &&
|
|
partnerConfigContent.includes("'madow_withdraw_refund' => 'dmepa提现退还'"),
|
|
'PartnerConfig rewardTypes 字典正确登记 madow_withdraw 与 madow_withdraw_refund'
|
|
);
|
|
|
|
// 2. 验证 Config.php
|
|
console.log('\n--- 2. 后台 Config.php 控制器白名单与自愈 ---');
|
|
const configPhpPath = path.resolve(__dirname, '../../application/admin/controller/shopro/Config.php');
|
|
assert(fs.existsSync(configPhpPath), 'Config.php 文件存在');
|
|
const configPhpContent = fs.readFileSync(configPhpPath, 'utf-8');
|
|
|
|
assert(
|
|
configPhpContent.includes("'partner_madow_withdraw_enable'") &&
|
|
configPhpContent.includes("'partner_madow_withdraw_min'"),
|
|
'Config.php 白名单 $keys 包含 partner_madow_withdraw_enable 与 partner_madow_withdraw_min'
|
|
);
|
|
assert(
|
|
configPhpContent.includes("'partner_madow_withdraw_enable' => 1") &&
|
|
configPhpContent.includes("'partner_madow_withdraw_min' => 1"),
|
|
'Config.php $defaults 包含 partner_madow_withdraw_enable 与 partner_madow_withdraw_min 默认值'
|
|
);
|
|
assert(
|
|
configPhpContent.includes("shop.commission.partner_madow_withdraw_enable") &&
|
|
configPhpContent.includes("shop.commission.partner_madow_withdraw_min"),
|
|
'Config.php $ensureConfigs 包含提现开关与最低金额自愈创建机制'
|
|
);
|
|
assert(
|
|
configPhpContent.includes("intval($save['partner_madow_withdraw_enable'])") &&
|
|
configPhpContent.includes("floatval($save['partner_madow_withdraw_min'])"),
|
|
'Config.php POST 保存处理了整型与浮点安全类型转换'
|
|
);
|
|
|
|
// 3. 验证 后台视图与 JS 脚本
|
|
console.log('\n--- 3. 后台配置视图与脚本 (index.html & config.js) ---');
|
|
const indexHtmlPath = path.resolve(__dirname, '../../application/admin/view/shopro/config/index.html');
|
|
assert(fs.existsSync(indexHtmlPath), 'config/index.html 视图文件存在');
|
|
const indexHtmlContent = fs.readFileSync(indexHtmlPath, 'utf-8');
|
|
|
|
assert(
|
|
indexHtmlContent.includes('form.model.partner_madow_withdraw_enable') &&
|
|
(indexHtmlContent.includes('开启dmepa提现') || indexHtmlContent.includes('开启DMEPA提现')),
|
|
'后台视图包含「开启DMEPA提现」switch 开关'
|
|
);
|
|
assert(
|
|
indexHtmlContent.includes('form.model.partner_madow_withdraw_min') &&
|
|
(indexHtmlContent.includes('dmepa最低提现金额') || indexHtmlContent.includes('DMEPA最低提现金额')),
|
|
'后台视图包含「DMEPA最低提现金额」输入框'
|
|
);
|
|
|
|
const configJsPath = path.resolve(__dirname, '../../public/assets/js/backend/shopro/config.js');
|
|
assert(fs.existsSync(configJsPath), 'config.js 脚本文件存在');
|
|
const configJsContent = fs.readFileSync(configJsPath, 'utf-8');
|
|
|
|
assert(
|
|
configJsContent.includes('form.model.partner_madow_withdraw_enable') &&
|
|
configJsContent.includes('form.model.partner_madow_withdraw_min'),
|
|
'config.js 对 partner_madow_withdraw_enable 与 partner_madow_withdraw_min 进行默认初始化'
|
|
);
|
|
|
|
// 4. 验证 partner_v2.sql
|
|
console.log('\n--- 4. 数据库升级脚本 partner_v2.sql ---');
|
|
const sqlPath = path.resolve(__dirname, '../../addons/shopro/upgrade/partner_v2.sql');
|
|
assert(fs.existsSync(sqlPath), 'partner_v2.sql 文件存在');
|
|
const sqlContent = fs.readFileSync(sqlPath, 'utf-8');
|
|
|
|
assert(
|
|
sqlContent.includes("'shop.commission.partner_madow_withdraw_enable'") &&
|
|
sqlContent.includes("'shop.commission.partner_madow_withdraw_min'"),
|
|
'partner_v2.sql 包含提现开关与最低金额初始配置行'
|
|
);
|
|
|
|
// 5. 验证 Withdraw.php 服务层业务闭环
|
|
console.log('\n--- 5. 提现服务层 (Withdraw.php) dmepa提现业务闭环 ---');
|
|
const withdrawServicePath = path.resolve(__dirname, '../../addons/shopro/service/Withdraw.php');
|
|
assert(fs.existsSync(withdrawServicePath), 'Withdraw.php 服务文件存在');
|
|
const withdrawServiceContent = fs.readFileSync(withdrawServicePath, 'utf-8');
|
|
|
|
assert(
|
|
(withdrawServiceContent.includes("params['wallet_type'] ?? 'commission'") ||
|
|
withdrawServiceContent.includes("params['wallet_type'] ?? 'money'")) &&
|
|
withdrawServiceContent.includes("applyMadow"),
|
|
'Withdraw.php::apply 支持 wallet_type=madow 并分流至 applyMadow'
|
|
);
|
|
assert(
|
|
withdrawServiceContent.includes("PartnerConfig::isMadowWithdrawEnabled()") &&
|
|
(withdrawServiceContent.includes('dmepa提现功能暂未开启') || withdrawServiceContent.includes('DMEPA提现功能暂未开启')),
|
|
'applyMadow 校验 DMEPA 提现开关,关闭时抛出面向用户的明确提示'
|
|
);
|
|
assert(
|
|
withdrawServiceContent.includes("$type !== 'bank'") &&
|
|
(withdrawServiceContent.includes('dmepa提现仅支持银行卡转账') || withdrawServiceContent.includes('DMEPA提现仅支持银行卡转账')),
|
|
'applyMadow 严格限制提现渠道仅支持 bank (银行卡转账)'
|
|
);
|
|
assert(
|
|
withdrawServiceContent.includes("PartnerConfig::madowWithdrawMin()"),
|
|
'applyMadow 校验最低提现金额'
|
|
);
|
|
assert(
|
|
withdrawServiceContent.includes("(new RateService())->currentRate()"),
|
|
'applyMadow 调用 RateService 实时获取当前大盘汇率'
|
|
);
|
|
assert(
|
|
withdrawServiceContent.includes("AgentModel::where('user_id', $this->user->id)->lock(true)->find()") &&
|
|
(withdrawServiceContent.includes("持仓dmepa不足,无法提现") || withdrawServiceContent.includes("持仓DMEPA不足,无法提现")),
|
|
'applyMadow 行级排他锁校验合伙人 DMEPA 持仓充足性'
|
|
);
|
|
assert(
|
|
withdrawServiceContent.includes("$agent->setDec('madow', $deductMadow)"),
|
|
'applyMadow 执行数据库原子扣减持仓 dmepa'
|
|
);
|
|
assert(
|
|
withdrawServiceContent.includes("'reward_type' => 'madow_withdraw'"),
|
|
'applyMadow 记录 PartnerRewardService madow_withdraw 负向提现流水'
|
|
);
|
|
assert(
|
|
withdrawServiceContent.includes("madow_withdraw_refund") &&
|
|
withdrawServiceContent.includes("$agent->setInc('madow', $madowRefund)"),
|
|
'handleRefuse 识别 dmepa 提现驳回并原子返还持仓 madow 记录 refund 流水'
|
|
);
|
|
assert(
|
|
withdrawServiceContent.includes("handleFail") &&
|
|
withdrawServiceContent.includes("madow_withdraw_refund"),
|
|
'handleFail 提现异常失败时同样支持安全返还 dmepa'
|
|
);
|
|
|
|
// 6. 验证 用户端接口 partner/Index.php
|
|
console.log('\n--- 6. 用户端 partner/Index.php 接口输出 ---');
|
|
const partnerIndexPath = path.resolve(__dirname, '../../addons/shopro/controller/partner/Index.php');
|
|
assert(fs.existsSync(partnerIndexPath), 'partner/Index.php 控制器存在');
|
|
const partnerIndexContent = fs.readFileSync(partnerIndexPath, 'utf-8');
|
|
|
|
assert(
|
|
partnerIndexContent.includes("'can_withdraw_madow' => PartnerConfig::isMadowWithdrawEnabled() ? 1 : 0") &&
|
|
partnerIndexContent.includes("'madow_withdraw_min' => PartnerConfig::madowWithdrawMin()"),
|
|
'madow() 接口返回 can_withdraw_madow 开关与 madow_withdraw_min 门槛'
|
|
);
|
|
|
|
// 7. 验证 前端 madow.vue 资产页
|
|
console.log('\n--- 7. 用户端 我的dmepa页面 (madow.vue) 提现入口 ---');
|
|
const madowVuePath = path.resolve(__dirname, '../../uniapp/pages/commission/madow.vue');
|
|
assert(fs.existsSync(madowVuePath), 'madow.vue 文件存在');
|
|
const madowVueContent = fs.readFileSync(madowVuePath, 'utf-8');
|
|
|
|
assert(
|
|
madowVueContent.includes("v-if=\"state.info.can_withdraw_madow !== false && state.info.can_withdraw_madow !== 0 && state.info.can_withdraw_madow !== '0'\""),
|
|
'madow.vue 提现按钮受后台 can_withdraw_madow 开关动态控制显隐'
|
|
);
|
|
assert(
|
|
madowVueContent.includes("@tap=\"onWithdrawMadow\"") &&
|
|
madowVueContent.includes("sheep.$router.go('/pages/pay/withdraw', { type: 'madow' })"),
|
|
'madow.vue 点击提现跳转至 /pages/pay/withdraw?type=madow'
|
|
);
|
|
assert(
|
|
madowVueContent.includes(".topup-btn") &&
|
|
madowVueContent.includes(".hero-left"),
|
|
'madow.vue 包含与钱包对齐的黑金渐变提现按钮样式'
|
|
);
|
|
assert(
|
|
madowVueContent.includes("state.info.can_withdraw_madow = data.can_withdraw_madow"),
|
|
'madow.vue getMadow() 解析服务端下发的 can_withdraw_madow 状态'
|
|
);
|
|
|
|
// 8. 验证 前端 withdraw.vue 提现申请页
|
|
console.log('\n--- 8. 用户端 提现申请页 (withdraw.vue) dmepa提现适配 ---');
|
|
const withdrawVuePath = path.resolve(__dirname, '../../uniapp/pages/pay/withdraw.vue');
|
|
assert(fs.existsSync(withdrawVuePath), 'withdraw.vue 文件存在');
|
|
const withdrawVueContent = fs.readFileSync(withdrawVuePath, 'utf-8');
|
|
|
|
assert(
|
|
withdrawVueContent.includes(":title=\"state.walletType === 'madow' ? 'dmepa提现' : '申请提现'\"") ||
|
|
withdrawVueContent.includes(":title=\"state.walletType === 'madow' ? 'DMEPA提现' : '申请提现'\""),
|
|
'withdraw.vue 页面标题根据 walletType 自适应切换 DMEPA提现 / 申请提现'
|
|
);
|
|
assert(
|
|
withdrawVueContent.includes("state.walletType === 'madow'") &&
|
|
withdrawVueContent.includes("state.madowInfo.madow"),
|
|
'withdraw.vue 顶部资产卡片在 madow 模式下展示 dmepa 持仓与预估市值'
|
|
);
|
|
assert(
|
|
withdrawVueContent.includes("onWithdrawAllMadow") &&
|
|
withdrawVueContent.includes("全部提现"),
|
|
'withdraw.vue madow 模式下支持一键「全部提现」'
|
|
);
|
|
assert(
|
|
withdrawVueContent.includes("estimatedDeductMadow") &&
|
|
withdrawVueContent.includes("实时汇率"),
|
|
'withdraw.vue 支持输入金额时根据大盘实时汇率计算需扣除的 dmepa 数量预览'
|
|
);
|
|
assert(
|
|
withdrawVueContent.includes(":methods=\"state.walletType === 'madow' ? ['bank'] : state.rules.methods\""),
|
|
'withdraw.vue 在 madow 模式下提现方式严格锁定为 bank 银行卡'
|
|
);
|
|
assert(
|
|
withdrawVueContent.includes("payload.wallet_type = 'madow'") &&
|
|
withdrawVueContent.includes("payload.type = 'bank'"),
|
|
'withdraw.vue 提交申请时附带 wallet_type: madow 与 type: bank 参数'
|
|
);
|
|
assert(
|
|
withdrawVueContent.includes("fetchUserBankAccount"),
|
|
'withdraw.vue 进入 madow 提现时自动调取既有已绑定的银行卡信息'
|
|
);
|
|
|
|
// 9. 验证 后台提现模型 (Withdraw.php) 属性追加与获取器清洗
|
|
console.log('\n--- 9. 后台提现模型 (Withdraw.php) 市值汇率与换算市值获取器 ---');
|
|
const adminWithdrawModelPath = path.resolve(__dirname, '../../application/admin/model/shopro/Withdraw.php');
|
|
assert(fs.existsSync(adminWithdrawModelPath), 'application/admin/model/shopro/Withdraw.php 存在');
|
|
const adminWithdrawModelContent = fs.readFileSync(adminWithdrawModelPath, 'utf-8');
|
|
|
|
assert(
|
|
adminWithdrawModelContent.includes("'is_madow_withdraw'") &&
|
|
adminWithdrawModelContent.includes("'withdraw_info_display'"),
|
|
'Withdraw 模型 $append 包含 is_madow_withdraw 与 withdraw_info_display 属性'
|
|
);
|
|
assert(
|
|
adminWithdrawModelContent.includes("function getIsMadowWithdrawAttr"),
|
|
'Withdraw 模型提供 getIsMadowWithdrawAttr 获取器精准识别 DMEPA 提现单'
|
|
);
|
|
assert(
|
|
adminWithdrawModelContent.includes("function getWithdrawInfoDisplayAttr"),
|
|
'Withdraw 模型提供 getWithdrawInfoDisplayAttr 获取器'
|
|
);
|
|
assert(
|
|
adminWithdrawModelContent.includes("市值汇率") &&
|
|
adminWithdrawModelContent.includes("换算市值") &&
|
|
adminWithdrawModelContent.includes("1 DMEPA ≈"),
|
|
'getWithdrawInfoDisplayAttr 包含「市值汇率」与「换算市值」规范格式化'
|
|
);
|
|
assert(
|
|
adminWithdrawModelContent.includes("wallet_type") &&
|
|
adminWithdrawModelContent.includes("madow_amount") &&
|
|
adminWithdrawModelContent.includes("rate"),
|
|
'getWithdrawInfoDisplayAttr 过滤 wallet_type、madow_amount、rate 等英文技术键'
|
|
);
|
|
|
|
// 10. 验证 后台提现视图 (index.html) 金额列与打款信息列展示
|
|
console.log('\n--- 10. 后台提现管理视图 (index.html) 市值汇率与换算市值高亮展示 ---');
|
|
const adminWithdrawHtmlPath = path.resolve(__dirname, '../../application/admin/view/shopro/withdraw/index.html');
|
|
assert(fs.existsSync(adminWithdrawHtmlPath), 'application/admin/view/shopro/withdraw/index.html 存在');
|
|
const adminWithdrawHtmlContent = fs.readFileSync(adminWithdrawHtmlPath, 'utf-8');
|
|
|
|
assert(
|
|
adminWithdrawHtmlContent.includes("scope.row.is_madow_withdraw") &&
|
|
adminWithdrawHtmlContent.includes("DMEPA提现") &&
|
|
adminWithdrawHtmlContent.includes("换算市值: {{ scope.row.amount || '-' }}元"),
|
|
'提现金额列识别 DMEPA 提现,展示 DMEPA提现 专属金标并明确标注「换算市值」'
|
|
);
|
|
assert(
|
|
adminWithdrawHtmlContent.includes("scope.row.withdraw_info_display || scope.row.withdraw_info"),
|
|
'打款信息列优先读取规范清洗后的 withdraw_info_display'
|
|
);
|
|
assert(
|
|
adminWithdrawHtmlContent.includes("['wallet_type', 'madow_amount', 'rate'].includes(key)"),
|
|
'打款信息列表格循环中过滤内部英文技术字段'
|
|
);
|
|
assert(
|
|
adminWithdrawHtmlContent.includes("['市值汇率', '换算市值', '提现资产', '扣除DMEPA'].includes(key)"),
|
|
'打款信息列对「市值汇率」、「换算市值」等关键要素进行金黄色强调高亮'
|
|
);
|
|
|
|
// 11. 验证 服务层 (Withdraw.php) 写入中文标准字典与退还稳健性
|
|
console.log('\n--- 11. 服务层 (Withdraw.php) 写入「市值汇率」与「换算市值」标准字典 ---');
|
|
assert(
|
|
withdrawServiceContent.includes("$withdrawInfo['市值汇率'] = '1 DMEPA ≈ ' . $rateClean . ' 元';") &&
|
|
withdrawServiceContent.includes("$withdrawInfo['换算市值'] = $moneyClean . ' 元';"),
|
|
'applyMadow 提现单据中明确写入标准中文「市值汇率」与「换算市值」'
|
|
);
|
|
assert(
|
|
withdrawServiceContent.includes("$withdrawInfo['提现资产'] = 'DMEPA';") &&
|
|
withdrawServiceContent.includes("$withdrawInfo['扣除DMEPA'] = $deductMadow . ' DMEPA';"),
|
|
'applyMadow 写入规范大写 DMEPA 与扣除资产数量说明'
|
|
);
|
|
|
|
console.log('--------------------------------------------------------');
|
|
console.log(`测试执行结果: 通过 ${passCount} 项, 失败 ${failCount} 项`);
|
|
console.log('========================================================\n');
|
|
|
|
if (failCount > 0) {
|
|
process.exit(1);
|
|
} else {
|
|
process.exit(0);
|
|
}
|