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 } } }