1227 lines
52 KiB
JavaScript
1227 lines
52 KiB
JavaScript
const dayjs = require("dayjs");
|
||
const validator = require('../../utils/validator.js');
|
||
const { ObjectId } = require("mongodb");
|
||
const tradeApi = require('../trade');
|
||
const hlwConfigApi = require('../hlw-config');
|
||
const BigNumber = require('bignumber.js');
|
||
const Sm4Util = require('../../utils/sm4-util');
|
||
const zytHis = require('../zyt-his');
|
||
const types = require('./types');
|
||
const format = require('./format');
|
||
const { buildHybridSearchQuery } = require('../diagnostic-record/format');
|
||
const { output } = types;
|
||
|
||
const HisPayStatus = {
|
||
0: '已收费',
|
||
1: '已退费',
|
||
5: '未收费',
|
||
x: '已作废',
|
||
}
|
||
|
||
let scheduleTaskIsRunning = false; // 定时任务是否正在运行
|
||
let db
|
||
|
||
module.exports = async (item, mongodb) => {
|
||
db = mongodb;
|
||
switch (item.type) {
|
||
case "getRxMedicinePurchaseOrderId":
|
||
return await getRxMedicinePurchaseOrderId(item);
|
||
case "addMedicinePurchaseOrder":
|
||
return await addMedicinePurchaseOrder(item);
|
||
case "getMedicinePurchaseOrder":
|
||
return await getMedicinePurchaseOrder(item);
|
||
case "getMedicinePurchaseOrderList":
|
||
return await getMedicinePurchaseOrderList(item);
|
||
case "getMedicinePurchaseShippingList":
|
||
// 新增接口:供 PC HLWSHIPPINGLIST 使用,支持更多筛选条件
|
||
return await getMedicinePurchaseShippingList(item);
|
||
case "getMedicinePurchaseOrderDetail":
|
||
return await getMedicinePurchaseOrderDetail(item);
|
||
case "getMedicineOrderTradeNo":
|
||
return await getMedicineOrderTradeNo(item);
|
||
case "reloadYbPayStatus":
|
||
return await reloadYbPayStatus(item);
|
||
case "reloadZfPayStatus":
|
||
return await reloadZfPayStatus(item);
|
||
case "getCostDetails":
|
||
return await getCostDetails(item);
|
||
case "invokeOnlineMedicinePurchasePaySuccess":
|
||
return await invokeOnlineMedicinePurchasePaySuccess(item);
|
||
case "getOrderInvoice":
|
||
return await getOrderInvoice(item);
|
||
case "getShippingDetail":
|
||
return await getShippingDetail(item);
|
||
case "runMedicinePurchaseOrderSchedule":
|
||
return await runMedicinePurchaseOrderSchedule(item);
|
||
case "refundMedicinePurchaseOrderYbFee":
|
||
return await refundMedicinePurchaseOrderYbFee(item);
|
||
case "refundMedicinePurchaseOrderSelfFee":
|
||
return await refundMedicinePurchaseOrderSelfFee(item);
|
||
case "purchaseTest":
|
||
return await purchaseTest(item);
|
||
case "updateAfterSaleInfo":
|
||
return await updateAfterSaleInfo(item);
|
||
case "getLastestPurchaseOrder":
|
||
return await getLastestPurchaseOrder(item);
|
||
case "getPatientPurchaseOrderList":
|
||
return await getPatientPurchaseOrderList(item);
|
||
case "getHighFreqAddressOrders":
|
||
return await getHighFreqAddressOrders(item);
|
||
}
|
||
}
|
||
|
||
function validMedicineAmount(amount) {
|
||
if (typeof amount !== 'number' || !(amount >= 0)) {
|
||
return false
|
||
}
|
||
// 金额最多精确到分
|
||
const cent = new BigNumber(amount).multipliedBy(100).toNumber();
|
||
return Number.isInteger(cent)
|
||
}
|
||
|
||
async function generatePickupCode(db, type = 'fengniao-pickup-code') {
|
||
const key = dayjs().format('YYYY-MM-DD');
|
||
const collection = db.collection('sequence-counter');
|
||
|
||
const result = await collection.findOneAndUpdate(
|
||
{ key, type }, // 添加 type 字段区分不同场景
|
||
{
|
||
$inc: { sequence: 1 },
|
||
$setOnInsert: { key, type }
|
||
},
|
||
{
|
||
upsert: true,
|
||
returnDocument: 'after'
|
||
}
|
||
);
|
||
const sequence = result.sequence;
|
||
return `${String(sequence).padStart(3, '0')}`;
|
||
}
|
||
|
||
async function createDeliveryOrder(order) {
|
||
try {
|
||
if (order.shippingType === 'fengniao') {
|
||
const fengniaoApi = require('../fengniao');
|
||
// 查询蜂鸟配送订单是否已经存在 如果存在则更新物流单号 如果不存在则创建订单
|
||
const detailRes = await fengniaoApi.main({ type: 'getOrderDetail', orderNo: order.orderNo });
|
||
const { data, unexist } = detailRes;
|
||
if (data && data.shippingNo) {
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: { shippingNo: data.shippingNo } });
|
||
return { success: true, message: '蜂鸟配送订单已存在', data: { shippingNo: data.shippingNo } };
|
||
}
|
||
if (unexist === true) {
|
||
const pickupCode = await generatePickupCode(db);
|
||
const fengniaoOrderData = format.formatFengniaoOrderData(order, pickupCode);
|
||
const { shippingNo } = await fengniaoApi.main({ type: 'createOrder', data: fengniaoOrderData });
|
||
if (shippingNo) {
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: { shippingNo, pickupCode } });
|
||
return { success: true, message: '蜂鸟配送订单创建成功', data: { shippingNo } };
|
||
}
|
||
}
|
||
} else if (order.shippingType === 'ems') {
|
||
const emsApi = require('../ems-express');
|
||
const emsOrderData = format.formatEMSOrderData(order);
|
||
const { success, data } = await emsApi.createOrder(emsOrderData);
|
||
if (success && data) {
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: { 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 getMedicinePurchaseOrder(ctx) {
|
||
try {
|
||
if (typeof ctx.accountId !== 'string' || ctx.accountId.trim() === '') {
|
||
return { success: false, message: "账号id不能为空" };
|
||
}
|
||
if (typeof ctx.id !== 'string' || ctx.id.trim() === '') {
|
||
return { success: false, message: "配药订单id不能为空" };
|
||
}
|
||
const order = await db.collection('medicine-purchase-order').findOne({ accountId: ctx.accountId.trim(), _id: new ObjectId(ctx.id) }, { projection: output.orderDetail });
|
||
if (!order) {
|
||
return { success: false, message: "订单不存在" };
|
||
}
|
||
// 主动查询his订单支付状态, 如果支付状态变更, 则更新购药订单状态
|
||
if (order.status === 'unpay') {
|
||
const res = await getHisMedicinePurchase(order.patientId, order.orderNo);
|
||
if (res && res.success) {
|
||
if (res.data.pay_mark === '0') {
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: { status: 'ybPaid' } });
|
||
order.status = 'ybPaid';
|
||
}
|
||
else if (res.data.pay_mark === '1') {
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: { status: 'refunded' } });
|
||
order.status = 'refunded';
|
||
}
|
||
}
|
||
}
|
||
// 未支付的订单, 如果已过期, 则更新购药订单状态为已过期
|
||
else if (order.status === 'unpay' && dayjs(order.expireTime).isBefore(dayjs())) {
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: { status: 'expired' } });
|
||
order.status = 'expired';
|
||
}
|
||
order.anotherName = order.name; // 支付宝医保支付需要加密后的姓名和证件号
|
||
order.name = Sm4Util.decryptDataForSm3(order.name);
|
||
|
||
const result = { success: true, message: "查询购药订单成功", data: order };
|
||
if (ctx.withExpressInfo) {
|
||
const expressFeeRes = await getExpressFee(ctx.corpId.trim(), db);
|
||
if (!expressFeeRes.success) {
|
||
return expressFeeRes;
|
||
}
|
||
result.exprssFee = expressFeeRes.data;
|
||
}
|
||
return result;
|
||
} catch (e) {
|
||
return { success: false, message: e.message };
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取购药订单交易单号以及支付类型
|
||
* @param {Object} ctx 请求参数
|
||
* @param {string} ctx.accountId 账号id
|
||
* @param {string} ctx.id 购药订单id
|
||
* @param {string} ctx.shippingType 配送方式
|
||
* @param {string} ctx.receiveName 收货人姓名
|
||
* @param {string} ctx.receivePhone 收货人手机号
|
||
* @param {string[]} ctx.receiveRegion 收货人地区
|
||
* @param {string} ctx.receiveAddress 收货人地址
|
||
* @param {number} ctx.receiveLatitude 收货人纬度
|
||
* @returns
|
||
*/
|
||
async function getMedicineOrderTradeNo(ctx) {
|
||
try {
|
||
const accountId = typeof ctx.accountId === 'string' ? ctx.accountId.trim() : '';
|
||
const id = typeof ctx.id === 'string' ? ctx.id.trim() : '';
|
||
if (accountId === '' || id === '') {
|
||
return { success: false, message: "账号id或购药订单id不能为空" };
|
||
}
|
||
const order = await db.collection('medicine-purchase-order').findOne({ accountId, _id: new ObjectId(id) });
|
||
if (!order) {
|
||
return { success: false, message: "购药订单不存在" };
|
||
}
|
||
if (order.status === 'unpay') {
|
||
const shippingType = typeof ctx.shippingType === 'string' ? ctx.shippingType.trim() : '';
|
||
const receiveName = typeof ctx.receiveName === 'string' ? ctx.receiveName.trim() : '';
|
||
const receivePhone = typeof ctx.receivePhone === 'string' ? ctx.receivePhone.trim() : '';
|
||
const receiveRegion = Array.isArray(ctx.receiveRegion) ? ctx.receiveRegion.map(i => typeof i == 'string' && i.trim()) : [];
|
||
const receiveAddress = typeof ctx.receiveAddress === 'string' ? ctx.receiveAddress.trim() : '';
|
||
const receiveLatitude = typeof ctx.receiveLatitude === 'number' ? ctx.receiveLatitude : 0;
|
||
const receiveLongitude = typeof ctx.receiveLongitude === 'number' ? ctx.receiveLongitude : 0;
|
||
let receiveData = { pass: false, msg: '' };
|
||
if (!['ems', 'fengniao'].includes(shippingType)) {
|
||
receiveData.msg = "配送方式无效";
|
||
receiveData.pass = false;
|
||
} else if (receiveName === '') {
|
||
receiveData.msg = "收货人姓名不能为空";
|
||
receiveData.pass = false;
|
||
} else if (receivePhone === '') {
|
||
receiveData.msg = "收货人手机号不能为空";
|
||
receiveData.pass = false;
|
||
} else if (!validator.isMobile(receivePhone)) {
|
||
receiveData.msg = "收货人手机号格式不正确";
|
||
receiveData.pass = false;
|
||
} else if (receiveRegion.length < 1 || receiveRegion.length > 3 || receiveRegion.some(i => typeof i !== 'string' || i.trim() === '' || i.length > 30)) {
|
||
receiveData.msg = "收货人地区格式不正确";
|
||
receiveData.pass = false;
|
||
} else if (receiveAddress === '') {
|
||
receiveData.msg = "收货人地址不能为空";
|
||
receiveData.pass = false;
|
||
} else if (receiveAddress.length > 200) {
|
||
receiveData.msg = "收货人地址不能超过200个字";
|
||
receiveData.pass = false;
|
||
} else if (typeof receiveLatitude !== 'number' || typeof receiveLongitude !== 'number') {
|
||
receiveData.msg = "收货人经纬度格式不正确";
|
||
receiveData.pass = false;
|
||
} else {
|
||
receiveData.pass = true;
|
||
}
|
||
// 之前没有保存过收货地址 校验收货地址信息
|
||
if (!order.receiveName && !receiveData.pass) {
|
||
return { success: false, message: receiveData.msg };
|
||
}
|
||
const expressFeeRes = await getExpressFee(ctx.corpId.trim(), db);
|
||
if (!expressFeeRes.success) {
|
||
return expressFeeRes;
|
||
}
|
||
const { shippingFee, shippingDiscount, shippingOriginalFee } = expressFeeRes.data[shippingType];
|
||
|
||
if (receiveData.pass) {
|
||
const updateRes = await db.collection('medicine-purchase-order').updateOne({ _id: new ObjectId(id) }, { $set: { shippingType, shippingFee, shippingDiscount, shippingOriginalFee, receiveName, receivePhone, receiveRegion, receiveAddress, receiveLatitude, receiveLongitude } });
|
||
if (!updateRes.matchedCount) {
|
||
return { success: false, message: "更新收货地址信息失败" };
|
||
}
|
||
}
|
||
}
|
||
if (order.status === 'unpay') {
|
||
const orderRes = await getHisMedicinePurchase(order.patientId, order.orderNo);
|
||
if (!orderRes || !orderRes.success) return orderRes;
|
||
if (!['0', '5'].includes(orderRes.data.pay_mark)) {
|
||
return { success: false, message: `购药订单支付状态异常:${HisPayStatus[orderRes.data.pay_mark] || '未知状态'}` };
|
||
}
|
||
if (orderRes.data.pay_mark === '5' && order.expireTime && dayjs(order.expireTime).isBefore(dayjs())) {
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: { status: 'expired' } });
|
||
return { success: false, message: "购药订单已过期", statusChanged: true };
|
||
}
|
||
if (orderRes.data.pay_mark === '5') {
|
||
return { success: true, message: "获取交易号成功", tradeNo: order.orderNo, payType: 'ybPay' };
|
||
}
|
||
if (orderRes.data.pay_mark === '0') {
|
||
return await settleZFMoney(order)
|
||
}
|
||
}
|
||
else if (order.status === 'ybPaid') {
|
||
return await settleZFMoney(order)
|
||
}
|
||
else if (order.status === 'expired') {
|
||
return { success: false, message: "购药订单已过期", statusChanged: true };
|
||
}
|
||
else if (order.status === 'shipped') {
|
||
return { success: true, message: "购药订单已支付", statusChanged: true };
|
||
}
|
||
else if (order.status === 'refunded') {
|
||
return { success: false, message: "购药订单已退款", statusChanged: true };
|
||
}
|
||
return { success: false, message: "购药订单状态不正确" };
|
||
} catch (e) {
|
||
return { success: false, message: e.message };
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取处方购药订单id, 没有购药订单则创建购药订单
|
||
* @param {Object} ctx 请求参数
|
||
* @param {string} ctx.corpId 机构id
|
||
* @param {string} ctx.accountId 账号id
|
||
* @param {string} ctx.rpNo 关联处方订单
|
||
* @returns
|
||
*/
|
||
async function getRxMedicinePurchaseOrderId(ctx) {
|
||
try {
|
||
if (typeof ctx.corpId !== 'string' || ctx.corpId.trim() === '') {
|
||
return { success: false, message: "机构id不能为空" };
|
||
}
|
||
if (typeof ctx.accountId !== 'string' || ctx.accountId.trim() === '') {
|
||
return { success: false, message: "账号id不能为空" };
|
||
}
|
||
if (typeof ctx.rpNo !== 'string' || ctx.rpNo.trim() === '') {
|
||
return { success: false, message: "关联处方订单不能为空" };
|
||
}
|
||
const record = await db.collection('medicine-purchase-order').findOne({ rpNo: ctx.rpNo.trim(), accountId: ctx.accountId.trim() });
|
||
if (record && record.status === 'unpay' && dayjs(record.expireTime).isBefore(dayjs())) {
|
||
return { success: true, message: "获取处方购药订单成功", id: record._id.toString(), status: 'expired' };
|
||
} else if (record) {
|
||
return { success: true, message: "获取处方购药订单成功", id: record._id.toString(), status: record.status };
|
||
}
|
||
const rx = await db.collection('diagnostic-record').findOne({ _id: new ObjectId(ctx.rpNo.trim()), accountId: ctx.accountId.trim() });
|
||
if (!rx) {
|
||
return { success: false, message: "处方不存在" };
|
||
}
|
||
if (rx.prescriptionType !== 'onlineMedicinePurchase') {
|
||
return { success: false, message: "暂只支持配药订单" };
|
||
}
|
||
if (rx.status !== 'PASS') {
|
||
return { success: false, message: "处方状态不正确, 暂不支持购药" };
|
||
}
|
||
if (!rx.expireTime || dayjs(rx.expireTime).isBefore(dayjs())) {
|
||
return { success: false, message: "处方已过期, 暂不支持购药" };
|
||
}
|
||
if (!Array.isArray(rx.drugs) || rx.drugs.length === 0) {
|
||
return { success: false, message: "处方药品信息为空, 暂不支持购药" };
|
||
}
|
||
const patinetInfo = await getPatientRegInfo(rx.idCard, rx.name)
|
||
if (!patinetInfo.success) {
|
||
return patinetInfo;
|
||
}
|
||
const { regFee } = patinetInfo;
|
||
const orderNo = rx.medOrgOrderNo;
|
||
const data = {
|
||
accountId: ctx.accountId.trim(),
|
||
anotherIdNo: rx.idCard, // 亲情付 需要
|
||
anotherName: rx.name, // 亲情付 需要
|
||
corpId: typeof ctx.corpId === 'string' ? ctx.corpId.trim() : undefined,
|
||
createTime: Date.now(),
|
||
disabled: false,
|
||
drugs: rx.drugs.map(med => ({
|
||
_id: med._id,
|
||
chargeCode: med.hisChargeInfo.drugId,
|
||
drugName: med.drugName,
|
||
insuranceCode: med.insurance_code,
|
||
price: med.hisChargeInfo.drugPrice,
|
||
quantity: med.quantity,
|
||
spec: med.specification,
|
||
totalPrice: med.hisChargeInfo.drugSumamt,
|
||
})),
|
||
expireTime: rx.expireTime,
|
||
idCard: rx.idCard,
|
||
name: rx.name,
|
||
orderId: rx.orderId,
|
||
orderNo,
|
||
patientId: rx.patientId,
|
||
regFee,
|
||
rpNo: rx._id.toString(),
|
||
status: 'unpay',
|
||
blhno: rx.blhno
|
||
}
|
||
const drugFee = data.drugs.reduce((acc, med) => {
|
||
return acc.plus(med.totalPrice > 0 ? med.totalPrice : 0);
|
||
}, new BigNumber(0));
|
||
data.drugFee = drugFee.toNumber();
|
||
const { insertedId } = await db.collection('medicine-purchase-order').insertOne(data);
|
||
if (!insertedId) {
|
||
return { success: false, message: "新增购药订单失败" };
|
||
}
|
||
return { success: true, message: "新增购药订单成功", id: insertedId.toString(), status: 'unpay' };
|
||
} catch (e) {
|
||
return { success: false, message: e.message };
|
||
}
|
||
}
|
||
|
||
async function getTradeNo(order) {
|
||
try {
|
||
const data = {
|
||
totalAmount: order.shippingFee,
|
||
businessNo: order.orderNo,
|
||
businessType: 'onlineMedicinePurchase',
|
||
desc: '震元配药订单配送费',
|
||
openId: order.accountId,
|
||
}
|
||
const { success, message, tradeNo, paid } = await tradeApi.getAlipayTradeNo(data);
|
||
if (success && paid) {
|
||
await reloadZfPayStatus({ tradeNo, id: order._id.toString() });
|
||
return { success: true, message: "购药订单已经支付", statusChanged: true };
|
||
}
|
||
if (success && tradeNo) {
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: { tradeNo } });
|
||
return { success: true, message: "获取交易号成功", tradeNo };
|
||
}
|
||
if (success && refunded) {
|
||
return { success: true, message: "购药订单已经退款", statusChanged: true };
|
||
}
|
||
return { success: false, message: message };
|
||
} catch (e) {
|
||
return { success: false, message: e.message };
|
||
}
|
||
}
|
||
|
||
async function settleZFMoney(order) {
|
||
try {
|
||
// 根据配送费 判断是否需要支付配送费
|
||
// 1.需要 获取配送费支付流水号 返回前端
|
||
// 2.不需要 更新购药订单状态为待配送状态 并调用物流下单接口
|
||
if (order.shippingFee > 0) {
|
||
const tradeRes = await getTradeNo(order);
|
||
if (tradeRes.success && tradeRes.tradeNo) {
|
||
return { success: true, message: "获取交易号成功", tradeNo: tradeRes.tradeNo, payType: 'alipay' };
|
||
}
|
||
if (tradeRes.success && tradeRes.statusChanged) {
|
||
return { success: true, message: '购药订单支付状态已经变更, 请刷新', statusChanged: true }
|
||
}
|
||
return tradeRes;
|
||
} else if (order.shippingFee === 0) {
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: { status: 'shipped', payTime: Date.now() } });
|
||
if (!order.shippingNo) {
|
||
await createDeliveryOrder(order);
|
||
}
|
||
return { success: true, message: '购药订单支付状态已经变更, 请刷新', statusChanged: true }
|
||
}
|
||
} catch (e) {
|
||
return { success: false, message: `购药订单自费结算错误: ${e.message}` }
|
||
}
|
||
}
|
||
|
||
async function getMedicinePurchaseOrderList(ctx) {
|
||
try {
|
||
const page = parseInt(ctx.page) > 0 ? parseInt(ctx.page) : 1;
|
||
const pageSize = parseInt(ctx.pageSize) > 0 ? parseInt(ctx.pageSize) : 10;
|
||
const query = { disabled: false };
|
||
if (typeof ctx.accountId == 'string' && ctx.accountId.trim() !== '') {
|
||
query.accountId = ctx.accountId.trim();
|
||
}
|
||
if (typeof ctx.name == 'string' && ctx.name.trim() !== '') {
|
||
query.name = { $regex: ".*" + ctx.name.trim() + ".*", $options: "i" };
|
||
}
|
||
if (Array.isArray(ctx.statusList) && ctx.statusList.length) {
|
||
query.status = { $in: ctx.statusList };
|
||
}
|
||
if (ctx.startDate && dayjs(ctx.startDate).isValid()) {
|
||
query.createTime = { $gte: dayjs(ctx.startDate).startOf('day').valueOf() };
|
||
}
|
||
if (ctx.endDate && dayjs(ctx.endDate).isValid()) {
|
||
query.createTime = {
|
||
...(query.createTime || {}),
|
||
$lte: dayjs(ctx.endDate).endOf('day').valueOf()
|
||
};
|
||
}
|
||
|
||
const total = await db.collection('medicine-purchase-order').countDocuments(query);
|
||
const list = await db.collection('medicine-purchase-order').find(query).sort({ createTime: -1 }).skip((page - 1) * pageSize).limit(pageSize).toArray();
|
||
return { success: true, message: "查询购药订单列表成功", list, total, page, pageSize, pages: Math.ceil(total / pageSize) };
|
||
} catch (e) {
|
||
return { success: false, message: e.message };
|
||
}
|
||
}
|
||
|
||
async function getMedicinePurchaseShippingList(ctx) {
|
||
try {
|
||
const page = parseInt(ctx.page, 10) > 0 ? parseInt(ctx.page, 10) : 1;
|
||
const pageSize = parseInt(ctx.pageSize, 10) > 0 ? parseInt(ctx.pageSize, 10) : 10;
|
||
const ids = Array.isArray(ctx.ids) ? ctx.ids.filter(i => ObjectId.isValid(i)).map(i => new ObjectId(i)) : null;
|
||
|
||
// 基础查询条件:只查询未禁用的数据
|
||
const query = { disabled: false };
|
||
const andConditions = [];
|
||
|
||
// 机构维度隔离(PC 端按机构查看;患者端可以不传 corpId)
|
||
if (typeof ctx.corpId === 'string' && ctx.corpId.trim() !== '') {
|
||
query.corpId = ctx.corpId.trim();
|
||
}
|
||
|
||
// 兼容账号维度的查询(如患者端按 accountId 查询)
|
||
if (typeof ctx.accountId === 'string' && ctx.accountId.trim() !== '') {
|
||
query.accountId = ctx.accountId.trim();
|
||
}
|
||
|
||
// 患者姓名查询:兼容旧的 name 字段和新的 patientName 字段
|
||
const rawName =
|
||
(typeof ctx.patientName === 'string' && ctx.patientName.trim() !== '' && ctx.patientName.trim()) ||
|
||
(typeof ctx.name === 'string' && ctx.name.trim() !== '' && ctx.name.trim()) ||
|
||
'';
|
||
if (rawName) {
|
||
// 使用混合明文/密文查询,兼容历史数据
|
||
const condition = buildHybridSearchQuery('name', rawName, false);
|
||
if (condition) {
|
||
andConditions.push(condition);
|
||
}
|
||
}
|
||
|
||
// 收件人姓名模糊查询(字段未加密,可直接正则)
|
||
if (typeof ctx.recipientName === 'string' && ctx.recipientName.trim() !== '') {
|
||
andConditions.push({
|
||
receiveName: {
|
||
$regex: ".*" + ctx.recipientName.trim() + ".*",
|
||
$options: "i",
|
||
},
|
||
});
|
||
}
|
||
|
||
// 退回运单号(售后)模糊查询:匹配 afterSale.waybillNo
|
||
// 兼容参数名:afterSaleWaybillNo(PC HLWSHIPPINGLIST)或 waybillNo(通用)
|
||
const rawAfterSaleWaybillNo =
|
||
(typeof ctx.afterSaleWaybillNo === 'string' && ctx.afterSaleWaybillNo.trim() !== '' && ctx.afterSaleWaybillNo.trim()) ||
|
||
(typeof ctx.waybillNo === 'string' && ctx.waybillNo.trim() !== '' && ctx.waybillNo.trim()) ||
|
||
'';
|
||
if (rawAfterSaleWaybillNo) {
|
||
andConditions.push({
|
||
'afterSale.waybillNo': {
|
||
$regex: ".*" + rawAfterSaleWaybillNo + ".*",
|
||
$options: 'i',
|
||
},
|
||
});
|
||
}
|
||
|
||
// 配送状态筛选:支持 statusList(优先)、status(兼容单状态)
|
||
let statusList = Array.isArray(ctx.statusList)
|
||
? ctx.statusList
|
||
.filter((i) => typeof i === 'string' && i.trim() !== '')
|
||
.map((i) => i.trim())
|
||
: [];
|
||
if (!statusList.length && typeof ctx.status === 'string' && ctx.status.trim() !== '') {
|
||
statusList = [ctx.status.trim()];
|
||
}
|
||
if (statusList.length) {
|
||
query.status = { $in: statusList };
|
||
}
|
||
|
||
// 创建时间范围
|
||
if (ctx.startDate && dayjs(ctx.startDate).isValid()) {
|
||
query.createTime = { $gte: dayjs(ctx.startDate).startOf('day').valueOf() };
|
||
}
|
||
if (ctx.endDate && dayjs(ctx.endDate).isValid()) {
|
||
query.createTime = {
|
||
...(query.createTime || {}),
|
||
$lte: dayjs(ctx.endDate).endOf('day').valueOf(),
|
||
};
|
||
}
|
||
if (ids) {
|
||
query._id = { $in: ids };
|
||
}
|
||
|
||
const finalQuery = andConditions.length ? { ...query, $and: andConditions } : query;
|
||
|
||
const collection = db.collection('medicine-purchase-order');
|
||
const total = await collection.countDocuments(finalQuery);
|
||
const list = await collection
|
||
.find(finalQuery)
|
||
.sort({ createTime: -1 })
|
||
.skip((page - 1) * pageSize)
|
||
.limit(pageSize)
|
||
.toArray();
|
||
|
||
// 聚合计算总金额
|
||
const totalResult = await collection.aggregate([
|
||
{ $match: finalQuery },
|
||
{
|
||
$group: {
|
||
_id: null,
|
||
totalDrugFee: { $sum: "$drugFee" },
|
||
totalShippingFee: { $sum: "$shippingFee" },
|
||
totalRegFee: { $sum: "$regFee" },
|
||
}
|
||
}
|
||
]).toArray();
|
||
const totals = totalResult.length > 0 ? totalResult[0] : {};
|
||
|
||
// 解密患者姓名,便于前端展示
|
||
const decryptedList = list.map((item) => {
|
||
const result = { ...item };
|
||
if (result.name && typeof result.name === 'string' && result.name.trim() !== '') {
|
||
try {
|
||
result.name = Sm4Util.decryptDataForSm3(result.name) || result.name;
|
||
} catch (err) {
|
||
// 解密失败时保留原值,避免影响整体返回
|
||
}
|
||
}
|
||
return result;
|
||
});
|
||
|
||
const pages = Math.ceil(total / pageSize);
|
||
|
||
const statistics = {
|
||
totalDrugFee: totals.totalDrugFee || 0,
|
||
totalShippingFee: totals.totalShippingFee || 0,
|
||
totalRegFee: totals.totalRegFee || 0,
|
||
};
|
||
|
||
const data = {
|
||
list: decryptedList,
|
||
total,
|
||
page,
|
||
pageSize,
|
||
pages,
|
||
statistics
|
||
};
|
||
|
||
// 兼容旧用法(直接返回 list/total),同时为 PC 端提供 data 包装
|
||
return {
|
||
success: true,
|
||
message: "获取成功",
|
||
data
|
||
};
|
||
} catch (e) {
|
||
return { success: false, message: e.message };
|
||
}
|
||
}
|
||
|
||
async function getMedicinePurchaseOrderDetail(ctx) {
|
||
try {
|
||
const id = typeof ctx.id === 'string' ? ctx.id.trim() : '';
|
||
if (!id) {
|
||
return { success: false, message: "id不能为空" };
|
||
}
|
||
const order = await db.collection('medicine-purchase-order').findOne({ _id: new ObjectId(id) });
|
||
if (!order) {
|
||
return { success: false, message: "购药订单不存在" };
|
||
}
|
||
order.name = Sm4Util.decryptDataForSm3(order.name) || order.name;
|
||
return { success: true, message: "查询购药订单详情成功", data: order };
|
||
} catch (e) {
|
||
return { success: false, message: e.message };
|
||
}
|
||
}
|
||
|
||
async function reloadYbPayStatus(ctx) {
|
||
try {
|
||
if (typeof ctx.ybTradeNo !== 'string' || ctx.ybTradeNo.trim() === '') {
|
||
return { success: false, message: "医保交易号不能为空" };
|
||
}
|
||
if (typeof ctx.id !== 'string' || ctx.id.trim() === '') {
|
||
return { success: false, message: "id不能为空" };
|
||
}
|
||
const order = await db.collection('medicine-purchase-order').findOne({ _id: new ObjectId(ctx.id), ybTradeNo: ctx.ybTradeNo.trim() });
|
||
if (!order) {
|
||
return { success: false, message: "购药订单不存在" };
|
||
}
|
||
if (order.status !== 'unpay') {
|
||
return { success: false, message: "购药订单状态不正确" };
|
||
}
|
||
const hasPaid = true; // 调用his接口查询医保是否支付成功
|
||
if (!hasPaid) {
|
||
return { success: false, message: "医保支付失败" };
|
||
}
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: { status: 'ybPaid' } });
|
||
return { success: true, message: "医保支付成功" };
|
||
} catch (e) {
|
||
return { success: false, message: e.message };
|
||
}
|
||
}
|
||
|
||
async function reloadZfPayStatus(ctx) {
|
||
try {
|
||
if (typeof ctx.tradeNo !== 'string' || ctx.tradeNo.trim() === '') {
|
||
return { success: false, message: "交易号不能为空" };
|
||
}
|
||
if (typeof ctx.id !== 'string' || ctx.id.trim() === '') {
|
||
return { success: false, message: "id不能为空" };
|
||
}
|
||
const order = await db.collection('medicine-purchase-order').findOne({ _id: new ObjectId(ctx.id), tradeNo: ctx.tradeNo.trim() });
|
||
if (!order) {
|
||
return { success: false, message: "购药订单不存在" };
|
||
}
|
||
if (order.status !== 'ybPaid') {
|
||
return { success: false, message: "购药订单状态不正确" };
|
||
}
|
||
const { data } = await tradeApi.queryAlipayTradeNo({ tradeNo: ctx.tradeNo });
|
||
if (data && (data.tradeStatus === 'TRADE_SUCCESS' || data.tradeStatus === 'TRADE_FINISHED')) {
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: { status: 'shipped', payTime: dayjs(data.sendPayDate).valueOf() } });
|
||
return { success: true, message: "自费支付成功", };
|
||
}
|
||
return { success: false, message: "自费支付失败" };
|
||
} catch (e) {
|
||
return { success: false, message: e.message };
|
||
}
|
||
}
|
||
|
||
async function getCostDetails(ctx) {
|
||
try {
|
||
if (typeof ctx.areaCode !== 'string' || ctx.areaCode.trim() === '') {
|
||
return { success: false, message: "区域代码不能为空" };
|
||
}
|
||
const insuranceCodes = Array.isArray(ctx.insuranceCodes) ? ctx.insuranceCodes.filter(typeof i === 'string' && i.trim() !== '') : [];
|
||
if (insuranceCodes.length === 0) {
|
||
return { success: false, message: "药品医保编码不能为空" };
|
||
}
|
||
const { success, message, data } = await zytHis.getHisDrugInfo({ insuranceCodes, areaCode: ctx.areaCode });
|
||
if (success && data) {
|
||
return { success: true, message: "查询药品信息成功", data };
|
||
}
|
||
return { success: false, message: message };
|
||
} catch (e) {
|
||
return { success: false, message: e.message };
|
||
}
|
||
}
|
||
|
||
async function getPatientRegInfo(idNo, patientName) {
|
||
try {
|
||
const idCard = Sm4Util.decryptDataForSm3(idNo);
|
||
const name = Sm4Util.decryptDataForSm3(patientName);
|
||
const patientRes = await zytHis({ type: 'getHisCustomer', idCard });
|
||
if (!patientRes || !patientRes.success) {
|
||
return { success: false, message: patientRes && patientRes.message ? patientRes.message : '获取患者信息失败' };
|
||
}
|
||
if (!patientRes.patient) {
|
||
return { success: false, message: "获取患者档案失败" };
|
||
}
|
||
if (patientRes.patient.name !== name) {
|
||
return { success: false, message: "患者姓名不匹配" };
|
||
}
|
||
const gh_fee = patientRes.patient.gh_fee;
|
||
const regFee = Number(gh_fee) == gh_fee && gh_fee >= 0 && gh_fee !== '' ? Number(gh_fee) : undefined;
|
||
if (typeof regFee !== 'number') {
|
||
return { success: false, message: "挂号费获取失败" };
|
||
}
|
||
return { success: true, regFee }
|
||
} catch (e) {
|
||
return { success: false, message: e.message };
|
||
}
|
||
}
|
||
|
||
async function getExpressFee(corpId, db) {
|
||
try {
|
||
const res = await hlwConfigApi({ type: 'getHlwConfig', corpId }, db)
|
||
if (!res || !res.success || !res.data) {
|
||
return { success: false, message: res && res.message ? res.message : '获取快递费用配置失败' };
|
||
}
|
||
const { fengNiaoExpressDiscountFee, fengNiaoExpressFee, emsExpressFee, emsExpressDiscountFee } = res.data;
|
||
const list = [fengNiaoExpressDiscountFee, fengNiaoExpressFee, emsExpressFee, emsExpressDiscountFee];
|
||
if (list.some(i => !validMedicineAmount(i))) {
|
||
return { success: false, message: '快递配用配置有误,请联系工作人员' };
|
||
}
|
||
const fengNiaoFee = new BigNumber(fengNiaoExpressFee).minus(fengNiaoExpressDiscountFee).toNumber();
|
||
const emsFee = new BigNumber(emsExpressFee).minus(emsExpressDiscountFee).toNumber();
|
||
if (emsFee < 0) {
|
||
return { success: false, message: '邮政快递配用配置有误,请联系工作人员' };
|
||
}
|
||
if (fengNiaoFee < 0) {
|
||
return { success: false, message: '蜂鸟配送费用配置有误,请联系工作人员' };
|
||
}
|
||
return {
|
||
success: true,
|
||
data: {
|
||
fengniao: {
|
||
shippingDiscount: fengNiaoExpressDiscountFee,
|
||
shippingOriginalFee: fengNiaoExpressFee,
|
||
shippingFee: fengNiaoFee
|
||
},
|
||
ems: {
|
||
shippingDiscount: emsExpressDiscountFee,
|
||
shippingOriginalFee: emsExpressFee,
|
||
shippingFee: emsFee
|
||
}
|
||
},
|
||
message: '获取快递费用配置成功'
|
||
}
|
||
} catch (e) {
|
||
return { success: false, message: e.message };
|
||
}
|
||
}
|
||
|
||
async function getHisMedicinePurchase(patientId, orderNo) {
|
||
try {
|
||
return await zytHis({ type: 'getHisMedicinePurchase', patientId, orderNo });
|
||
} catch (e) {
|
||
return { success: false, message: e.message };
|
||
}
|
||
}
|
||
|
||
async function invokeOnlineMedicinePurchasePaySuccess({ tradeNo, businessNo: orderNo, payTime }) {
|
||
try {
|
||
const order = await db.collection('medicine-purchase-order').findOne({ orderNo, tradeNo });
|
||
if (order && order.status === 'ybPaid' && order.shippingType && !order.shippingNo) {
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: { status: 'shipped', payTime: payTime.getTime() } });
|
||
await createDeliveryOrder(order);
|
||
return { success: true, message: "配送费支付成功, 订单状态已更新" };
|
||
}
|
||
return { success: false, message: "购药订单不存在或状态不正确" };
|
||
} catch (e) {
|
||
console.log('购药订单支付回调错误: ', e.message)
|
||
return { success: false, message: e.message };
|
||
}
|
||
}
|
||
|
||
async function getShippingDetail(ctx) {
|
||
try {
|
||
const id = typeof ctx.id === 'string' ? ctx.id.trim() : '';
|
||
const accountId = typeof ctx.accountId === 'string' ? ctx.accountId.trim() : '';
|
||
if (!id || !accountId) {
|
||
return { success: false, message: "id或accountId不能为空" };
|
||
}
|
||
const order = await db.collection('medicine-purchase-order').findOne({ _id: new ObjectId(id), accountId }, { projection: output.shippingDetail });
|
||
if (order) {
|
||
if (order.shippingType === 'fengniao') {
|
||
const fengniaoApi = require('../fengniao');
|
||
const res = await fengniaoApi.main({ type: 'getOrderDetail', shippingNo: order.shippingNo });
|
||
if (res.success && res.data) {
|
||
order.shippingDetail = res.data
|
||
}
|
||
} else if (order.shippingType === 'ems') {
|
||
const emsApi = require('../ems-express');
|
||
const res = await emsApi.getShippingDetail(order.shippingNo);
|
||
if (res.success && res.data) {
|
||
order.shippingDetail = res.data
|
||
}
|
||
}
|
||
return { success: true, message: "获取配送详情成功", data: order };
|
||
}
|
||
return { success: false, message: "订单不存在" };
|
||
} catch (e) {
|
||
return { success: false, message: e.message };
|
||
}
|
||
}
|
||
|
||
async function refundMedicinePurchaseOrderYbFee(ctx) {
|
||
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() : '';
|
||
if (!id || !orderNo || !operator || !operatorId) {
|
||
return { success: false, message: "参数不能为空" };
|
||
}
|
||
const order = await db.collection('medicine-purchase-order').findOne({ _id: new ObjectId(id), orderNo });
|
||
if (!order) {
|
||
return { success: false, message: "配药订单不存在" };
|
||
}
|
||
if (['ybFeeRefunded', 'refunded'].includes(order.status)) {
|
||
return { success: false, message: "配药订单医保费用已退费" };
|
||
}
|
||
if (!['shipped', 'ybPaid'].includes(order.status)) {
|
||
return { success: false, message: "配药订单状态不正确" };
|
||
}
|
||
|
||
const { success, message, data } = await zytHis({ type: 'getHisMedicinePurchase', patientId: order.patientId, orderNo: order.orderNo });
|
||
if (!success) {
|
||
return { success: false, message: message };
|
||
}
|
||
if (data && data.pay_mark === '1') {
|
||
// 是否需要退运费
|
||
const shouldRefundSelfFee = order.status === 'shipped' && order.shippingFee > 0;
|
||
const targetStatus = shouldRefundSelfFee ? 'ybFeeRefunded' : 'refunded';
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: { status: targetStatus } });
|
||
return { success: true, message: "配药订单医保费用退费成功" };
|
||
}
|
||
if (!data || data.pay_mark !== '0') {
|
||
return { success: false, message: `his购药订单支付状态异常【${HisPayStatus[data?.pay_mark] || '未知状态'}】` };
|
||
}
|
||
const refundRes = await zytHis({ type: 'refundMedicinePurchase', patientId: order.patientId, orderNo: order.orderNo });
|
||
if (!refundRes.success) {
|
||
return { success: false, message: refundRes.message };
|
||
}
|
||
const refundRecords = Array.isArray(order.refundRecords) ? order.refundRecords : [];
|
||
refundRecords.push({
|
||
amount: new BigNumber(order.drugFee).plus(order.regFee).toNumber(),
|
||
applyTime,
|
||
platform: 'his',
|
||
reason: '',
|
||
refundTime: Date.now(),
|
||
refundSerialNo: order.orderNo,
|
||
result: 'refunded',
|
||
tradeStatus: '1',
|
||
operator,
|
||
operatorId
|
||
});
|
||
const shouldRefundSelfFee = order.status === 'shipped' && order.shippingFee > 0;
|
||
const targetStatus = shouldRefundSelfFee ? 'ybFeeRefunded' : 'refunded';
|
||
const obj = { refundRecords, status: targetStatus }
|
||
const { modifiedCount, } = await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: obj });
|
||
if (modifiedCount > 0) {
|
||
return { success: true, message: "配药订单医保费用退费成功" };
|
||
}
|
||
return { success: false, message: "配药订单医保费用退费失败" };
|
||
} catch (e) {
|
||
return { success: false, message: `购药订单医保退费错误: ${e.message}` };
|
||
}
|
||
}
|
||
|
||
async function refundMedicinePurchaseOrderSelfFee(ctx) {
|
||
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 === '') {
|
||
return { success: false, message: "退费原因不能为空" };
|
||
}
|
||
const order = await db.collection('medicine-purchase-order').findOne({ _id: new ObjectId(id), orderNo });
|
||
if (!order) {
|
||
return { success: false, message: "配药订单不存在" };
|
||
}
|
||
if ('refunded' === order.status) {
|
||
return { success: false, message: "配药订单自费费用已退费" };
|
||
}
|
||
if (!['ems', 'fengniao'].includes(order.shippingType) || !order.shippingNo) {
|
||
return { success: false, message: "配药订单物流信息异常,暂不支持退费" };
|
||
}
|
||
if (!(order.shippingFee > 0 && order.payTime && order.tradeNo)) {
|
||
return { success: false, message: "配药订单没有运费或支付状态异常,暂不支持退费" };
|
||
}
|
||
if ("shipped" == order.status) {
|
||
return { success: false, message: "请先完成配药订单医保退费" };
|
||
}
|
||
if ("ybFeeRefunded" !== order.status) {
|
||
return { success: false, message: "配药订单状态不正确,暂不支持退费" };
|
||
}
|
||
const refundRecords = Array.isArray(order.refundRecords) ? order.refundRecords : [];
|
||
const copyArr = refundRecords.map(i => ({ ...i })).sort((a, b) => b.applyTime - a.applyTime);
|
||
const lastRecord = copyArr.find(i => i.platform === 'alipay');// 找到最新一条支付宝的退费记录
|
||
if (lastRecord && lastRecord.result === 'refunded') {
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: { status: 'refunded' } });
|
||
return { success: true, message: "配药订单自费费用退费成功" };
|
||
} else if (lastRecord && lastRecord.result === 'refunding') {
|
||
const seconds = Math.floor((applyTime - lastRecord.applyTime) / 1000);
|
||
if (seconds < 30) { // 支付宝退费查询要求至少等待10秒再查询
|
||
return { success: false, message: `配药订单自费费用退费中,请${30 - seconds}秒后再试` };
|
||
}
|
||
const { success, message, data } = await tradeApi.queryAlipayRefundDetail({ tradeNo: order.tradeNo });
|
||
if (!success) {
|
||
return { success, message }
|
||
}
|
||
const index = refundRecords.findIndex(i => i.platform === 'alipay' && i.applyTime === lastRecord.applyTime);
|
||
if (data && data.refundStatus === 'REFUND_SUCCESS') {
|
||
refundRecords[index].result = 'refunded';
|
||
refundRecords[index].refundTime = dayjs(data.gmtRefundPay).valueOf();
|
||
refundRecords[index].tradeStatus = data.tradeStatus;
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: { status: 'refunded', refundRecords } });
|
||
return { success: true, message: "配药订单自费费用退费成功" };
|
||
} else { // 没有返回 或者 退费状态字段不是 REFUND_SUCCESS 认为退费失败
|
||
refundRecords[index].result = 'refund_fail';
|
||
refundRecords[index].tradeStatus = data?.tradeStatus || '';
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: { refundRecords } });
|
||
}
|
||
}
|
||
if (!order.deliveryCancelled && order.shippingType === 'fengniao') {
|
||
const cancelCode = typeof ctx.cancelCode === 'string' ? ctx.cancelCode.trim() : '';
|
||
const role = typeof ctx.role === 'string' ? ctx.role.trim() : '';
|
||
if (!['1', '2'].includes(role)) {
|
||
return { success: false, message: "无效的取消类型,仅支持商户或用户取消" };
|
||
}
|
||
if (cancelCode === '') {
|
||
return { success: false, message: "取消编码不能为空" };
|
||
}
|
||
if (reason.length > 20) {
|
||
return { success: false, message: "[蜂鸟配送]退费原因不能超过20个字符" };
|
||
}
|
||
const fengniaoApi = require('../fengniao');
|
||
const { success, message } = await fengniaoApi.main({ type: 'cancelOrder', orderNo: order.orderNo, role, cancelCode, reason });
|
||
if (!success) {
|
||
return { success, message }
|
||
}
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: { deliveryCancelled: true } });
|
||
} else if (!order.deliveryCancelled && order.shippingType === 'ems') {
|
||
if (reason.length > 200) {
|
||
return { success: false, message: "[邮政快递]退费原因不能超过200个字符" };
|
||
}
|
||
const emsApi = require('../ems-express');
|
||
const { success, message } = await emsApi.cancelOrder({ logisticsOrderNo: order.orderNo, waybillNo: order.shippingNo, cancelReason: reason });
|
||
if (!success) {
|
||
return { success, message }
|
||
}
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: { deliveryCancelled: true } });
|
||
}
|
||
const applyRecord = {
|
||
amount: order.shippingFee,
|
||
applyTime,
|
||
platform: 'alipay',
|
||
reason,
|
||
refundSerialNo: order.tradeNo,
|
||
result: 'refunding',
|
||
operator,
|
||
operatorId
|
||
}
|
||
const res = await tradeApi.refundTrade({ tradeNo: order.tradeNo, reason, totalAmount: order.shippingFee });
|
||
if (!res.success) {
|
||
return { success: false, message: res.message };
|
||
}
|
||
const { tradeStatus, refundTime } = res.data;
|
||
applyRecord.result = tradeStatus;
|
||
applyRecord.refundTime = dayjs(refundTime).valueOf();
|
||
refundRecords.push(applyRecord);
|
||
const obj = { refundRecords }
|
||
if (tradeStatus === 'refunded') {
|
||
obj.status = 'refunded';
|
||
}
|
||
const { modifiedCount } = await db.collection('medicine-purchase-order').updateOne({ _id: order._id }, { $set: obj });
|
||
if (modifiedCount > 0) {
|
||
return { success: true, message: "配药订单自费费用退费成功" };
|
||
}
|
||
return { success: false, message: "配药订单自费费用退费失败" };
|
||
} catch (e) {
|
||
return { success: false, message: `购药订单自费退费错误: ${e.message}` };
|
||
}
|
||
}
|
||
|
||
// 定时任务
|
||
// 查询 待支付且超时的订单 查询his处方状态 是否为待支付 如果是待支付修改为过期状态 如果是已支付修改为医保支付成功状态 退费状态修改为已退费状态
|
||
// 查询 待配送的订单且没有物流单号的订单 去物流下单 同步物流单号
|
||
async function runMedicinePurchaseOrderSchedule() {
|
||
if (scheduleTaskIsRunning) return;
|
||
scheduleTaskIsRunning = true;
|
||
try {
|
||
// 当日未支付且超时的订单
|
||
const expiredOrders = await db.collection('medicine-purchase-order').find({ disabled: false, status: 'unpay', createTime: { $gt: dayjs().startOf('day').valueOf() }, expireTime: { $lt: Date.now() } }, { projection: { _id: 1, patientId: 1, orderNo: 1 } }).toArray();
|
||
console.log(`[超时购药订单定时任务]: 查询到超时订单条数: ${expiredOrders.length}`)
|
||
for (let expiredOrder of expiredOrders) {
|
||
const { success, data } = await getHisMedicinePurchase(expiredOrder.patientId, expiredOrder.orderNo);
|
||
if (data && data.pay_mark === '0') {
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: expiredOrder._id }, { $set: { status: 'ybPaid' } });
|
||
} else if (data && data.pay_mark === '1') {
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: expiredOrder._id }, { $set: { status: 'refunded' } });
|
||
} else if (!data || data.pay_mark === '5') {
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: expiredOrder._id }, { $set: { status: 'expired' } });
|
||
} else if (success && data) {
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: expiredOrder._id }, { $set: { status: 'abnormal' } });
|
||
}
|
||
}
|
||
// 今日支付完成 待配送的订单且没有物流单号的订单 去物流下单 同步物流单号
|
||
const shippedOrders = await db.collection('medicine-purchase-order').find({
|
||
disabled: false,
|
||
status: 'shipped',
|
||
shippingNo: { $exists: false },
|
||
shippingType: { $exists: true },
|
||
payTime: { $lte: dayjs().subtract(3, 'minute').valueOf(), $gt: dayjs().startOf('day').valueOf() }
|
||
}).toArray();
|
||
console.log(`[购药订单物流下单定时任务]: 查询到待下单订单条数: ${shippedOrders.length}`)
|
||
for (let shippedOrder of shippedOrders) {
|
||
await createDeliveryOrder(shippedOrder);
|
||
}
|
||
|
||
// 待同步his购药订单物流信息 同步his购药订单已收取运费或已退还运费信息
|
||
const updateDeliveryOrders = await db.collection('medicine-purchase-order').find({
|
||
$or: [
|
||
{ disabled: false, status: 'shipped', shippingNo: { $exists: true }, syncHisDelivery: { $exists: false } }, // 已经收取运费 未同步his
|
||
{ disabled: false, status: 'refunded', shippingNo: { $exists: true }, payTime: { $exists: true }, syncHisDelivery: 'charged' } //已退还运费 但未同步his
|
||
]
|
||
}).toArray();
|
||
console.log(`[购药订单物流同步定时任务]: 查询到待同步订单条数: ${updateDeliveryOrders.length}`)
|
||
for (let updateDeliveryOrder of updateDeliveryOrders) {
|
||
const regions = Array.isArray(updateDeliveryOrder.receiveRegion) ? updateDeliveryOrder.receiveRegion.map(i => i.trim()) : [];
|
||
const address = updateDeliveryOrder.receiveAddress.trim();
|
||
const fullAddress = regions.join('') + address;
|
||
const shippingType = updateDeliveryOrder.shippingType === 'fengniao' ? 'fengn' : '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 pickupCode = updateDeliveryOrder.pickupCode;
|
||
const { success } = await zytHis({ type: 'updateMedicinePurchaseDelivery', ...updateDeliveryOrder, pickupCode, shippingType, fullAddress, payTime, backFlag })
|
||
if (success) {
|
||
const target = backFlag === 0 ? 'charged' : 'refunded';
|
||
await db.collection('medicine-purchase-order').updateOne({ _id: updateDeliveryOrder._id }, { $set: { syncHisDelivery: target } });
|
||
}
|
||
}
|
||
} catch (e) {
|
||
console.log('执行定时任务出现错误: ', e.message)
|
||
}
|
||
scheduleTaskIsRunning = false;
|
||
}
|
||
|
||
async function updateAfterSaleInfo(ctx) {
|
||
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('medicine-purchase-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 getLastestPurchaseOrder(ctx) {
|
||
try {
|
||
const appId = process.env.CONFIG_ALIPAY_MINI_APPID;
|
||
const ciphertext = typeof ctx.ciphertext === 'string' ? ctx.ciphertext.trim() : '';
|
||
const data = Sm4Util.decryptDataForSm3(ciphertext);
|
||
const [, accountId] = data.split(appId);
|
||
if (!accountId) {
|
||
return { success: false, order: null };
|
||
}
|
||
const order = await db.collection('medicine-purchase-order').findOne({
|
||
accountId,
|
||
disabled: false,
|
||
status: { $in: ['ybPaid', 'shipped', 'refunded', 'ybFeeRefunded'] }
|
||
}, { projection: output.lastestOrder, sort: { createTime: -1 } });
|
||
if (order) {
|
||
const rx = await db.collection('diagnostic-record').findOne({ _id: new ObjectId(order.rpNo) }, { projection: { doctorName: 1, sex: 1, age: 1 } });
|
||
if (rx) {
|
||
order.doctorName = rx.doctorName;
|
||
order.sex = rx.sex;
|
||
order.age = rx.age;
|
||
}
|
||
order.name = Sm4Util.decryptDataForSm3(order.name);
|
||
}
|
||
return { success: Boolean(order), order };
|
||
} catch (e) {
|
||
return { success: false, message: `获取最新购药订单错误: ${e.message}` };
|
||
}
|
||
}
|
||
|
||
async function getPatientPurchaseOrderList(ctx) {
|
||
try {
|
||
const page = Number.isInteger(ctx.page) && ctx.page > 0 ? ctx.page : 1;
|
||
const pageSize = Number.isInteger(ctx.pageSize) && ctx.pageSize > 0 ? ctx.pageSize : 1;
|
||
const patientId = typeof ctx.patientId === 'string' ? ctx.patientId.trim() : '';
|
||
if (patientId === '') {
|
||
return { success: false, message: '参数错误' }
|
||
}
|
||
// , status: 'shipped'
|
||
const list = await db.collection('medicine-purchase-order').find({ patientId, disabled: false, status: 'shipped' }, { project: { rpNo: 1 } }).sort({ createTime: -1 }).skip((page - 1) * pageSize).limit(pageSize).toArray();
|
||
const total = await db.collection('medicine-purchase-order').countDocuments({ patientId, disabled: false, status: 'shipped' })
|
||
const data = await db.collection('diagnostic-record').find({ _id: { $in: list.map(i => new ObjectId(i.rpNo)) } }, {
|
||
projection: {
|
||
"createTime": 1,
|
||
"diagnosisList.name": 1,
|
||
"drugs.drugName": 1,
|
||
"drugs.specification": 1,
|
||
"drugs.quantity": 1,
|
||
"drugs.unit": 1,
|
||
"drugs.usageName": 1,
|
||
"drugs.frequencyName": 1,
|
||
"drugs.dosage": 1,
|
||
"drugs.dosage_unit": 1
|
||
}
|
||
}).sort({ createTime: -1 }).toArray()
|
||
return { success: true, data, total }
|
||
} catch (e) {
|
||
return { success: false, message: e.message }
|
||
}
|
||
}
|
||
|
||
async function getHighFreqAddressOrders(ctx) {
|
||
try {
|
||
const startDate = ctx.startDate && dayjs(ctx.startDate).isValid() ? dayjs(ctx.startDate).valueOf() : null;
|
||
const endDate = ctx.endDate && dayjs(ctx.endDate).isValid() ? dayjs(ctx.endDate).valueOf() : null;
|
||
const times = ctx.times > 1 && Number.isInteger(ctx.times) ? ctx.times : '';
|
||
const operator = ['eq', 'gte'].includes(ctx.operator) ? ctx.operator : 'eq';
|
||
if (!times || !startDate || !endDate || !(endDate > startDate)) {
|
||
return { success: false, message: '参数错误' }
|
||
}
|
||
|
||
const pipeline = [
|
||
{
|
||
$match: {
|
||
disabled: { $ne: true },
|
||
receiveAddress: { $exists: true, $ne: null, $ne: '' },
|
||
createTime: { $gte: startDate, $lte: endDate }
|
||
}
|
||
},
|
||
{
|
||
$sort: { createTime: -1 }
|
||
},
|
||
{
|
||
$group: {
|
||
_id: '$receiveAddress',
|
||
orderIds: { $push: '$_id' },
|
||
count: { $sum: 1 }
|
||
}
|
||
},
|
||
{
|
||
$match: operator === 'gte' ? { count: { $gte: times } } : { count: { $eq: times } }
|
||
},
|
||
{
|
||
$project: {
|
||
_id: 0,
|
||
receiveAddress: '$_id',
|
||
orderIds: 1,
|
||
count: 1
|
||
}
|
||
}
|
||
];
|
||
|
||
const data = await db.collection('medicine-purchase-order').aggregate(pipeline).toArray();
|
||
return { success: true, data }
|
||
} catch (e) {
|
||
return { success: false, message: e.message }
|
||
}
|
||
}
|
||
|
||
async function purchaseTest() {
|
||
try {
|
||
const pickupCode = await generatePickupCode(db);
|
||
return { success: true, data: pickupCode }
|
||
} catch (e) {
|
||
return { success: false, message: e.message }
|
||
}
|
||
}
|
||
|
||
|