817 lines
33 KiB
JavaScript
817 lines
33 KiB
JavaScript
const { ObjectId } = require('mongodb');
|
|
const BigNumber = require('bignumber.js');
|
|
const dayjs = require('dayjs');
|
|
const common = require('../../common');
|
|
|
|
const zytHis = require('../zyt-his');
|
|
const Sm4Util = require("../../utils/sm4-util");
|
|
const trade = require('../trade');
|
|
const format = require('./format');
|
|
const ems = require('../ems-express');
|
|
const devAmount = Number(process.env.CONFIG_DEV_UNION_PAY_AMOUNT);
|
|
|
|
let scheduleTaskIsRunning = false;
|
|
exports.main = async (ctx, db) => {
|
|
switch (ctx.type) {
|
|
case 'getRxMedicalWineOrder':
|
|
return getRxMedicalWineOrder(ctx, db);
|
|
case 'getWineOrderPayQrcode':
|
|
return getWineOrderPayQrcode(ctx, db);
|
|
case 'initRxMedicalWineOrder':
|
|
return initRxMedicalWineOrder(ctx, db);
|
|
case 'refundRxMedicalWineOrder':
|
|
return refundRxMedicalWineOrder(ctx, db);
|
|
case 'invokeMedicalWinePurchasePaySuccess':
|
|
return invokeMedicalWinePurchasePaySuccess(ctx, db);
|
|
case 'checkReceiveAddress':
|
|
return checkReceiveAddress(ctx, db);
|
|
case 'runChineseMedicineOrderSchedule':
|
|
return runChineseMedicineOrderSchedule(ctx, db);
|
|
case 'getWineShippingList':
|
|
return getWineShippingList(ctx, db);
|
|
case 'getWineShippingDetail':
|
|
return getWineShippingDetail(ctx);
|
|
case 'updateWineAfterSaleInfo':
|
|
return updateWineAfterSaleInfo(ctx, db);
|
|
case 'getWineOrderStatus':
|
|
return getWineOrderStatus(ctx, db);
|
|
case 'refundWineOrderFee':
|
|
return refundWineOrderFee(ctx, db);
|
|
case 'refundWineOrderShippingFee':
|
|
return refundWineOrderShippingFee(ctx, db);
|
|
case 'getWineOrderPatient':
|
|
return getWineOrderPatient(ctx, db);
|
|
case 'reCreateWineEmsOrder':
|
|
return reCreateWineEmsOrder(ctx, db);
|
|
case 'wineTest':
|
|
return await wineTest(ctx, db);
|
|
}
|
|
}
|
|
|
|
function validChargeAmount(amount) {
|
|
if (typeof amount !== 'number' || !(amount >= 0)) {
|
|
return false
|
|
}
|
|
// 金额最多精确到分
|
|
const cent = new BigNumber(amount).multipliedBy(100).toNumber();
|
|
return Number.isInteger(cent) && cent >= 0;
|
|
}
|
|
|
|
async function checkReceiveAddress(ctx) {
|
|
try {
|
|
const region = Array.isArray(ctx.region) ? ctx.region.filter(i => typeof i === 'string' && i.trim()) : [];
|
|
const address = typeof ctx.address === 'string' ? ctx.address.trim() : '';
|
|
if (region.length === 0 || address === '') {
|
|
return { success: false, message: '参数错误' }
|
|
}
|
|
const res = await ems.parseAddress(region.join('') + address);
|
|
if (!res || !res.success) {
|
|
return { success: false, message: `收货地址校验失败:${res?.message}` }
|
|
}
|
|
const [province, city, area] = region;
|
|
const result = await ems.checkAddress({ province, city, area, address });
|
|
return { success: true, data: result, message: '地址校验成功' };
|
|
} catch (e) {
|
|
return { success: false, message: `地址校验失败:${e?.message}` }
|
|
}
|
|
}
|
|
|
|
async function getWineShippingList(ctx, db) {
|
|
try {
|
|
const orderNo = typeof ctx.orderNo === 'string' ? ctx.orderNo.trim() : '';
|
|
const name = typeof ctx.name === 'string' ? ctx.name.trim() : '';
|
|
const receiveName = typeof ctx.receiveName === 'string' ? ctx.receiveName.trim() : '';
|
|
const backShippingNo = typeof ctx.backShippingNo === 'string' ? ctx.backShippingNo.trim() : '';
|
|
const startDate = ctx.startDate && dayjs(ctx.startDate).isValid() ? dayjs(ctx.startDate).startOf('day') : null;
|
|
const endDate = ctx.endDate && dayjs(ctx.endDate).isValid() ? dayjs(ctx.endDate).endOf('day') : null;
|
|
const page = Number.isInteger(ctx.page) && ctx.page > 0 ? ctx.page : 0;
|
|
const pageSize = Number.isInteger(ctx.pageSize) && ctx.pageSize > 0 ? ctx.pageSize : 10;
|
|
const skip = (page - 1) * pageSize;
|
|
const query = { payTime: { $exists: true } };
|
|
if (ctx.storeIds && ctx.storeIds.length > 0) {
|
|
query.storeId = { $in: ctx.storeIds };
|
|
}
|
|
if (orderNo) {
|
|
query.orderNo = orderNo;
|
|
}
|
|
if (name) {
|
|
query.name = RegExp(name, 'i');
|
|
}
|
|
if (receiveName) {
|
|
query['receiveInfo.name'] = RegExp(receiveName, 'i');
|
|
}
|
|
if (backShippingNo) {
|
|
query['afterSale.waybillNo'] = backShippingNo;
|
|
}
|
|
if (Array.isArray(ctx.statusList) && ctx.statusList.length > 0) {
|
|
query.status = { $in: ctx.statusList };
|
|
}
|
|
if (startDate) {
|
|
query.createTime = { $gte: startDate.valueOf() };
|
|
}
|
|
if (endDate) {
|
|
query.createTime = query.createTime || {};
|
|
query.createTime['$lte'] = endDate.valueOf();
|
|
}
|
|
const data = await db.collection('chinese-medicine-order').find(query).sort({ createTime: -1 }).skip(skip).limit(pageSize).toArray();
|
|
const total = await db.collection('chinese-medicine-order').countDocuments(query);
|
|
const pages = Math.ceil(total / pageSize);
|
|
return { success: true, data: { list: data, total, pages }, message: '查询订单成功' };
|
|
} catch (e) {
|
|
return { success: false, message: `获取订单失败:${e?.message}` }
|
|
}
|
|
}
|
|
|
|
async function getRxMedicalWineOrder(ctx, db) {
|
|
try {
|
|
const corpId = typeof ctx.corpId === 'string' ? ctx.corpId.trim() : '';
|
|
const id = ObjectId.isValid(ctx.id) ? new ObjectId(ctx.id) : null;
|
|
const withChargeInfo = typeof ctx.withChargeInfo === 'boolean' ? ctx.withChargeInfo : false;
|
|
if (!id) {
|
|
return { success: false, message: '参数错误' }
|
|
}
|
|
const order = await db.collection('chinese-medicine-order').findOne({ _id: id });
|
|
if (!order) {
|
|
return { success: false, message: '中药饮配方配方订单不存在' }
|
|
}
|
|
const result = { success: true, data: order, message: '查询中药饮配方配方订单成功' };
|
|
if (order.status === 'unpay' && withChargeInfo) {
|
|
const store = await db.collection('store-list').findOne({ store_id: order.storeId });
|
|
if (!store) {
|
|
return { success: false, message: '门店不存在' }
|
|
}
|
|
result.storeSaleWine = Boolean(store.saleWine);
|
|
const res = await getExpressFee(corpId, db);
|
|
if (!res.success) {
|
|
return res
|
|
}
|
|
result.deliveryCharge = res.data;
|
|
}
|
|
return result;
|
|
} catch (e) {
|
|
return { success: false, message: `查询浸酒方失败:${e?.message}` }
|
|
}
|
|
}
|
|
|
|
async function getWineOrderPayQrcode(ctx, db) {
|
|
try {
|
|
const id = ObjectId.isValid(ctx.id) ? new ObjectId(ctx.id) : null;
|
|
const name = typeof ctx.name === 'string' ? ctx.name.trim() : '';
|
|
const mobile = typeof ctx.mobile === 'string' ? ctx.mobile.trim() : '';
|
|
const region = Array.isArray(ctx.region) ? ctx.region.filter(i => typeof i === 'string' && i.trim()) : [];
|
|
const address = typeof ctx.address === 'string' ? ctx.address.trim() : '';
|
|
const paperInvoice = typeof ctx.paperInvoice === 'boolean' ? ctx.paperInvoice : false;
|
|
if (!id || name === '' || mobile === '' || region.length === 0 || address === '') {
|
|
return { success: false, message: '参数错误' }
|
|
}
|
|
if (!/^1[3456789]\d{9}$/.test(mobile)) {
|
|
return { success: false, message: '手机号格式错误' }
|
|
}
|
|
const order = await db.collection('chinese-medicine-order').findOne({ _id: id });
|
|
if (!order) {
|
|
return { success: false, message: '浸酒订单不存在' }
|
|
}
|
|
if (order.status !== 'unpay' || order.pickUpType != 'delivery') {
|
|
return { success: false, message: '当前订单状态不支持生成支付二维码' }
|
|
}
|
|
await db.collection('chinese-medicine-order').updateOne({ _id: order._id }, {
|
|
$set: {
|
|
receiveInfo: {
|
|
name,
|
|
mobile,
|
|
region,
|
|
address,
|
|
},
|
|
paperInvoice
|
|
}
|
|
})
|
|
const totalAmount = devAmount > 0 ? new BigNumber(devAmount).plus(order.shippingFee).toNumber() : order.totalFee;
|
|
const data = {
|
|
totalAmount,
|
|
businessNo: order.orderNo,
|
|
businessType: 'chineseMedicineOrder',
|
|
desc: `【震元堂】中药饮片订单`,
|
|
expireTime: order.expireTime,
|
|
}
|
|
const res = await trade.createUnionPayTrade(data);
|
|
if (!res || !res.success) {
|
|
return res
|
|
}
|
|
return { success: true, data: res.qrcode, message: '生成中药饮片订单支付二维码成功' }
|
|
} catch (e) {
|
|
return { success: false, message: `获取中药饮片订单支付二维码失败:${e?.message}` }
|
|
}
|
|
}
|
|
|
|
async function initRxMedicalWineOrder(ctx, db) {
|
|
try {
|
|
const rpNo = typeof ctx.rpNo === 'string' ? ctx.rpNo.trim() : '';
|
|
const corpId = typeof ctx.corpId === 'string' ? ctx.corpId.trim() : '';
|
|
if (!ObjectId.isValid(rpNo)) {
|
|
return { success: false, message: '参数错误' }
|
|
}
|
|
const order = await db.collection('chinese-medicine-order').findOne({ rpNo, disabled: false });
|
|
if (order) {
|
|
return { success: true, data: { status: order.status, id: order._id }, message: '该处方已经生成浸酒订单' }
|
|
}
|
|
const rx = await db.collection('diagnostic-record').findOne({ _id: new ObjectId(rpNo) });
|
|
if (!rx) {
|
|
return { success: false, message: '处方不存在' }
|
|
}
|
|
if (rx.status !== 'PASS' || rx.prescriptionType !== 'medicalWinePurchase') {
|
|
return { success: false, message: '当前处方不支持生成浸酒订单' }
|
|
}
|
|
if (Date.now() > rx.expireTime) {
|
|
return { success: false, message: '处方已过期' }
|
|
}
|
|
const data = {
|
|
createTime: Date.now(),
|
|
rpNo,
|
|
storeId: rx.drugStoreNo,
|
|
name: Sm4Util.decryptDataForSm3(rx.name),
|
|
mobile: Sm4Util.decryptDataForSm3(rx.mobile),
|
|
patientId: rx.patientId,
|
|
orderNo: rx.medOrgOrderNo,
|
|
orderId: rx.orderId,
|
|
status: rx.pickUpType === 'selfTake' ? 'completed' : 'unpay', // 自提订单默认已完成 线下支付
|
|
pickUpType: rx.pickUpType,
|
|
expireTime: rx.expireTime,
|
|
disabled: false
|
|
}
|
|
const store = await db.collection('store-list').findOne({ store_id: data.storeId });
|
|
if (!store) {
|
|
return { success: false, message: '门店不存在' }
|
|
}
|
|
data.storeName = store.name;
|
|
const wineInfo = await getWineInfo(rx.wines, db);
|
|
if (!wineInfo.success) {
|
|
return wineInfo
|
|
}
|
|
data.wines = wineInfo.data;
|
|
const res = await zytHis({ type: 'getHisMedicinePurchase', patientId: rx.patientId, orderNo: data.orderNo })
|
|
if (!res.success) {
|
|
return res
|
|
}
|
|
const total_amount = Number(res.data.total_amount);
|
|
if (!validChargeAmount(total_amount)) {
|
|
return { success: false, message: '金额格式错误' }
|
|
}
|
|
if (res.data.patientid !== rx.patientId) {
|
|
return { success: false, message: '患者ID不匹配' }
|
|
}
|
|
data.goodsFee = total_amount;
|
|
if (rx.pickUpType === 'selfTake') {
|
|
data.shippingFee = 0;
|
|
data.shippingDiscount = 0;
|
|
data.shippingOriginalFee = 0;
|
|
} else {
|
|
const res = await getExpressFee(corpId, db);
|
|
if (!res.success) {
|
|
return res
|
|
}
|
|
data.shippingFee = res.data.shippingFee;
|
|
data.shippingDiscount = res.data.shippingDiscount;
|
|
data.shippingOriginalFee = res.data.shippingOriginalFee;
|
|
}
|
|
const totalFee = new BigNumber(data.goodsFee).plus(data.shippingFee).toNumber();
|
|
data.totalFee = totalFee;
|
|
if (!validChargeAmount(totalFee)) {
|
|
return { success: false, message: '总金额计算错误' }
|
|
}
|
|
const { insertedId } = await db.collection('chinese-medicine-order').insertOne(data);
|
|
if (!insertedId) {
|
|
return { success: false, message: '生成浸酒订单失败' }
|
|
}
|
|
return { success: true, data: { status: data.status, id: insertedId }, message: '生成浸酒订单成功' }
|
|
} catch (e) {
|
|
return { success: false, message: e.message }
|
|
}
|
|
}
|
|
|
|
async function refundRxMedicalWineOrder(ctx, db) {
|
|
try {
|
|
const id = ObjectId.isValid(ctx.id) ? new ObjectId(ctx.id) : null;
|
|
if (!id) {
|
|
return { success: false, message: '参数错误' }
|
|
}
|
|
const order = await db.collection('chinese-medicine-order').findOne({ _id: id });
|
|
if (!order) {
|
|
return { success: false, message: '浸酒订单不存在' }
|
|
}
|
|
if (order.status !== 'paid') {
|
|
return { success: false, message: '当前订单状态不支持退款' }
|
|
}
|
|
const data = {
|
|
businessNo: order.orderNo,
|
|
businessType: 'chineseMedicineOrder',
|
|
tradeNo: order.tradeNo,
|
|
}
|
|
const res = await trade.refundUnionPayTrade(data);
|
|
if (!res.success) {
|
|
return res
|
|
}
|
|
return { success: true, data: res, message: '浸酒订单退款成功' }
|
|
} catch (e) {
|
|
return { success: false, message: `获取浸酒订单退款失败:${e?.message}` }
|
|
}
|
|
}
|
|
|
|
async function invokeMedicalWinePurchasePaySuccess(ctx, db) {
|
|
try {
|
|
const { tradeNo, businessNo, payTime } = ctx;
|
|
const order = await db.collection('chinese-medicine-order').findOne({ orderNo: businessNo });
|
|
if (!order) {
|
|
return { success: false, message: '浸酒订单不存在' }
|
|
}
|
|
if (order.status !== 'unpay') {
|
|
return { success: false, message: '当前订单状态不支持支付成功回调' }
|
|
}
|
|
const timestamp = payTime && dayjs(payTime).isValid() ? dayjs(payTime).valueOf() : Date.now();
|
|
await db.collection('chinese-medicine-order').updateOne({ _id: order._id }, { $set: { status: 'paid', tradeNo, payTime: timestamp, updateTime: Date.now() } });
|
|
order.status = 'paid';
|
|
order.payTime = timestamp;
|
|
order.tradeNo = tradeNo;
|
|
await syncHisWineOrderInfo(order, db)
|
|
await createDeliveryOrder(order, db);
|
|
return { success: true, message: '浸酒订单支付成功回调处理成功' }
|
|
} catch (e) {
|
|
return { success: false, message: `浸酒订单支付成功回调处理失败:${e?.message}` }
|
|
}
|
|
}
|
|
|
|
async function getWineInfo(data, db) {
|
|
const ids = data.map(i => new ObjectId(i._id));
|
|
const wines = await db.collection('chinese-medicine').find({ type: 'wine', disabled: false, _id: { $in: ids } }).toArray();
|
|
const result = [];
|
|
for (const item of data) {
|
|
const wine = wines.find(i => i._id.toString() === item._id);
|
|
if (!wine) {
|
|
return { success: false, message: `浸酒${item.name}不存在` }
|
|
}
|
|
result.push({
|
|
name: wine.name,
|
|
details: wine.details,
|
|
ingredients: wine.ingredients,
|
|
efficacy: wine.efficacy,
|
|
quantity: item.quantity,
|
|
hisId: wine.hisId,
|
|
unit: wine.unit
|
|
})
|
|
}
|
|
return { success: true, data: result }
|
|
}
|
|
|
|
async function getExpressFee(corpId, db) {
|
|
try {
|
|
const config = await db.collection('hlw-config').findOne({ corpId });
|
|
if (!config) {
|
|
return { success: false, message: '快递配用配置有误,请联系工作人员' };
|
|
}
|
|
const { wineExpressFee, wineExpressDiscountFee } = config;
|
|
const list = [wineExpressFee, wineExpressDiscountFee];
|
|
if (list.some(i => !validChargeAmount(i))) {
|
|
return { success: false, message: '快递配用配置有误,请联系工作人员' };
|
|
}
|
|
const shippingFee = new BigNumber(wineExpressFee).minus(wineExpressDiscountFee).toNumber();
|
|
if (!(validChargeAmount(shippingFee))) {
|
|
return { success: false, message: '邮政快递配用配置有误,请联系工作人员' };
|
|
}
|
|
return {
|
|
success: true,
|
|
data: {
|
|
shippingDiscount: wineExpressDiscountFee,
|
|
shippingOriginalFee: wineExpressFee,
|
|
shippingFee
|
|
},
|
|
message: '获取快递费用配置成功'
|
|
}
|
|
} catch (e) {
|
|
return { success: false, message: e.message };
|
|
}
|
|
}
|
|
|
|
async function syncHisWineOrderInfo(order, db) {
|
|
try {
|
|
if (!['paid', 'shipped'].includes(order.status)) {
|
|
return { success: false, message: '当前订单状态不支持同步' }
|
|
}
|
|
const trade = await db.collection('trades').findOne({ tradeNo: order.tradeNo }, { projection: { tradeStatus: 1, tradeNo: 1, outTradeNo: 1, totalAmount: 1 } });
|
|
if (!trade || trade.tradeStatus !== 'paid') {
|
|
return { success: false, message: '订单不存在或状态错误' }
|
|
}
|
|
const data = {
|
|
patientId: order.patientId,
|
|
orderNo: order.orderNo,
|
|
tradeNo: order.tradeNo,
|
|
outTradeNo: trade.outTradeNo,
|
|
totalAmount: order.totalFee
|
|
}
|
|
const res = await zytHis({ type: 'syncHisChargeStatus', ...data });
|
|
if (res.success) {
|
|
await db.collection('chinese-medicine-order').updateOne({ _id: order._id }, { $set: { syncHisChargeStatus: 'charged' } });
|
|
return { success: true, message: '同步浸酒订单信息成功' }
|
|
}
|
|
return res
|
|
} catch (e) {
|
|
return { success: false, message: e.message }
|
|
}
|
|
}
|
|
|
|
async function syncHisRefundStatus(order, db) {
|
|
try {
|
|
if (!['goodsFeeRefunded', 'refunded'].includes(order.status)) {
|
|
return { success: false, message: '当前订单状态不支持同步' }
|
|
}
|
|
const refundRecords = Array.isArray(order.refundRecords) ? order.refundRecords.reverse() : [];
|
|
const refund = refundRecords.find(i => i.type === 'goodsFee' && i.result === 'refunded');
|
|
if (!refund) {
|
|
return { success: false, message: '订单不存在退款记录' }
|
|
}
|
|
const data = {
|
|
patientId: order.patientId,
|
|
orderNo: order.orderNo,
|
|
refundSerialNo: refund.refundSerialNo,
|
|
}
|
|
const res = await zytHis({ type: 'syncHisRefundStatus', ...data });
|
|
if (res.success) {
|
|
await db.collection('chinese-medicine-order').updateOne({ _id: order._id }, { $set: { syncHisChargeStatus: 'refunded' } });
|
|
return { success: true, message: '同步浸酒订单信息成功' }
|
|
}
|
|
return res
|
|
} catch (e) {
|
|
return { success: false, message: e.message }
|
|
}
|
|
}
|
|
|
|
async function getWineShippingDetail(ctx) {
|
|
try {
|
|
const shippingNo = typeof ctx.shippingNo === 'string' ? ctx.shippingNo.trim() : '';
|
|
if (!shippingNo) {
|
|
return { success: false, message: '配送单号不能为空' }
|
|
}
|
|
const emsApi = require('../ems-express');
|
|
const res = await emsApi.getShippingDetail(shippingNo);
|
|
return { success: true, data: res.data, message: '获取配送详情成功' }
|
|
} catch (e) {
|
|
return { success: false, message: e.message };
|
|
}
|
|
}
|
|
|
|
async function createDeliveryOrder(order, db) {
|
|
try {
|
|
const emsApi = require('../ems-express');
|
|
const emsOrderData = format.formatEMSOrderData(order);
|
|
const { success, data } = await emsApi.createOrder(emsOrderData);
|
|
if (success && data) {
|
|
await db.collection('chinese-medicine-order').updateOne({ _id: order._id }, { $set: { status: 'shipped', shippingNo: data.waybillNo } });
|
|
return { success: true, message: 'ems订单创建成功', data: { shippingNo: data.waybillNo } };
|
|
}
|
|
return { success: false, message: '购药订单物流下单失败' };
|
|
} catch (e) {
|
|
return { success: false, message: `购药订单物流下单错误:${e.message}` };
|
|
}
|
|
}
|
|
|
|
async function updateWineAfterSaleInfo(ctx, db) {
|
|
try {
|
|
const id = typeof ctx.id === 'string' ? ctx.id.trim() : '';
|
|
if (id === '') {
|
|
return { success: false, message: "浸酒订单id不能为空" };
|
|
}
|
|
const afterSale = {};
|
|
if ('notes' in ctx && typeof ctx.notes === 'string') {
|
|
afterSale.notes = ctx.notes.trim();
|
|
}
|
|
if ('waybillNo' in ctx && typeof ctx.waybillNo === 'string') {
|
|
afterSale.waybillNo = ctx.waybillNo.trim();
|
|
}
|
|
if (afterSale.notes && afterSale.notes.length > 300) {
|
|
return { success: false, message: "售后备注不能超过300个字符" };
|
|
}
|
|
if (afterSale.waybillNo && afterSale.waybillNo.length > 100) {
|
|
return { success: false, message: "物流单号不能超过100个字符" };
|
|
}
|
|
if (Object.keys(afterSale).length === 0) {
|
|
return { success: true, message: "售后信息没有变化" };
|
|
}
|
|
const { matchedCount } = await db.collection('chinese-medicine-order').updateOne({ _id: new ObjectId(id) }, { $set: { afterSale } });
|
|
if (matchedCount > 0) {
|
|
return { success: true, message: "更新售后信息成功" };
|
|
}
|
|
return { success: false, message: "更新售后信息失败" };
|
|
} catch (e) {
|
|
return { success: false, message: `更新售后信息错误: ${e.message}` };
|
|
}
|
|
}
|
|
|
|
async function getWineOrderStatus(ctx, db) {
|
|
try {
|
|
const rpNo = ObjectId.isValid(ctx.rpNo) ? ctx.rpNo : '';
|
|
if (!rpNo) {
|
|
return { success: false, message: '参数错误' }
|
|
}
|
|
const rx = await db.collection('diagnostic-record').findOne({ _id: new ObjectId(rpNo) });
|
|
if (!rx) {
|
|
return { success: false, message: '记录不存在' }
|
|
}
|
|
const order = await db.collection('chinese-medicine-order').findOne({ rpNo });
|
|
const rxExpired = !order && Date.now() < rx.expireTime;
|
|
const payExpired = order.status === 'unpay' && Date.now() > order.expireTime;
|
|
const orderExpired = order.status === 'expired';
|
|
if (rxExpired || payExpired || orderExpired) {
|
|
return { success: true, status: 'expired' }
|
|
}
|
|
if (Date.now() < rx.expireTime && (!order || order.status === 'unpay')) {
|
|
return { success: true, status: 'unpay', expireTime: rx.expireTime }
|
|
}
|
|
return { success: true, status: order?.status, message: '查询成功' }
|
|
} catch (e) {
|
|
return { success: false, message: e.message }
|
|
}
|
|
}
|
|
|
|
async function refundWineOrderFee(ctx, db) {
|
|
try {
|
|
const applyTime = Date.now();
|
|
const id = typeof ctx.id === 'string' ? ctx.id.trim() : '';
|
|
const orderNo = typeof ctx.orderNo === 'string' ? ctx.orderNo.trim() : '';
|
|
const operator = typeof ctx.operator === 'string' ? ctx.operator.trim() : '';
|
|
const operatorId = typeof ctx.operatorId === 'string' ? ctx.operatorId.trim() : '';
|
|
const reason = typeof ctx.reason === 'string' ? ctx.reason.trim() : '';
|
|
if (!id || !orderNo || !operator || !operatorId) {
|
|
return { success: false, message: "参数不能为空" };
|
|
}
|
|
if (reason.length > 200) {
|
|
return { success: false, message: "[邮政快递]退费原因不能超过200个字符" };
|
|
}
|
|
const order = await db.collection('chinese-medicine-order').findOne({ _id: new ObjectId(id), orderNo });
|
|
if (!order) {
|
|
return { success: false, message: '浸酒订单不存在' }
|
|
}
|
|
if (['goodsFeeRefunded', 'refunded'].includes(order.status)) {
|
|
return { success: false, message: "配药订单医保费用已退费" };
|
|
}
|
|
if (!['paid', 'shipped'].includes(order.status)) {
|
|
return { success: false, message: "配药订单状态不正确" };
|
|
}
|
|
const refundOrderId = common.generateUniqueStr('3JHR');
|
|
const res = await trade.refundUnionPayTrade({
|
|
tradeNo: order.tradeNo,
|
|
businessNo: order.orderNo,
|
|
businessType: 'chineseMedicineOrder',
|
|
refundAmount: devAmount || order.goodsFee,
|
|
refundOrderId,
|
|
});
|
|
if (!res.success) {
|
|
return { success: false, message: res.message || '退费失败' };
|
|
}
|
|
const refundRecord = {
|
|
amount: order.goodsFee,
|
|
applyTime,
|
|
platform: 'unionPay',
|
|
reason,
|
|
type: 'goodsFee',
|
|
refundSerialNo: refundOrderId,
|
|
refundTime: applyTime,
|
|
result: res.success ? 'refunded' : 'refund_fail',
|
|
operator,
|
|
operatorId
|
|
}
|
|
const refundRecords = order.refundRecords || [];
|
|
refundRecords.push(refundRecord);
|
|
await db.collection('chinese-medicine-order').updateOne({ _id: order._id }, { $set: { refundRecords } });
|
|
if (order.shippingFee === 0) {
|
|
await db.collection('chinese-medicine-order').updateOne({ _id: order._id }, { $set: { status: 'refunded' } });
|
|
} else if (order.shippingFee > 0) {
|
|
await db.collection('chinese-medicine-order').updateOne({ _id: order._id }, { $set: { status: 'goodsFeeRefunded' } });
|
|
}
|
|
if (order.shippingFee === 0 && order.shippingNo) {
|
|
const emsApi = require('../ems-express');
|
|
const { success } = await emsApi.cancelOrder({ logisticsOrderNo: order.orderNo, waybillNo: order.shippingNo, cancelReason: reason });
|
|
if (success) {
|
|
await db.collection('chinese-medicine-order').updateOne({ _id: order._id }, { $set: { deliveryCancelled: true } });
|
|
}
|
|
}
|
|
return { success: true, message: "费用退费成功" };
|
|
} catch (e) {
|
|
return { success: false, message: e.message }
|
|
}
|
|
}
|
|
|
|
async function refundWineOrderShippingFee(ctx, db) {
|
|
try {
|
|
const applyTime = Date.now();
|
|
const id = typeof ctx.id === 'string' ? ctx.id.trim() : '';
|
|
const orderNo = typeof ctx.orderNo === 'string' ? ctx.orderNo.trim() : '';
|
|
const operator = typeof ctx.operator === 'string' ? ctx.operator.trim() : '';
|
|
const operatorId = typeof ctx.operatorId === 'string' ? ctx.operatorId.trim() : '';
|
|
const reason = typeof ctx.reason === 'string' ? ctx.reason.trim() : '';
|
|
if (!id || !orderNo || !operator || !operatorId) {
|
|
return { success: false, message: "参数不能为空" };
|
|
}
|
|
if (reason.length > 200) {
|
|
return { success: false, message: "[邮政快递]退费原因不能超过200个字符" };
|
|
}
|
|
const order = await db.collection('chinese-medicine-order').findOne({ _id: new ObjectId(id), orderNo });
|
|
if (!order) {
|
|
return { success: false, message: '浸酒订单不存在' }
|
|
}
|
|
if ('goodsFeeRefunded' !== order.status) {
|
|
return { success: false, message: "配药订单状态不正确" };
|
|
}
|
|
const refundOrderId = common.generateUniqueStr('3JHR');
|
|
const res = await trade.refundUnionPayTrade({
|
|
tradeNo: order.tradeNo,
|
|
businessNo: order.orderNo,
|
|
businessType: 'chineseMedicineOrder',
|
|
refundAmount: order.shippingFee,
|
|
refundOrderId,
|
|
});
|
|
const refundRecord = {
|
|
amount: order.shippingFee,
|
|
applyTime,
|
|
platform: 'unionPay',
|
|
reason,
|
|
type: 'shippingFee',
|
|
refundSerialNo: refundOrderId,
|
|
refundTime: applyTime,
|
|
result: res.success ? 'refunded' : 'refund_fail',
|
|
operator,
|
|
operatorId
|
|
}
|
|
const refundRecords = order.refundRecords || [];
|
|
refundRecords.push(refundRecord);
|
|
await db.collection('chinese-medicine-order').updateOne({ _id: order._id }, { $set: { refundRecords } });
|
|
if (!res.success) {
|
|
return { success: false, message: res.message || '退费失败' };
|
|
}
|
|
await db.collection('chinese-medicine-order').updateOne({ _id: order._id }, { $set: { status: 'refunded' } });
|
|
const emsApi = require('../ems-express');
|
|
const { success } = await emsApi.cancelOrder({ logisticsOrderNo: order.orderNo, waybillNo: order.shippingNo, cancelReason: reason });
|
|
if (success) {
|
|
await db.collection('chinese-medicine-order').updateOne({ _id: order._id }, { $set: { deliveryCancelled: true } });
|
|
}
|
|
return { success: true, message: "费用退费成功" };
|
|
} catch (e) {
|
|
return { success: false, message: e.message }
|
|
}
|
|
}
|
|
|
|
// 定时任务
|
|
// 查询 超时未支付的浸酒订单
|
|
async function runChineseMedicineOrderSchedule(ctx, db) {
|
|
if (scheduleTaskIsRunning) return;
|
|
const logText = [`${'='.repeat(8)}浸酒订单定时任务开始${'='.repeat(8)}`];
|
|
scheduleTaskIsRunning = true;
|
|
try {
|
|
// 当日未支付且超时的订单
|
|
const list = await db.collection('chinese-medicine-order').find(
|
|
{
|
|
status: 'unpay',
|
|
expireTime: { $lt: Date.now() },
|
|
createTime: { $gt: dayjs().startOf('day').valueOf() }
|
|
}).toArray();
|
|
logText.push(`[${dayjs().format('YYYY-MM-DD HH:mm:ss')}]支付超时数: ${list.length}`);
|
|
for (let item of list) {
|
|
const { status } = await trade.checkUnionPayUnpay({ businessNo: item.orderNo, businessType: 'chineseMedicineOrder' });
|
|
if (status === 'unpay') {
|
|
await db.collection('chinese-medicine-order').updateOne({ _id: item._id }, { $set: { status: 'expired' } });
|
|
} else if (status === 'refunded') {
|
|
await db.collection('chinese-medicine-order').updateOne({ _id: item._id }, { $set: { status: 'refunded' } });
|
|
}
|
|
}
|
|
// 已经支付但是没有同步his状态的同步his
|
|
const paidList = await db.collection('chinese-medicine-order').find({
|
|
status: { $in: ['paid', 'shipped'] },
|
|
syncHisChargeStatus: { $exists: false },
|
|
createTime: { $gt: dayjs().startOf('day').valueOf() },
|
|
payTime: {
|
|
$gt: dayjs().startOf('day').valueOf(),
|
|
$lt: dayjs().subtract(5, 'minute').valueOf(),
|
|
}
|
|
}).toArray();
|
|
logText.push(`[${dayjs().format('YYYY-MM-DD HH:mm:ss')}]同步支付数: ${paidList.length}`);
|
|
for (let item of paidList) {
|
|
await syncHisWineOrderInfo(item, db);
|
|
}
|
|
const refundList = await db.collection('chinese-medicine-order').find({
|
|
status: { $in: ['goodsFeeRefunded', 'refunded'] },
|
|
syncHisChargeStatus: 'charged',
|
|
refundRecords: {
|
|
$elemMatch: {
|
|
type: 'goodsFee',
|
|
result: 'refunded',
|
|
refundTime: { $gt: dayjs().startOf('day').valueOf() }
|
|
}
|
|
}
|
|
}).toArray();
|
|
logText.push(`[${dayjs().format('YYYY-MM-DD HH:mm:ss')}]同步退款数: ${refundList.length}`);
|
|
for (let item of refundList) {
|
|
await syncHisRefundStatus(item, db);
|
|
}
|
|
// 已经支付但是没有发货的 发货
|
|
const shippedList = await db.collection('chinese-medicine-order').find(
|
|
{
|
|
status: 'paid',
|
|
pickUpType: 'delivery',
|
|
disabled: false,
|
|
createTime: { $gt: dayjs().startOf('day').valueOf() },
|
|
payTime: { $lt: dayjs().subtract(3, 'minute').valueOf() }
|
|
}).toArray();
|
|
logText.push(`[${dayjs().format('YYYY-MM-DD HH:mm:ss')}]待发货数: ${shippedList.length}`);
|
|
for (let item of shippedList) {
|
|
await createDeliveryOrder(item, db);
|
|
}
|
|
// 待同步his购药订单物流信息 同步his购药订单已收取运费或已退还运费信息
|
|
const updateDeliveryOrders = await db.collection('chinese-medicine-order').find({
|
|
$or: [
|
|
{ disabled: false, status: 'shipped', shippingNo: { $exists: true }, syncHisDelivery: { $exists: false }, payTime: { $gt: dayjs().startOf('day').valueOf() } }, // 已经收取运费 未同步his
|
|
{
|
|
disabled: false, status: 'refunded', shippingNo: { $exists: true }, syncHisDelivery: { $ne: 'refunded' }, refundRecords: {
|
|
$elemMatch: {
|
|
refundTime: { $gt: dayjs().startOf('day').valueOf() }
|
|
}
|
|
}
|
|
}, // 已退还运费 未同步his
|
|
]
|
|
}).toArray();
|
|
logText.push(`[${dayjs().format('YYYY-MM-DD HH:mm:ss')}]待同步物流数: ${updateDeliveryOrders.length}`);
|
|
for (let updateDeliveryOrder of updateDeliveryOrders) {
|
|
const region = updateDeliveryOrder.receiveInfo.region || [];
|
|
const address = updateDeliveryOrder.receiveInfo.address || '';
|
|
const invoice = updateDeliveryOrder.paperInvoice ? 1 : 0;
|
|
const fullAddress = region.join('') + address;
|
|
const shippingType = 'ems';
|
|
const payTime = updateDeliveryOrder.payTime ? dayjs(updateDeliveryOrder.payTime).format('YYYY-MM-DD HH:mm:ss') : undefined;
|
|
const backFlag = updateDeliveryOrder.status === 'shipped' ? 0 : 1; // 0 收取运费 | 1 退还运费
|
|
const { success } = await zytHis({ type: 'updateMedicinePurchaseDelivery', ...updateDeliveryOrder, shippingType, fullAddress, payTime, invoice, backFlag })
|
|
if (success) {
|
|
const target = backFlag === 0 ? 'charged' : 'refunded';
|
|
await db.collection('chinese-medicine-order').updateOne({ _id: updateDeliveryOrder._id }, { $set: { syncHisDelivery: target } });
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.log('执行定时任务出现错误: ', e.message)
|
|
}
|
|
scheduleTaskIsRunning = false;
|
|
logText.push(`${'='.repeat(8)}浸酒订单定时任务结束${'='.repeat(8)}`);
|
|
logText.forEach(item => console.log(item))
|
|
}
|
|
|
|
async function getWineOrderPatient(ctx, db) {
|
|
const patientId = typeof ctx.patientId === 'string' ? ctx.patientId.trim() : '';
|
|
const orderNo = typeof ctx.orderNo === 'string' ? ctx.orderNo.trim() : '';
|
|
if (!patientId || !orderNo) {
|
|
return { success: false, message: '参数错误' }
|
|
}
|
|
try {
|
|
const order = await db.collection('chinese-medicine-order').findOne({ disabled: false, patientId, orderNo });
|
|
if (!order) {
|
|
return { success: false, message: '订单不存在' }
|
|
}
|
|
const rx = await db.collection('diagnostic-record').findOne({ _id: new ObjectId(order.rpNo) });
|
|
if (!rx) {
|
|
return { success: false, message: '处方不存在' }
|
|
}
|
|
const anotherIdNo = typeof rx.idCard === 'string' ? rx.idCard.trim() : '';
|
|
if (!anotherIdNo) {
|
|
return { success: false, message: '处方中没有患者身份证号' }
|
|
}
|
|
return await zytHis({ type: 'getHisCustomer', anotherIdNo })
|
|
} catch (e) {
|
|
return { success: false, message: e.message }
|
|
}
|
|
}
|
|
|
|
async function reCreateWineEmsOrder(ctx, db) {
|
|
const orderNo = typeof ctx.orderNo === 'string' ? ctx.orderNo.trim() : '';
|
|
if (!orderNo) {
|
|
return { success: false, message: '参数错误' }
|
|
}
|
|
try {
|
|
const order = await db.collection('chinese-medicine-order').findOne({ disabled: false, orderNo, status: 'paid', pickUpType: 'delivery' });
|
|
if (!order) {
|
|
return { success: false, message: '订单不存在' }
|
|
}
|
|
if (order.shippingNo) {
|
|
return { success: false, message: '当前订单已创建邮政订单' }
|
|
}
|
|
if (!order.tradeNo) {
|
|
return { success: false, message: '支付订单号不存在' }
|
|
}
|
|
const res1 = await trade.checkUnionPayUnpay({ businessNo: order.orderNo, businessType: 'chineseMedicineOrder' });
|
|
const { status } = res1 || {};
|
|
if (!res1 || status !== 'paid') {
|
|
return { success: false, message: '银联订单支付状态异常' }
|
|
}
|
|
const res = await createDeliveryOrder(order, db);
|
|
return res
|
|
} catch (e) {
|
|
return { success: false, message: e.message }
|
|
}
|
|
}
|
|
|
|
async function wineTest(ctx, db) {
|
|
|
|
}
|