Files
jjx-web-sign-only/uniCloud-tcb/cloudfunctions/router/service/client/payment.js
T

758 lines
18 KiB
JavaScript

'use strict';
const dayjs = require("dayjs");
const {
BALANCE_DOC_ID,
normalizeAmount
} = require("../admin/finance/balance/sys/util.js");
const notaryPay = require("./order/kh/util/notaryPay");
var vk; // 全局vk实例
const orderTypeList = [
'商城订单',
'金久信自营增值服务',
'保证金',
'会员升级',
'询价订单',
'加工订单',
'旧货订单',
'报价次数',
'现货广告',
'旧货加急',
'旧货次数',
'金久信学堂下载次数',
'司法调证',
'金久信签约宝次数',
'金久信自营询价',
'',
'',
'',
'',
'',
'AI积分充值'
];
// 涉及的表名
const dbName = {
//test: "vk-test", // 测试表
};
var db = uniCloud.database(); // 全局数据库引用
var _ = db.command; // 数据库操作符
var $ = _.aggregate; // 聚合查询操作符
function pickFirstDefined() {
for (let i = 0; i < arguments.length; i++) {
const value = arguments[i];
if (value !== undefined && value !== null && value !== '') {
return value;
}
}
return undefined;
}
function toFenAmount(value) {
const amount = Number(value);
if (!Number.isFinite(amount)) {
throw new Error(`支付金额格式不正确: ${value}`);
}
return Number((amount / 100).toFixed(2));
}
/**
* 权限注意:访问以下链接查看
* 文档地址:https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#内置权限
*/
var cloudObject = {
isCloudObject: true, // 标记为云对象模式
/**
* 请求前处理,主要用于调用方法之前进行预处理,一般用于拦截器、统一的身份验证、参数校验、定义全局对象等。
* 文档地址:https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#before-预处理
*/
_before: async function() {
vk = this.vk; // 将vk定义为全局对象
// let { customUtil, uniID, config, pubFun } = this.getUtil(); // 获取工具包
},
/**
* 请求后处理,主要用于处理本次调用方法的返回结果或者抛出的错误
* 文档地址:https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#after-后处理
*/
_after: async function(options) {
let {
err,
res
} = options;
if (err) {
return; // 如果方法抛出错误,直接return;不处理
}
return res;
},
/**
* 获取列表
* @url client/payment.getList 前端调用的url参数地址
*/
pub_payNotify: async function(data) {
console.log("=== 支付回调触发 ===", JSON.stringify(data));
console.log("订单号:", data.billNo || data.merOrderId);
console.log("支付状态:", data.billStatus);
let res = {
code: 0,
msg: ''
};
// 业务逻辑开始-----------------------------------------------------------
console.log("pay notify data", data)
let orderNo = data.billNo
if (!orderNo) orderNo = data.merOrderId
let payTime = null,
payAmount = null,
payNo = null
if (data.billPayment) {
const billPayment = JSON.parse(data.billPayment)
payTime = pickFirstDefined(billPayment.payTime, data.payTime, data.createTime)
payAmount = toFenAmount(pickFirstDefined(billPayment.receiptAmount, billPayment.totalAmount, data
.receiptAmount, data.totalAmount))
payNo = pickFirstDefined(billPayment.paySeqId, billPayment.seqId, data.seqId, data.targetOrderId)
} else {
payTime = pickFirstDefined(data.payTime, data.createTime)
payAmount = toFenAmount(pickFirstDefined(data.receiptAmount, data.totalAmount))
payNo = pickFirstDefined(data.seqId, data.targetOrderId)
}
const isPaid = data.billStatus === 'PAID' || data.status === 'TRADE_SUCCESS'
const payRecord = await vk.baseDao.findByWhereJson({
dbName: "jjx-order-pay-list",
whereJson: {
orderNo
}
});
if (payRecord && isPaid) {
const order = await vk.baseDao.findById({
dbName: "jjx-order",
id: payRecord.orderId
});
if (!payRecord.hasPaid) {
await vk.baseDao.updateById({
dbName: "jjx-order-pay-list",
id: payRecord._id,
dataJson: {
hasPaid: true,
paidAt: payTime,
payAmount,
payNo,
paidVoucher: "",
buyerRemark: payRecord.isNotaryFullPay ? "公证支付" : payRecord.buyerRemark,
sellerConfirm: payRecord.isNotaryFullPay ? true : payRecord.sellerConfirm,
confirmAt: payRecord.isNotaryFullPay ? payTime : payRecord.confirmAt,
payNotifyData: data
}
});
if (payRecord.isNotaryFullPay) {
await notaryPay.notifyPaySuccess({
vk,
payRecord,
order
});
}
}
if (order) {
const orderUpdate = {
orderStatus: order.orderStatus > 0 ? order.orderStatus : 1,
payTime,
payAmount,
payNo,
};
if (payRecord.isNotaryFullPay) {
orderUpdate.notaryPayStatus = 1;
orderUpdate.notaryPaidAt = payTime;
orderUpdate.notaryPaidAmount = payAmount;
orderUpdate.notaryPayListId = payRecord._id;
orderUpdate.notaryPayOrderNo = orderNo;
orderUpdate.payStatus = 2;
}
await vk.baseDao.updateById({
dbName: "jjx-order",
id: order._id,
dataJson: orderUpdate
});
}
return res;
}
let order = await vk.baseDao.findByWhereJson({
dbName: "jjx-order",
whereJson: {
orderNo
}
});
// type 0: 商品
// type 1: 自营
// type 2: 保证金
// type 3: 会员升级
// type 7: 询价次数
// orderStatus 0待支付 1已支付待发货 2已发货待收货 3已收货待完成 4已完成 5退款审核中 6退款成功 7退款失败
if (order && order.orderStatus === 0 && isPaid) {
await vk.baseDao.updateById({
dbName: "jjx-order",
id: order._id,
dataJson: {
orderStatus: 1,
payTime,
payAmount,
payNo,
}
});
if (![4, 5, 6].includes(order.type)) {
const incomeAmount = normalizeAmount(payAmount);
const orderTypeName = orderTypeList[order.type] || `类型${order.type}`;
const balanceInfo = await vk.baseDao.findByWhereJson({
dbName: "jjx-balance",
whereJson: {
_id: BALANCE_DOC_ID
}
});
if (!balanceInfo) {
throw new Error(`jjx-balance余额记录不存在: ${BALANCE_DOC_ID}`);
}
await vk.baseDao.add({
dbName: "jjx-balance-log",
dataJson: {
description: `${orderTypeName}-订单支付入账-${order.orderNo}`,
amount: incomeAmount,
type: "income",
logTime: payTime ? new Date(payTime).getTime() : Date.now(),
operatorId: order.uid || "",
source: "order_pay",
orderId: order._id,
orderNo: order.orderNo
}
});
await vk.baseDao.updateById({
dbName: "jjx-balance",
id: BALANCE_DOC_ID,
dataJson: {
balance: _.inc(incomeAmount),
_update_time: Date.now()
}
});
}
if ([2, 3, 11, 12, 13,20].includes(order.type)) {
await vk.baseDao.updateById({
dbName: "jjx-order",
id: order._id,
dataJson: {
orderStatus: 4
}
});
}
if (order.type === 0) {
const goodsList = await vk.baseDao.select({
dbName: "jjx-order-goods",
whereJson: {
orderId: order._id,
}
});
for (let i = 0; i < goodsList.rows.length; i++) {
const orderGoods = goodsList.rows[i];
const goods = await vk.baseDao.findByWhereJson({
dbName: "jjx-goods",
whereJson: {
_id: orderGoods.goodsId,
}
});
if (!goods.sales) {
await vk.baseDao.updateById({
dbName: "jjx-goods",
id: orderGoods.goodsId,
dataJson: {
sales: 1,
}
});
} else {
await vk.baseDao.updateById({
dbName: "jjx-goods",
id: orderGoods.goodsId,
dataJson: {
sales: _.inc(1),
}
})
}
}
}
if (order.type === 2) {
const goods = await vk.baseDao.findByWhereJson({
dbName: "jjx-order-goods",
whereJson: {
orderId: order._id,
}
});
const user = await vk.baseDao.findByWhereJson({
dbName: "uni-id-users",
whereJson: {
_id: order.uid,
}
});
if (!user.paidEnsure) {
await vk.baseDao.updateById({
dbName: "uni-id-users",
id: order.uid,
dataJson: {
paidEnsure: goods.goodsPrice,
}
});
} else {
await vk.baseDao.updateById({
dbName: "uni-id-users",
id: order.uid,
dataJson: {
paidEnsure: _.inc(goods.goodsPrice),
}
});
}
} else if (order.type === 3) {
const goods = await vk.baseDao.findByWhereJson({
dbName: "jjx-order-goods",
whereJson: {
orderId: order._id,
}
});
const userLevelConfig = await vk.baseDao.findByWhereJson({
dbName: "jjx-user-level",
whereJson: {
level: goods.goodsId,
}
});
let paidEnsure = 0
if (goods.goodsId === 3) {
paidEnsure = [50000, 100000, 200000][order.ensureIndex]
}
const dataJson = {
userLevel: goods.goodsId,
userGrade: 0,
upgradeExpiredAt: vk.pubfn.getOffsetTime(new Date(), {
year: 1,
mode: "after",
}),
paidEnsure: _.inc(paidEnsure),
}
if (userLevelConfig.ensureAmount && userLevelConfig.ensureAmount > 0) {
dataJson.paidEnsure = _.inc(userLevelConfig.ensureAmount)
}
const user = await vk.baseDao.updateAndReturn({
dbName: "uni-id-users",
whereJson: {
_id: order.uid,
},
dataJson
});
const messageConfig = await vk.baseDao.findByWhereJson({
dbName: "jjx-message-config",
dataJson: {
uid: order.uid
}
});
if (!messageConfig) {
await vk.baseDao.add({
dbName: "jjx-message-config",
dataJson: {
uid: order.uid,
article: true,
process: true,
old: true,
enquiry: true,
productList: [],
addressRegion: {}
}
})
}
} else if (order.type === 7) {
await vk.baseDao.updateById({
dbName: "jjx-order",
id: order._id,
dataJson: {
orderStatus: 4
}
});
const goods = await vk.baseDao.findByWhereJson({
dbName: "jjx-order-goods",
whereJson: {
orderId: order._id,
}
});
// 单次
if (goods.goodsId === '6587b034466d41a591df881c') {
// 仅针对单条询价次数
if (goods.isSingleQuote) {
const checkData = await vk.baseDao.findByWhereJson({
dbName: "jjx-user-quote-num",
whereJson: {
uid: order.uid,
type: goods.type,
sheetId: goods.sheetId,
}
});
await vk.baseDao.add({
dbName: "jjx-user-quote-num",
dataJson: {
num: checkData ? _.inc(1) : 1,
type: goods.type,
sheetId: goods.sheetId,
uid: order.uid,
}
});
} else {
await vk.baseDao.updateById({
dbName: "uni-id-users",
id: order.uid,
dataJson: {
remainQuoteNum: _.inc(1)
}
});
}
} else {
const amountItem = await vk.baseDao.findById({
dbName: 'jjx-quote-num-config',
id: goods.goodsId
})
const user = await vk.baseDao.findById({
dbName: "uni-id-users",
id: order.uid
});
let quoteExpiredAt = vk.pubfn.getOffsetTime(new Date(), {
day: amountItem.day,
mode: "after",
})
if (user.quoteExpiredAt) {
if (dayjs(user.quoteExpiredAt).isAfter(dayjs())) {
vk.pubfn.getOffsetTime(dayjs(user.quoteExpiredAt).toDate(), {
day: amountItem.day,
mode: "after",
})
}
}
await vk.baseDao.updateById({
dbName: "uni-id-users",
id: order.uid,
dataJson: {
quoteExpiredAt
}
});
}
} else if (order.type === 8) {
await vk.baseDao.updateById({
dbName: "jjx-order",
id: order._id,
dataJson: {
orderStatus: 4
}
});
const goods = await vk.baseDao.findByWhereJson({
dbName: "jjx-order-goods",
whereJson: {
orderId: order._id,
}
});
const hasData = await vk.baseDao.findByWhereJson({
dbName: "jjx-spot-ad",
whereJson: {
uid: order.uid,
province: goods.goodsId
}
})
let topExpiredAt = vk.pubfn.getOffsetTime(new Date(), {
month: goods.num,
mode: "after",
})
if (!hasData) {
await vk.baseDao.add({
dbName: "jjx-spot-ad",
dataJson: {
uid: order.uid,
province: goods.goodsId,
topExpiredAt
}
})
} else {
topExpiredAt = vk.pubfn.getOffsetTime(hasData.topExpiredAt, {
month: goods.num,
mode: "after",
})
await vk.baseDao.updateById({
dbName: "jjx-spot-ad",
id: hasData._id,
dataJson: {
topExpiredAt
}
})
}
await vk.baseDao.updateById({
dbName: "jjx-spot-goods",
id: goods.pk,
dataJson: {
topExpiredAt
}
});
} else if (order.type === 9) {
await vk.baseDao.updateById({
dbName: "jjx-order",
id: order._id,
dataJson: {
orderStatus: 4
}
});
const goods = await vk.baseDao.findByWhereJson({
dbName: "jjx-order-goods",
whereJson: {
orderId: order._id,
}
});
await vk.baseDao.updateById({
dbName: "jjx-old",
id: goods.goodsId,
dataJson: {
isUrgent: true
}
})
} else if (order.type === 10) {
await vk.baseDao.updateById({
dbName: "jjx-order",
id: order._id,
dataJson: {
orderStatus: 4
}
});
await vk.baseDao.updateById({
dbName: "uni-id-users",
id: order.uid,
dataJson: {
remainOldNum: _.inc(1)
}
});
} else if (order.type === 11) {
await vk.baseDao.updateById({
dbName: "uni-id-users",
id: order.uid,
dataJson: {
remainArticleDownloadNum: _.inc(1)
}
});
} else if (order.type === 12) {
const goods = await vk.baseDao.findByWhereJson({
dbName: "jjx-order-goods",
whereJson: {
orderId: order._id,
}
});
const contract = await vk.baseDao.findById({
dbName: "jjx-contract",
id: goods.goodsId
});
const canDownloadUidList = []
if (!contract.canDownloadUidList) {
canDownloadUidList.push(order.uid)
} else {
canDownloadUidList.push(...contract.canDownloadUidList, order.uid)
}
await vk.baseDao.updateById({
dbName: "jjx-contract",
id: goods.goodsId,
dataJson: {
canDownloadUidList
}
});
await vk.baseDao.update({
dbName: "jjx-certificate",
whereJson: {
contractId: goods.goodsId
},
dataJson: {
status: 1,
paidConfirm: true
}
});
const certificate = await vk.baseDao.findByWhereJson({
dbName: "jjx-certificate",
whereJson: {
contractId: goods.goodsId,
uid: order.uid
}
});
if (certificate.invoiceTypes !== 'none') {
await vk.baseDao.updateById({
dbName: "jjx-order",
id: order._id,
dataJson: {
isInvoice: 1,
name: certificate.companyName,
code: certificate.taxNumber,
phone: certificate.phone,
}
});
}
} else if (order.type === 13) {
const goods = await vk.baseDao.findByWhereJson({
dbName: "jjx-order-goods",
whereJson: {
orderId: order._id,
}
});
const qyb = await vk.baseDao.findByWhereJson({
dbName: "jjx-qyb",
whereJson: {
_id: goods.goodsId
}
});
const user = await vk.baseDao.findByWhereJson({
dbName: "uni-id-users",
whereJson: {
_id: order.uid,
}
});
const remainNum = user.qybNum + qyb.getNum;
await vk.baseDao.updateById({
dbName: "uni-id-users",
id: order.uid,
dataJson: {
qybNum: _.inc(qyb.getNum)
}
});
await vk.baseDao.updateById({
dbName: "jjx-order",
id: order._id,
dataJson: {
remainNum
}
});
} else if (order.type === 20) {
// 积分充值到账
const goods = await vk.baseDao.findByWhereJson({
dbName: "jjx-order-goods",
whereJson: {
orderId: order._id
}
});
if (goods) {
const points = parseInt(goods.goodsName.replace('积分充值_', '').replace('积分', ''));
if (points > 0) {
// 增加积分余额
const userPoints = await vk.baseDao.findByWhereJson({
dbName: "jjx-user-points",
whereJson: {
_id: order.uid
}
});
if (userPoints) {
await vk.baseDao.updateById({
dbName: "jjx-user-points",
id: order.uid,
dataJson: {
balance: _.inc(points),
total_earned: _.inc(points),
update_time: new Date()
}
});
} else {
await vk.baseDao.add({
dbName: "jjx-user-points",
dataJson: {
_id: order.uid,
balance: points,
total_earned: points,
total_spent: 0,
gift: 0,
update_time: new Date()
}
});
}
// 记录流水
const updatedPoints = await vk.baseDao.findById({
dbName: "jjx-user-points",
id: order.uid
});
await vk.baseDao.add({
dbName: "jjx-points-log",
dataJson: {
user_id: order.uid,
type: 'earn',
amount: points,
balance_after: updatedPoints ? updatedPoints.balance : points,
reason: '积分充值(' + order.offAmount + '元)',
biz_type: 'recharge',
biz_id: order._id,
_add_time: new Date()
}
});
}
}
await vk.baseDao.updateById({
dbName: "jjx-order",
id: order._id,
dataJson: {
orderStatus: 4
}
});
}
}
if (!order) {
console.log('order not found')
order = await vk.baseDao.findByWhereJson({
dbName: "jjx-order-pay-list",
whereJson: {
orderNo
}
});
console.log('pay list order data', order)
if (order && !order.sellerConfirm && (data.billStatus === 'PAID' || data.status ===
'TRADE_SUCCESS')) {
await vk.baseDao.updateById({
dbName: "jjx-order-pay-list",
id: order._id,
dataJson: {
// sellerConfirm: true,
hasPaid: true,
paidAt: vk.pubfn.timeFormat(new Date(), "yyyy-MM-dd hh:mm:ss"),
// confirmAt: vk.pubfn.timeFormat(new Date(), "yyyy-MM-dd hh:mm:ss"),
}
});
}
}
// 业务逻辑结束-----------------------------------------------------------
return res;
},
/**
* 模板函数
* @url client/payment.test 前端调用的url参数地址
*/
test: async function(data) {
let res = {
code: 0,
msg: ''
};
let {
uid
} = this.getClientInfo(); // 获取客户端信息
// 业务逻辑开始-----------------------------------------------------------
// 业务逻辑结束-----------------------------------------------------------
return res;
},
};
module.exports = cloudObject;