This commit is contained in:
2026-10-08 18:18:21 +08:00
parent 9cc1ff546c
commit 1e3095c05e
1911 changed files with 349551 additions and 0 deletions
@@ -0,0 +1,56 @@
'use strict';
const balanceUtil = require('./util.js');
module.exports = {
/**
* 新增资金流水
* @url admin/finance/balance/sys/add 前端调用的url参数地址
*/
main: async (event) => {
let { data = {}, userInfo, util } = event;
let { vk } = util;
const transaction = await vk.baseDao.startTransaction();
try {
const description = String(data.description || '').trim();
if (!description) {
throw new Error('说明不能为空');
}
const logData = {
description,
amount: balanceUtil.normalizeAmount(data.amount),
type: balanceUtil.normalizeType(data.type),
logTime: balanceUtil.normalizeTime(data.logTime),
operatorId: userInfo && userInfo.uid ? userInfo.uid : '',
source: data.source || 'manual'
};
const changeAmount = balanceUtil.buildBalanceChange(logData);
await balanceUtil.checkBalanceAvailable({
transaction,
vk,
changeAmount
});
const addRes = await vk.baseDao.add({
db: transaction,
dbName: 'jjx-balance-log',
dataJson: logData
});
await balanceUtil.updateBalanceWithDelta({
transaction,
vk,
delta: changeAmount,
lastLogId: addRes.id
});
await transaction.commit();
return { code: 0, msg: '' };
} catch (err) {
return await balanceUtil.rollbackTransaction({
transaction,
err
});
}
}
};
@@ -0,0 +1,57 @@
'use strict';
const balanceUtil = require('./util.js');
module.exports = {
/**
* 删除资金流水
* @url admin/finance/balance/sys/delete 前端调用的url参数地址
*/
main: async (event) => {
let { data = {}, util } = event;
let { vk } = util;
const transaction = await vk.baseDao.startTransaction();
try {
if (vk.pubfn.isNull(data._id)) {
throw new Error('流水ID不能为空');
}
const oldLog = await vk.baseDao.findByWhereJson({
db: transaction,
dbName: 'jjx-balance-log',
whereJson: {
_id: data._id
}
});
if (!oldLog) {
throw new Error('流水不存在');
}
const revertDelta = Number((-balanceUtil.buildBalanceChange(oldLog)).toFixed(2));
await balanceUtil.checkBalanceAvailable({
transaction,
vk,
changeAmount: revertDelta
});
await vk.baseDao.deleteById({
db: transaction,
dbName: 'jjx-balance-log',
id: data._id
});
await balanceUtil.updateBalanceWithDelta({
transaction,
vk,
delta: revertDelta
});
await transaction.commit();
return { code: 0, msg: '' };
} catch (err) {
return await balanceUtil.rollbackTransaction({
transaction,
err
});
}
}
};
@@ -0,0 +1,91 @@
'use strict';
const balanceUtil = require('./util.js');
module.exports = {
/**
* 查询状态
* @url admin/finance/balance/sys/getActionLog 前端调用的url参数地址
* @param {String} accNo 账号
* @param {String} reqDate 请求日期,格式:yyyyMMdd
* @param {String} reqJournalNo 请求流水号
*/
main: async (event) => {
let { data = {}, util } = event;
let { vk } = util;
let { accNo, reqDate, reqJournalNo } = data;
accNo = String(accNo || '').trim();
reqDate = String(reqDate || '').trim();
reqJournalNo = String(reqJournalNo || '').trim();
if (!accNo) {
return {
code: -1,
msg: 'accNo不能为空'
};
}
if (!reqDate) {
return {
code: -1,
msg: 'reqDate不能为空'
};
}
if (!/^\d{8}$/.test(reqDate)) {
return {
code: -1,
msg: 'reqDate格式不正确'
};
}
if (!reqJournalNo) {
return {
code: -1,
msg: 'reqJournalNo不能为空'
};
}
let res = await vk.request({
url: 'http://jjx-union-pay.gxwebsoft.com/api/union-pay-jjx/getActionLog',
method: 'POST',
dataType: 'json',
header: {
'content-type': 'application/json; charset=utf-8'
},
data: {
accNo,
reqDate,
reqJournalNo
},
timeout: 60000
});
if (res && typeof res === 'object' && typeof res.code === 'undefined') {
res.code = 0;
}
const responseObjects = balanceUtil.getRemoteResponseObjects(res);
const list = balanceUtil.pickFirstDefined([
Array.isArray(res.list) ? res.list : undefined,
Array.isArray(res.rows) ? res.rows : undefined,
Array.isArray(res.data) ? res.data : undefined,
Array.isArray(res.data && res.data.list) ? res.data.list : undefined,
Array.isArray(res.data && res.data.rows) ? res.data.rows : undefined,
Array.isArray(res.info && res.info.list) ? res.info.list : undefined,
Array.isArray(res.info && res.info.rows) ? res.info.rows : undefined,
Array.isArray(res.content && res.content.list) ? res.content.list : undefined,
Array.isArray(res.content && res.content.rows) ? res.content.rows : undefined
]) || [];
if (responseObjects.data && typeof responseObjects.data === 'object' && !Array.isArray(responseObjects.data)) {
responseObjects.data.list = list;
} else if (res && typeof res === 'object') {
res.data = {
list
};
}
return res;
}
};
@@ -0,0 +1,81 @@
'use strict';
const balanceUtil = require('./util.js');
module.exports = {
/**
* 查询余额明细
* @url admin/finance/balance/sys/getFlow 前端调用的url参数地址
* @param {String} accNo 账号
* @param {String} transDate 交易日期,格式:yyyyMMdd
*/
main: async (event) => {
let { data = {}, util } = event;
let { vk } = util;
let { accNo, transDate } = data;
accNo = String(accNo || '').trim();
transDate = String(transDate || '').trim();
if (!accNo) {
return {
code: -1,
msg: 'accNo不能为空'
};
}
if (!transDate) {
return {
code: -1,
msg: 'transDate不能为空'
};
}
if (!/^\d{8}$/.test(transDate)) {
return {
code: -1,
msg: 'transDate格式不正确'
};
}
let res = await vk.request({
url: 'http://jjx-union-pay.gxwebsoft.com/api/union-pay-jjx/getFlow',
method: 'POST',
dataType: 'json',
header: {
'content-type': 'application/json; charset=utf-8'
},
data: {
accNo,
transDate
},
timeout: 60000
});
if (res && typeof res === 'object' && typeof res.code === 'undefined') {
res.code = 0;
}
const responseObjects = balanceUtil.getRemoteResponseObjects(res);
const list = balanceUtil.pickFirstDefined([
Array.isArray(res.list) ? res.list : undefined,
Array.isArray(res.rows) ? res.rows : undefined,
Array.isArray(res.data) ? res.data : undefined,
Array.isArray(res.data && res.data.list) ? res.data.list : undefined,
Array.isArray(res.data && res.data.rows) ? res.data.rows : undefined,
Array.isArray(res.info && res.info.list) ? res.info.list : undefined,
Array.isArray(res.info && res.info.rows) ? res.info.rows : undefined,
Array.isArray(res.content && res.content.list) ? res.content.list : undefined,
Array.isArray(res.content && res.content.rows) ? res.content.rows : undefined
]) || [];
if (responseObjects.data && typeof responseObjects.data === 'object' && !Array.isArray(responseObjects.data)) {
responseObjects.data.list = list;
} else if (res && typeof res === 'object') {
res.data = {
list
};
}
return res;
}
};
@@ -0,0 +1,63 @@
'use strict';
const dayjs = require('dayjs');
const balanceUtil = require('./util.js');
module.exports = {
/**
* 查询余额
* @url admin/finance/balance/sys/getInfo 前端调用的url参数地址
* @param {String} accNo 账号
*/
main: async (event) => {
let { data = {}, util } = event;
let { vk } = util;
let { accNo } = data;
accNo = String(accNo || '').trim();
if (!accNo) {
return {
code: -1,
msg: 'accNo不能为空'
};
}
let res = await balanceUtil.requestMerchantBalance({
vk,
accNo
});
if (res && typeof res === 'object' && typeof res.code === 'undefined') {
res.code = 0;
}
const merchantBalance = balanceUtil.getRemoteMerchantBalance(res);
if (merchantBalance !== null) {
const updateTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
const syncRes = await balanceUtil.syncMerchantBalance({
vk,
accNo,
merchantBalance,
updateTime
});
const nextMerchantBalance = syncRes.merchantBalance;
if (res.data && typeof res.data === 'object') {
res.data.balance = nextMerchantBalance;
res.data.updateTime = updateTime;
} else if (res.info && typeof res.info === 'object') {
res.info.balance = nextMerchantBalance;
res.info.updateTime = updateTime;
} else if (res.content && typeof res.content === 'object') {
res.content.balance = nextMerchantBalance;
res.content.updateTime = updateTime;
} else {
res.data = {
balance: nextMerchantBalance,
updateTime
};
}
}
return res;
}
};
@@ -0,0 +1,53 @@
'use strict';
const balanceUtil = require('./util.js');
module.exports = {
/**
* 资金流水列表
* @url admin/finance/balance/sys/getList 前端调用的url参数地址
*/
main: async (event) => {
let { data = {}, util } = event;
let { vk, _ } = util;
let { pageIndex, pageSize, formData = {} } = data;
let res = { code: 0, msg: '' };
const andArr = [];
if (vk.pubfn.isNotNull(formData.type)) {
andArr.push({ type: formData.type });
}
if (vk.pubfn.isNotNull(formData.logTime) && Array.isArray(formData.logTime) && formData.logTime.length === 2) {
andArr.push({
logTime: _.gte(Number(formData.logTime[0]))
});
andArr.push({
logTime: _.lte(Number(formData.logTime[1]))
});
}
let whereJson = {};
if (andArr.length > 0) {
whereJson = _.and(andArr);
}
res = await vk.baseDao.selects({
dbName: 'jjx-balance-log',
getCount: true,
pageIndex,
pageSize,
whereJson,
sortArr: [{ name: 'logTime', type: 'desc' }, { name: '_add_time', type: 'desc' }]
});
res.rows = res.rows.map(item => ({
...item,
amount: balanceUtil.normalizeAmount(item.amount),
merchantId: item.merchantId || '',
merchantName: item.merchantName || '',
srcReqId: item.srcReqId || '',
status: typeof item.status === 'number' ? item.status : Number(item.status || 0)
}));
return res;
}
};
@@ -0,0 +1,39 @@
'use strict';
const { BALANCE_DOC_ID, getBalanceInfoList } = require('./util.js');
module.exports = {
/**
* 资金汇总
* @url admin/finance/balance/sys/getSummary 前端调用的url参数地址
*/
main: async (event) => {
let { util } = event;
let { vk } = util;
let info = await vk.baseDao.findByWhereJson({
dbName: 'jjx-balance',
whereJson: {
_id: BALANCE_DOC_ID
}
});
if (!info) {
return {
code: -1,
msg: `jjx-balance余额记录不存在: ${BALANCE_DOC_ID}`
};
}
const balanceInfoList = getBalanceInfoList(info.balanceInfo || {});
return {
code: 0,
msg: '',
data: {
balance: Number(Number(info.balance || 0).toFixed(2)),
updateTime: info.updateTime || info._update_time_str || info._add_time_str || '',
balanceInfoList
}
};
}
};
@@ -0,0 +1,75 @@
'use strict';
const balanceUtil = require('./util.js');
module.exports = {
/**
* 编辑资金流水
* @url admin/finance/balance/sys/update 前端调用的url参数地址
*/
main: async (event) => {
let { data = {}, userInfo, util } = event;
let { vk } = util;
const transaction = await vk.baseDao.startTransaction();
try {
if (vk.pubfn.isNull(data._id)) {
throw new Error('流水ID不能为空');
}
const oldLog = await vk.baseDao.findByWhereJson({
db: transaction,
dbName: 'jjx-balance-log',
whereJson: {
_id: data._id
}
});
if (!oldLog) {
throw new Error('流水不存在');
}
const description = String(data.description || '').trim();
if (!description) {
throw new Error('说明不能为空');
}
const newLog = {
description,
amount: balanceUtil.normalizeAmount(data.amount),
type: balanceUtil.normalizeType(data.type),
logTime: balanceUtil.normalizeTime(data.logTime),
operatorId: userInfo && userInfo.uid ? userInfo.uid : oldLog.operatorId || '',
source: oldLog.source || data.source || 'manual'
};
const oldChange = balanceUtil.buildBalanceChange(oldLog);
const newChange = balanceUtil.buildBalanceChange(newLog);
const delta = Number((newChange - oldChange).toFixed(2));
await balanceUtil.checkBalanceAvailable({
transaction,
vk,
changeAmount: delta
});
await vk.baseDao.updateById({
db: transaction,
dbName: 'jjx-balance-log',
id: data._id,
dataJson: newLog
});
await balanceUtil.updateBalanceWithDelta({
transaction,
vk,
delta,
lastLogId: data._id
});
await transaction.commit();
return { code: 0, msg: '' };
} catch (err) {
return await balanceUtil.rollbackTransaction({
transaction,
err
});
}
}
};
@@ -0,0 +1,381 @@
'use strict';
const dayjs = require('dayjs');
const BALANCE_DOC_ID = 'e35392d069f2104f003790b271c67c6d';
const MERCHANT_OPTIONS = [
{ accNo: 'zg000002466577', label: '广西金久信电子商务有限公司' },
{ accNo: 'zg000002460927', label: '南宁亿利通钢管有限公司' },
{ accNo: 'zg000002494918', label: '广西冀旺贸易有限公司' },
{ accNo: 'zg000002459804', label: '广西金久信电子商务有限公司' }
];
const MERCHANT_MAP = MERCHANT_OPTIONS.reduce((map, item) => {
map[item.accNo] = item.label;
return map;
}, {});
function normalizeAmount(value) {
const amount = Number(value || 0);
if (!Number.isFinite(amount)) {
throw new Error('金额格式不正确');
}
return Number(amount.toFixed(2));
}
function normalizeFenToYuan(value) {
const amount = Number(value || 0);
if (!Number.isFinite(amount)) {
throw new Error('金额格式不正确');
}
return Number((amount / 100).toFixed(2));
}
function normalizeType(type) {
if (!['income', 'expense'].includes(type)) {
throw new Error('类型不正确');
}
return type;
}
function normalizeTime(value) {
const time = Number(value || Date.now());
if (!Number.isFinite(time) || time <= 0) {
throw new Error('时间格式不正确');
}
return time;
}
function buildBalanceChange(log = {}) {
const type = normalizeType(log.type);
const amount = normalizeAmount(log.amount);
return type === 'income' ? amount : Number((-amount).toFixed(2));
}
function getMerchantLabel(accNo) {
return MERCHANT_MAP[accNo] || '';
}
function buildBalanceInfoMap(source = {}) {
const rawSource = source && typeof source === 'object' ? source : {};
const balanceInfoMap = {};
MERCHANT_OPTIONS.forEach(item => {
const current = rawSource[item.accNo] || {};
balanceInfoMap[item.accNo] = {
accNo: item.accNo,
merchantName: current.merchantName || current.label || item.label,
balance: normalizeAmount(current.balance || 0),
updateTime: current.updateTime || ''
};
});
return balanceInfoMap;
}
function getBalanceInfoList(source = {}) {
const balanceInfoMap = buildBalanceInfoMap(source);
return MERCHANT_OPTIONS.map(item => balanceInfoMap[item.accNo]);
}
function sumBalanceInfoMap(source = {}) {
const balanceInfoMap = buildBalanceInfoMap(source);
return Number(
Object.keys(balanceInfoMap).reduce((sum, accNo) => {
return sum + Number(balanceInfoMap[accNo].balance || 0);
}, 0).toFixed(2)
);
}
function getRemoteResponseObjects(res = {}) {
return {
root: res && typeof res === 'object' ? res : {},
data: res && res.data && typeof res.data === 'object' ? res.data : {},
info: res && res.info && typeof res.info === 'object' ? res.info : {},
content: res && res.content && typeof res.content === 'object' ? res.content : {}
};
}
function pickFirstDefined(values = []) {
return values.find(value => value !== undefined && value !== null && value !== '');
}
function getRemoteMerchantBalance(res = {}) {
const { root, data, info, content } = getRemoteResponseObjects(res);
const canPayAmt = pickFirstDefined([
root.canPayAmt,
data.canPayAmt,
info.canPayAmt,
content.canPayAmt
]);
if (canPayAmt !== undefined) {
return normalizeFenToYuan(canPayAmt);
}
const balanceValue = pickFirstDefined([
data.balance,
info.balance,
content.balance,
data.availableBalance,
info.availableBalance,
content.availableBalance,
data.amount,
info.amount,
content.amount
]);
if (balanceValue !== undefined) {
return normalizeAmount(balanceValue);
}
return null;
}
async function requestMerchantBalance({ vk, accNo }) {
return await vk.request({
url: 'http://jjx-union-pay.gxwebsoft.com/api/union-pay-jjx/getInfo',
method: 'POST',
dataType: 'json',
header: {
'content-type': 'application/json; charset=utf-8'
},
data: {
accNo
},
timeout: 60000
});
}
async function requestActionLog({ vk, accNo, reqDate, reqJournalNo }) {
return await vk.request({
url: 'http://jjx-union-pay.gxwebsoft.com/api/union-pay-jjx/getActionLog',
method: 'POST',
dataType: 'json',
header: {
'content-type': 'application/json; charset=utf-8'
},
data: {
accNo,
reqDate,
reqJournalNo
},
timeout: 60000
});
}
function pickOrderSet(res = {}) {
const candidates = [
res && res.orderSet,
res && res.data && res.data.orderSet,
res && res.info && res.info.orderSet,
res && res.content && res.content.orderSet,
res && res.data && Array.isArray(res.data) && res.data[0] && res.data[0].orderSet,
res && res.list && Array.isArray(res.list) && res.list[0] && res.list[0].orderSet,
res && res.rows && Array.isArray(res.rows) && res.rows[0] && res.rows[0].orderSet,
res && res.data && res.data.list && Array.isArray(res.data.list) && res.data.list[0] && res.data.list[0].orderSet,
res && res.data && res.data.rows && Array.isArray(res.data.rows) && res.data.rows[0] && res.data.rows[0].orderSet
];
for (let i = 0; i < candidates.length; i++) {
if (typeof candidates[i] === 'string' && candidates[i]) {
return candidates[i];
}
}
return '';
}
function parseOrderSet(res = {}) {
const orderSet = pickOrderSet(res);
if (!orderSet) {
return [];
}
try {
const orderList = JSON.parse(orderSet);
return Array.isArray(orderList) ? orderList : [];
} catch (err) {
console.error('parseOrderSet error', err, orderSet);
return [];
}
}
function getActionStatus(res = {}) {
const orderList = parseOrderSet(res);
if (!orderList.length) {
return null;
}
const firstOrder = orderList[0] || {};
const status = Number(firstOrder.status);
return Number.isFinite(status) ? status : null;
}
function getActionStatusTextByStatus(status) {
const statusMap = {
1: '处理中',
2: '成功',
3: '处理失败',
5: '退票',
6: '退票重提'
};
return statusMap[Number(status)] || '';
}
async function syncMerchantBalance({
vk,
accNo,
merchantBalance,
updateTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
}) {
const balanceRecord = await ensureBalanceRecord({ vk });
const balanceInfoMap = buildBalanceInfoMap(balanceRecord.balanceInfo || {});
const currentMerchantInfo = balanceInfoMap[accNo] || {
accNo,
merchantName: getMerchantLabel(accNo),
balance: 0,
updateTime: ''
};
const currentMerchantBalance = normalizeAmount(currentMerchantInfo.balance || 0);
const nextMerchantBalance = normalizeAmount(merchantBalance);
const nextBalanceInfoMap = {
...balanceInfoMap,
[accNo]: {
accNo,
merchantName: currentMerchantInfo.merchantName || getMerchantLabel(accNo),
balance: nextMerchantBalance,
updateTime
}
};
const nextTotalBalance = Number(
(Number(balanceRecord.balance || 0) - currentMerchantBalance + nextMerchantBalance).toFixed(2)
);
await vk.baseDao.updateById({
dbName: 'jjx-balance',
id: balanceRecord._id,
dataJson: {
balance: nextTotalBalance,
balanceInfo: nextBalanceInfoMap,
updateTime
}
});
return {
balance: nextTotalBalance,
merchantBalance: nextMerchantBalance,
updateTime,
balanceInfoMap: nextBalanceInfoMap
};
}
async function ensureBalanceRecord({ transaction, vk }) {
let balanceInfo = await vk.baseDao.findByWhereJson({
db: transaction,
dbName: 'jjx-balance',
whereJson: {
_id: BALANCE_DOC_ID
}
});
if (!balanceInfo) {
throw new Error(`jjx-balance余额记录不存在: ${BALANCE_DOC_ID}`);
}
return balanceInfo;
}
async function recalculateBalance({ transaction, vk, logId }) {
const res = await vk.baseDao.select({
db: transaction,
dbName: 'jjx-balance-log',
whereJson: {},
sortArr: [{ name: '_add_time', type: 'desc' }],
pageIndex: 1,
pageSize: 5000
});
const balance = Number(res.rows.reduce((sum, item) => sum + buildBalanceChange(item), 0).toFixed(2));
const balanceInfo = await ensureBalanceRecord({ transaction, vk });
await vk.baseDao.updateById({
db: transaction,
dbName: 'jjx-balance',
id: balanceInfo._id,
dataJson: {
balance,
lastLogId: logId || balanceInfo.lastLogId || ''
}
});
return balance;
}
async function checkBalanceAvailable({ transaction, vk, changeAmount, excludeLogId = '' }) {
const balanceInfo = await ensureBalanceRecord({ transaction, vk });
let currentBalance = Number(balanceInfo.balance || 0);
if (excludeLogId) {
const oldLog = await vk.baseDao.findByWhereJson({
db: transaction,
dbName: 'jjx-balance-log',
whereJson: {
_id: excludeLogId
}
});
if (!oldLog) {
throw new Error('原始流水不存在');
}
currentBalance = Number((currentBalance - buildBalanceChange(oldLog)).toFixed(2));
}
const nextBalance = Number((currentBalance + changeAmount).toFixed(2));
if (nextBalance < 0) {
throw new Error('余额不足');
}
return {
currentBalance,
nextBalance
};
}
async function updateBalanceWithDelta({ transaction, vk, delta, lastLogId = '' }) {
const balanceInfo = await ensureBalanceRecord({ transaction, vk });
const nextBalance = Number((Number(balanceInfo.balance || 0) + Number(delta || 0)).toFixed(2));
await vk.baseDao.updateById({
db: transaction,
dbName: 'jjx-balance',
id: balanceInfo._id,
dataJson: {
balance: nextBalance,
lastLogId: lastLogId || balanceInfo.lastLogId || ''
}
});
return nextBalance;
}
async function rollbackTransaction({ transaction, err }) {
try {
await transaction.rollback();
} catch (rollbackErr) {
console.error(rollbackErr);
}
return {
code: -1,
msg: err.message || '操作失败'
};
}
module.exports = {
BALANCE_DOC_ID,
MERCHANT_OPTIONS,
MERCHANT_MAP,
normalizeAmount,
normalizeFenToYuan,
normalizeType,
normalizeTime,
buildBalanceChange,
getMerchantLabel,
buildBalanceInfoMap,
getBalanceInfoList,
sumBalanceInfoMap,
getRemoteResponseObjects,
pickFirstDefined,
getRemoteMerchantBalance,
requestMerchantBalance,
requestActionLog,
pickOrderSet,
parseOrderSet,
getActionStatus,
getActionStatusTextByStatus,
syncMerchantBalance,
ensureBalanceRecord,
recalculateBalance,
checkBalanceAvailable,
updateBalanceWithDelta,
rollbackTransaction
};
@@ -0,0 +1,138 @@
'use strict';
const dayjs = require('dayjs');
const balanceUtil = require('./util.js');
const merchantMap = balanceUtil.MERCHANT_MAP;
module.exports = {
/**
* 提现
* @url admin/finance/balance/sys/withdraw 前端调用的url参数地址
*/
main: async (event) => {
let { data = {}, userInfo, util } = event;
let { vk } = util;
const transaction = await vk.baseDao.startTransaction();
try {
const merchantId = String(data.merchantId || '').trim();
if (!merchantMap[merchantId]) {
throw new Error('提现商户不正确');
}
const amount = balanceUtil.normalizeAmount(data.amount);
if (amount <= 0) {
throw new Error('提现金额必须大于0');
}
const balanceRecord = await balanceUtil.ensureBalanceRecord({
transaction,
vk
});
const balanceInfoMap = balanceUtil.buildBalanceInfoMap(balanceRecord.balanceInfo || {});
const merchantBalanceInfo = balanceInfoMap[merchantId] || {
accNo: merchantId,
merchantName: merchantMap[merchantId],
balance: 0,
updateTime: ''
};
const merchantBalance = balanceUtil.normalizeAmount(merchantBalanceInfo.balance || 0);
if (merchantBalance <= 0) {
throw new Error('当前企业余额小于等于0,无法提现');
}
if (amount > merchantBalance) {
throw new Error('提现金额不能大于当前企业余额');
}
const description = String(data.description || '').trim() || `余额提现-${merchantMap[merchantId]}`;
const requestRes = await vk.request({
method: "POST",
url: 'http://jjx-union-pay.gxwebsoft.com/api/union-pay-jjx/transByAmount',
header: {
"content-type": "application/json; charset=utf-8",
},
data: {
accNo: merchantId,
amount
},
timeout: 60000
});
console.log('requestRes', requestRes)
const code = Number(requestRes && requestRes.code);
const success = requestRes && (
code === 0 ||
code === 200 ||
requestRes.success === true ||
(typeof requestRes.code === 'undefined' && !requestRes.msg && !requestRes.message)
);
if (!success) {
throw new Error(
(requestRes && (requestRes.msg || requestRes.message)) ||
(requestRes && requestRes.content && (requestRes.content.msg || requestRes.content.message)) ||
'提现失败'
);
}
const logData = {
description,
amount,
type: 'expense',
logTime: Date.now(),
operatorId: userInfo && userInfo.uid ? userInfo.uid : '',
source: 'withdraw',
merchantId,
merchantName: merchantMap[merchantId],
srcReqId: requestRes.srcReqId,
status: 1
};
const changeAmount = balanceUtil.buildBalanceChange(logData);
await balanceUtil.checkBalanceAvailable({
transaction,
vk,
changeAmount
});
const addRes = await vk.baseDao.add({
db: transaction,
dbName: 'jjx-balance-log',
dataJson: logData
});
const updateTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
const nextMerchantBalance = Number((merchantBalance + changeAmount).toFixed(2));
const nextBalance = Number((Number(balanceRecord.balance || 0) + changeAmount).toFixed(2));
await vk.baseDao.updateById({
db: transaction,
dbName: 'jjx-balance',
id: balanceRecord._id,
dataJson: {
balance: nextBalance,
lastLogId: addRes.id,
updateTime,
balanceInfo: {
...balanceInfoMap,
[merchantId]: {
accNo: merchantId,
merchantName: merchantMap[merchantId],
balance: nextMerchantBalance,
updateTime
}
}
}
});
await transaction.commit();
return {
code: 0,
msg: '',
data: {
balance: nextBalance,
merchantBalance: nextMerchantBalance
}
};
} catch (err) {
return await balanceUtil.rollbackTransaction({
transaction,
err
});
}
}
};