rapid-ztx
Version:
Rapid ZTX module
346 lines (305 loc) • 9.09 kB
JavaScript
/**
* 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,
}