UNPKG

rapid-ztx

Version:

Rapid ZTX module

346 lines (305 loc) 9.09 kB
/** * Copyright (c) 2017 Lucky Byte, Inc. */ const debug = require('debug')('ztx'); const winston = require('winston'); const rapid_db = require('rapid-db'); /** * 计算银联交易成本(烟草通道) * * 参数: * amount: 金额,以分为单位 * * 返回: * 银联烟草商户交易成本,以分为单位 * * * 银联手续费分为 3 部分: * 1. 0.35%, 4 元封顶 * 2. 0.05%, 0.5 元封顶 * 3. 0.02%, 不封顶 */ const unipay_cost1 = (amount) => { if (!amount) { throw new Error('unipay_cost1 参数 amount 无效'); } const p1 = Math.min(amount / 100 * 0.35, 400); const p2 = Math.min(amount / 100 * 0.05, 50); const p3 = amount / 100 * 0.02; return Math.round(p1 + p2 + p3); } /** * 计算银联交易成本(便民通道) * * 参数: * amount: 金额,以分为单位 * * 返回: * 银联便民商户交易成本,以分为单位 * * * 银联便民通道手续费分为 2 部分: * 1. 0.24 元每笔 * 2. 0.02%, 不封顶 * * 2017-12-01 更新: * 被告知是 0.34 元每笔,无其他费 */ const unipay_cost2 = (amount) => { if (!amount) { throw new Error('unipay_cost2 参数 amount 无效'); } return 34; // return amount / 100 * 0.02 + 24; } /** * 计算银联交易成本(航旅通道) * * 参数: * amount: 金额,以分为单位 * * 返回: * 银联航旅商户交易成本,以分为单位 * * * 银联航旅通道手续费分为 0.3% + 0.02% */ const unipay_cost3 = (amount) => { if (!amount) { throw new Error('unipay_cost3 参数 amount 无效'); } return Math.round(amount / 100 * 0.32); } /** * 计算银联成本 * * 参数: * cost_type: 商户成本类型, 1-烟草, 2-便民 * amount: 交易金额,以分为单位 * * 返回: * 银联交易成本,以分为单位 */ const unipay_cost = async (cost_type, amount) => { if (cost_type == 1) { return unipay_cost1(amount); } if (cost_type == 2) { return unipay_cost2(amount); } if (cost_type == 3) { return unipay_cost3(amount); } throw new Error(`计算银联成本错: 商户成本类型[${cost_type}]无效`); } /** * 计算银联交易手续费 * * 参数: * amount: 交易金额,以分为单位 * * 烟草商户,固定每笔 8 元 */ const unipay_fee1 = async (amount) => { return 800; } /** * 计算银联交易手续费 * * 参数: * amount: 交易金额,以分为单位 * * 便民商户,固定每笔 0.5 元 */ const unipay_fee2 = async (amount) => { return 50; } /** * 计算银联交易手续费 * * 参数: * amount: 交易金额,以分为单位 * * 航旅商户,固定每笔 0.3% */ const unipay_fee3 = async (amount) => { return Math.round(amount / 100 * 0.3); } /** * 计算银联交易手续费 * * 参数: * fee_type: 手续费类型,1-烟草,2-便民, 3-航旅 * amount: 交易金额,以分为单位 */ const unipay_fee = async (fee_type, amount) => { if (fee_type == 1) { return unipay_fee1(amount); } if (fee_type == 2) { return unipay_fee2(amount); } if (fee_type == 3) { return unipay_fee3(amount); } throw new Error(`计算银联手续费错: 商户手续费类型[${fee_type}]无效`); } /** * 计算代理商交易成本 * * 参数: * agent: 代理商完整信息 * amount: 金额,以分为单位 * * 返回: * 代理商交易成本,以分为单位 * * 如果不足代理商最低成本,则按最低成本计 */ const agent_cost = async (agent, amount) => { if (!agent || !amount) { throw new Error('agent_cost 参数无效'); } if (!agent.cost || agent.cost.length == 0) { throw new Error(`代理商 ${agent.fullname} 未配置费率`); } let cost = 0; for (let i = 0; i < agent.cost.length; i++) { if (amount <= agent.cost[i].max * 100) { // 手续费(1) if (!agent.cost[i].fee) { throw new Error(`代理商 ${agent.fullname} 费率配置无效`); } cost = Math.round(amount / 100 * agent.cost[i].fee); // 手续费(1)封顶,封顶金额以元为单位存储 if (agent.cost[i].top && agent.cost[i].top > 0) { cost = Math.min(cost, parseInt(agent.cost[i].top * 100)); } // 固定成本,固定金额以元为单位存储 if (agent.cost[i].amt && agent.cost[i].amt > 0) { cost += parseInt(agent.cost[i].amt * 100); } // 手续费(2),不封顶 if (agent.cost[i].fe2 && agent.cost[i].fe2 > 0) { cost += Math.round(amount / 100 * agent.cost[i].fe2); } break; } } // 不能小于代理商最低成本 if (!agent.cost_min || agent.cost_min <= 0) { throw new Error(`代理商 ${agent.fullname} 未配置最低成本`); } return Math.max(cost, agent.cost_min * 100); } /** * 计算持卡人交易成本 * * 参数: * sumer_fee: 持卡人费率,百分比 * sumer_bot: 持卡人手续费保底,以元为单位 * sumer_top: 持卡人手续费封顶,以元为单位 * sumer_amt: 持卡人附加费,以分为单位 * amount: 金额,以分为单位 * * 返回: * 持卡人交易成本,以分为单位 */ const sumer_cost = async ( sumer_fee, sumer_bot, sumer_top, sumer_amt, amount ) => { if (!sumer_fee || !amount) { throw new Error('sumer_cost 参数无效'); } let cost = Math.round(amount / 100 * sumer_fee + 0.0001); // 手续费封顶 if (sumer_top && sumer_top > 0) { cost = Math.min(cost, sumer_top * 100); } // 附加费 if (sumer_amt && sumer_amt > 0) { cost += parseInt(sumer_amt); } // 手续费保底 if (sumer_bot && sumer_bot > 0) { cost = Math.max(cost, sumer_bot * 100); } return cost; } /** * 代理商成本保底、持卡人手续费保底 * 1. 代理商的成本不能低于银联成本,否则会参数负收益 * 2. 持卡人的手续费不能低于代理商的成本,否则代理商会产生负收益 */ const min_protect = async ( agent, _unipay_cost, _agent_cost, _sumer_cost, has_daifu ) => { let result = { unipay_cost: _unipay_cost, agent_cost: _agent_cost, sumer_cost: _sumer_cost, } // 总成本 = 银联成本 + 0.5 元代付成本 const base_cost = has_daifu ? _unipay_cost + 50 : _unipay_cost; const base_cost_txt = !has_daifu ? `银联成本[${_unipay_cost / 100}]` : `银联成本[${_unipay_cost / 100}] + 代付成本[0.5]`; // 代理商成本不能少于银联成本 + 代付成本 if (_agent_cost < base_cost) { await rapid_db.notify.warn( `代理商[${agent.fullname}]成本[${_agent_cost / 100}]` + `低于${base_cost_txt},按成本扣取` ); result.agent_cost = base_cost; } // 持卡人手续费不能少于银联成本 + 代付成本 if (_sumer_cost < base_cost) { await rapid_db.notify.warn( `持卡人手续费[${_sumer_cost / 100}]低于${base_cost_txt},按成本扣取` ); result.sumer_cost = base_cost; } // 代理商负收益保护,这里没有提高持卡人手续费,只是记录警告通知 if (_agent_cost > _sumer_cost) { await rapid_db.notify.warn( `交易会产生代理商负收益,代理商成本[${_agent_cost / 100}],` + `持卡人手续费[${_sumer_cost / 100}],代理商[${agent.fullname}]` ); } return result; } /** * 计算诺百作为一级代理的收益 * 诺百收益 = 代理商成本 * 比例(可配置) * 注意如果代理商本身是诺百,则不要调用这个函数,以免造成银盛负收益 */ // const nuob_profit = async (agent_cost) => { // if (!agent_cost) { // throw new Error('nuob_profit 参数无效'); // } // // 从配置中获取分润比例 // const params = await unique_db.one(` // select nuob_profit from rapid_ctod_params limit 1 // `); // if (params.nuob_profit < 0.1 || params.nuob_profit > 1) { // throw new Error(`一级代理分润比例配置[${params.nuob_profit}]无效`); // } // return Math.round(agent_cost * params.nuob_profit); // } /** * 计算诺百代理收益 * 诺百收益 = (代理商成本 - 银联手续费) * 0.8 */ const nuob_profit = async (agent_cost, unipay_fee) => { if (!agent_cost || !unipay_fee) { throw new Error('nuob_profit 参数无效'); } return Math.round((agent_cost - unipay_fee) * 0.8); } module.exports = { unipay_cost: unipay_cost, unipay_fee: unipay_fee, agent_cost: agent_cost, sumer_cost: sumer_cost, min_protect: min_protect, nuob_profit: nuob_profit, }