feat: 对接合理用药
This commit is contained in:
parent
eb58dfdbbe
commit
8125e9d4e6
@ -274,13 +274,13 @@ async function cancelAutoOpenForHighRisk({
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldNotify) {
|
||||
await sendManualOpenNotification(
|
||||
db,
|
||||
{ type: AUTOMATION_TYPES.OPEN_RX, corpId, orderId },
|
||||
doctorCode
|
||||
);
|
||||
}
|
||||
// if (shouldNotify) {
|
||||
// await sendManualOpenNotification(
|
||||
// db,
|
||||
// { type: AUTOMATION_TYPES.OPEN_RX, corpId, orderId },
|
||||
// doctorCode
|
||||
// );
|
||||
// }
|
||||
return {
|
||||
success: false,
|
||||
skipped: true,
|
||||
@ -960,6 +960,20 @@ async function handleAutoOpenRx(db, task) {
|
||||
|
||||
const params = await buildAutoPrescriptionParams(db, order);
|
||||
const diagnosticRecord = require("../diagnostic-record");
|
||||
const reviewResult = await diagnosticRecord(
|
||||
{
|
||||
type: "getYbReviewResult",
|
||||
corpId: order.corpId,
|
||||
params,
|
||||
},
|
||||
db
|
||||
);
|
||||
if (!reviewResult || !reviewResult.success) {
|
||||
throw new AutomationError(
|
||||
reviewResult?.message || "合理用药审核未通过"
|
||||
);
|
||||
}
|
||||
|
||||
const result = await diagnosticRecord(
|
||||
{
|
||||
type: "addConsultDiagnosis",
|
||||
|
||||
@ -624,6 +624,110 @@ describe("automation task scheduling", () => {
|
||||
);
|
||||
});
|
||||
|
||||
test("blocks automatic prescription when rational-drug review fails", async () => {
|
||||
tencentIM.mockResolvedValue({ success: true });
|
||||
diagnosticRecord.mockResolvedValue({
|
||||
success: false,
|
||||
message: "该处方存在不合理用药",
|
||||
});
|
||||
const drugId = new ObjectId();
|
||||
const taskUpdateOne = jest.fn().mockResolvedValue({ modifiedCount: 1 });
|
||||
const order = {
|
||||
orderId: "order-review-failed",
|
||||
corpId: "corp-1",
|
||||
orderSource: "ALIPAY_MINI",
|
||||
orderStatus: "processing",
|
||||
doctorCode: "D001",
|
||||
patientId: "P001",
|
||||
name: "患者甲",
|
||||
description: "鼻塞流涕",
|
||||
medInfo: { dise_codg: "J00", dise_name: "普通感冒" },
|
||||
drugs: [
|
||||
{
|
||||
_id: drugId.toString(),
|
||||
dosage: 10,
|
||||
dosage_unit: "mg",
|
||||
quantity: 1,
|
||||
usageName: "口服",
|
||||
frequencyName: "每日两次",
|
||||
unit: "盒",
|
||||
},
|
||||
],
|
||||
expireTime: Date.now() + 60_000,
|
||||
};
|
||||
const db = createCollectionDb({
|
||||
"hlw-config": {
|
||||
findOne: jest.fn().mockResolvedValue({ autoOpenRx: true }),
|
||||
find: jest.fn().mockReturnValue({
|
||||
toArray: jest.fn().mockResolvedValue([
|
||||
{ key: "store-medicine-dosage-unit", list: [{ code: "MG", name: "mg" }] },
|
||||
{ key: "store-medicine-frequence", list: [{ code: "BID", name: "每日两次" }] },
|
||||
{ key: "store-medicine-administration", list: [{ code: "PO", name: "口服" }] },
|
||||
{ key: "medicine-package-unit", list: [{ code: "盒", name: "盒" }] },
|
||||
]),
|
||||
}),
|
||||
},
|
||||
"consult-order": { findOne: jest.fn().mockResolvedValue(order) },
|
||||
"diagnostic-record": { findOne: jest.fn().mockResolvedValue(null) },
|
||||
"hlw-doctor": {
|
||||
findOne: jest.fn().mockResolvedValue({
|
||||
doctorNo: "D001",
|
||||
signatureUrl: "doctor-sign",
|
||||
onlineStatus: "online",
|
||||
}),
|
||||
},
|
||||
"drug-info": {
|
||||
find: jest.fn().mockReturnValue({
|
||||
toArray: jest.fn().mockResolvedValue([
|
||||
{
|
||||
_id: drugId,
|
||||
onSale: true,
|
||||
name: "测试药品",
|
||||
erpId: "ERP-1",
|
||||
insurance_code: "MED-1",
|
||||
dosage_form: "片剂",
|
||||
days: 3,
|
||||
dosage_unit: "mg",
|
||||
administration_method: "口服",
|
||||
freq: "每日两次",
|
||||
unit: "盒",
|
||||
},
|
||||
]),
|
||||
}),
|
||||
},
|
||||
[COLLECTION]: { updateOne: taskUpdateOne },
|
||||
});
|
||||
const task = {
|
||||
_id: new ObjectId(),
|
||||
type: AUTOMATION_TYPES.OPEN_RX,
|
||||
corpId: "corp-1",
|
||||
orderId: order.orderId,
|
||||
attempts: 1,
|
||||
expiresAt: Date.now() + 60_000,
|
||||
};
|
||||
|
||||
await processClaimedTask(db, task);
|
||||
|
||||
expect(diagnosticRecord).toHaveBeenCalledTimes(1);
|
||||
expect(diagnosticRecord).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
type: "getYbReviewResult",
|
||||
corpId: order.corpId,
|
||||
params: expect.objectContaining({ orderId: order.orderId }),
|
||||
}),
|
||||
db
|
||||
);
|
||||
expect(taskUpdateOne).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ _id: task._id, status: TASK_STATUS.RUNNING }),
|
||||
expect.objectContaining({
|
||||
$set: expect.objectContaining({
|
||||
status: TASK_STATUS.FAILED,
|
||||
lastError: "该处方存在不合理用药",
|
||||
}),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test("fails automatic audit immediately and sends the failure reason", async () => {
|
||||
tencentIM.mockResolvedValue({ success: true });
|
||||
const rxId = new ObjectId();
|
||||
|
||||
@ -91,9 +91,9 @@ exports.formatUploadRxData = function (data) {
|
||||
hospid: "108",
|
||||
phar_code: data.pharmacistNo,
|
||||
phar_name: data.pharmacist,
|
||||
phar_chk_time: dayjs(data.auditTime).format("YYYY-MM-DD HH:mm:ss"),
|
||||
ysjd_time: dayjs(data.prescriptionStartTime).format("YYYY-MM-DD HH:mm:ss"),
|
||||
prsc_time: dayjs(data.prescriptionEndTime).format("YYYY-MM-DD HH:mm:ss"),
|
||||
phar_chk_time: data.auditTime ? dayjs(data.auditTime).format("YYYY-MM-DD HH:mm:ss") : "",
|
||||
ysjd_time: data.prescriptionStartTime ? dayjs(data.prescriptionStartTime).format("YYYY-MM-DD HH:mm:ss") : "",
|
||||
prsc_time: data.prescriptionEndTime ? dayjs(data.prescriptionEndTime).format("YYYY-MM-DD HH:mm:ss") : "",
|
||||
details: data.drugs.map((i) => {
|
||||
const item = {
|
||||
erp_id: i.erpId,
|
||||
|
||||
@ -18,7 +18,7 @@ const consultOrder = require("../consult-order");
|
||||
const tencentIM = require("../tencent-im");
|
||||
const beijingCa = require("../beijing-ca");
|
||||
const BigNumber = require("bignumber.js");
|
||||
const timeApi = require("../hlw-time-duration");
|
||||
// const timeApi = require("../hlw-time-duration");
|
||||
const types = require("./types");
|
||||
|
||||
/**
|
||||
@ -218,25 +218,25 @@ async function addConsultDiagnosis(item) {
|
||||
if (orderExpired) {
|
||||
return { success: false, message: "当前订单不在有效期内" };
|
||||
}
|
||||
timeApi({ type: "addDoctorRxDuration", orderId }, db);
|
||||
// timeApi({ type: "addDoctorRxDuration", orderId }, db);
|
||||
const doctor = await db.collection("hlw-doctor").findOne({ corpId, doctorNo: doctorCode });
|
||||
if (!doctor) {
|
||||
return { success: false, message: "医生不存在" };
|
||||
}
|
||||
// 判断是否医生发的消息是否大于2条
|
||||
const chatCount = automated
|
||||
? 3
|
||||
: await db.collection("im-chat-msg").countDocuments({
|
||||
From_Account: doctorCode,
|
||||
To_Account: orderId,
|
||||
});
|
||||
timeData.chatCountQueryTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||||
if (!automated && chatCount < 3) {
|
||||
return {
|
||||
success: false,
|
||||
message: "请先向患者发送2条提问消息后再开方",
|
||||
};
|
||||
}
|
||||
// const chatCount = automated
|
||||
// ? 3
|
||||
// : await db.collection("im-chat-msg").countDocuments({
|
||||
// From_Account: doctorCode,
|
||||
// To_Account: orderId,
|
||||
// });
|
||||
// timeData.chatCountQueryTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||||
// if (!automated && chatCount < 3) {
|
||||
// return {
|
||||
// success: false,
|
||||
// message: "请先向患者发送2条提问消息后再开方",
|
||||
// };
|
||||
// }
|
||||
const record = await db
|
||||
.collection("diagnostic-record")
|
||||
.findOne(
|
||||
@ -2146,47 +2146,119 @@ async function getRxMedicineOrderStatus(ctx, db) {
|
||||
}
|
||||
}
|
||||
|
||||
async function getYbReviewResult(ctx) {
|
||||
let { params = {} } = ctx;
|
||||
try {
|
||||
async function getYbReviewResult(ctx, db) {
|
||||
const params = ctx && ctx.params && typeof ctx.params === "object" ? ctx.params : {};
|
||||
const orderId = typeof params.orderId === "string" ? params.orderId.trim() : "";
|
||||
const drugs = Array.isArray(params.drugs) ? params.drugs : [];
|
||||
const insuranceCodes = drugs.map(i => i.insurance_code).filter(Boolean);
|
||||
if (insuranceCodes.length === 0) {
|
||||
return { success: false, message: "药品列表不能为空" };
|
||||
const diagnosisList = Array.isArray(params.diagnosisList) ? params.diagnosisList : [];
|
||||
const corpId = typeof ctx.corpId === "string" ? ctx.corpId.trim() : "";
|
||||
|
||||
if (!orderId) {
|
||||
return { success: false, message: "订单号不能为空" };
|
||||
}
|
||||
const { data: hisDrugs } = await zytHis({ type: 'getHisDrugInfo', insuranceCodes, ignoreAreaCode: true });
|
||||
const hisDrugList = Array.isArray(hisDrugs) ? hisDrugs : [];
|
||||
const validDrugs = []
|
||||
for (let i of params.drugs) {
|
||||
const hisDrug = hisDrugList.find(j => i.insurance_code && i.insurance_code === j.gjbm);
|
||||
if (!hisDrug) {
|
||||
continue;
|
||||
if (drugs.length === 0) {
|
||||
return { success: false, message: "药品信息不能为空" };
|
||||
}
|
||||
validDrugs.push({
|
||||
...i,
|
||||
hisChargeInfo: {
|
||||
drugGroupNo: hisDrug.group_no,
|
||||
drugId: hisDrug.charge_code,
|
||||
drugSerial: hisDrug.serial,
|
||||
drugPrice: hisDrug.pack_retprice,
|
||||
drugSumamt: new BigNumber(hisDrug.pack_retprice).multipliedBy(i.quantity).toNumber()
|
||||
}
|
||||
})
|
||||
}
|
||||
if (validDrugs.length === 0) {
|
||||
return { success: true, message: '未能有效查询: 药品信息未找到 ', advices: [] }
|
||||
}
|
||||
params.drugs = validDrugs;
|
||||
const payload = formatReviewData(params)
|
||||
const { success, advices, message } = await zytHis({
|
||||
type: 'ybReviewPrescription',
|
||||
data: payload
|
||||
})
|
||||
return { success, message, advices }
|
||||
} catch (e) {
|
||||
return { success: false, message: `获取处方审核结果失败: ${e.message}` }
|
||||
if (diagnosisList.length === 0) {
|
||||
return { success: false, message: "诊断信息不能为空" };
|
||||
}
|
||||
|
||||
try {
|
||||
// 订单中的患者、医保及就诊信息是审核请求的基础数据;药品以本次开方页面提交的数据为准。
|
||||
const orderQuery = { orderId };
|
||||
if (corpId) {
|
||||
orderQuery.corpId = corpId;
|
||||
}
|
||||
const order = await db.collection("consult-order").findOne(orderQuery);
|
||||
if (!order) {
|
||||
return { success: false, message: "订单不存在" };
|
||||
}
|
||||
|
||||
const drugIds = drugs.map((drug) =>
|
||||
drug && typeof drug._id === "string" ? drug._id.trim() : ""
|
||||
);
|
||||
const invalidDrugId = drugIds.find((id) => !ObjectId.isValid(id));
|
||||
if (invalidDrugId !== undefined) {
|
||||
return { success: false, message: "药品ID无效" };
|
||||
}
|
||||
const normalizedDrugIds = drugIds.map((id) => new ObjectId(id).toString());
|
||||
|
||||
const dbDrugs = await db
|
||||
.collection("drug-info")
|
||||
.find(
|
||||
{
|
||||
_id: {
|
||||
$in: [...new Set(normalizedDrugIds)].map((id) => new ObjectId(id)),
|
||||
},
|
||||
},
|
||||
{
|
||||
projection: {
|
||||
erpId: 1,
|
||||
insurance_code: 1,
|
||||
name: 1,
|
||||
dosage_form: 1,
|
||||
specification: 1,
|
||||
},
|
||||
}
|
||||
)
|
||||
.toArray();
|
||||
const dbDrugMap = new Map(
|
||||
dbDrugs.map((drug) => [drug._id.toString(), drug])
|
||||
);
|
||||
const missingDrugId = normalizedDrugIds.find((id) => !dbDrugMap.has(id));
|
||||
if (missingDrugId) {
|
||||
return { success: false, message: `未匹配到药品信息:${missingDrugId}` };
|
||||
}
|
||||
|
||||
const reviewDrugs = drugs.map((drug, index) => {
|
||||
const dbDrug = dbDrugMap.get(normalizedDrugIds[index]);
|
||||
return {
|
||||
erpId: dbDrug.erpId,
|
||||
insurance_code: dbDrug.insurance_code,
|
||||
_id: dbDrug._id.toString(),
|
||||
drugName: dbDrug.name,
|
||||
dosage_form: dbDrug.dosage_form,
|
||||
specification: dbDrug.specification,
|
||||
quantity: drug.quantity,
|
||||
usageCode: drug.usageCode,
|
||||
usageName: drug.usageName,
|
||||
days: drug.days,
|
||||
frequencyCode: drug.frequencyCode,
|
||||
frequencyName: drug.frequencyName,
|
||||
dosage: drug.dosage,
|
||||
dosage_unit: drug.dosage_unit,
|
||||
dose_time_name: drug.dose_time_name,
|
||||
};
|
||||
});
|
||||
|
||||
const medInfo = order.medInfo && typeof order.medInfo === "object" ? order.medInfo : {};
|
||||
const reviewData = {
|
||||
feeType: order.feeType,
|
||||
patientId: order.patientId,
|
||||
medOrgOrderNo: order.registerId,
|
||||
med_type: medInfo.med_type,
|
||||
dise_codg: medInfo.dise_codg,
|
||||
dise_name: medInfo.dise_name,
|
||||
doctorCode: order.doctorCode,
|
||||
unitCode: order.unitCode,
|
||||
doctorCode: order.doctorCode,
|
||||
doctorCode: order.doctorCode,
|
||||
diagnosisList,
|
||||
drugs: reviewDrugs,
|
||||
};
|
||||
const payload = formatUploadRxData(reviewData);
|
||||
const { success, message } = await hnHis({
|
||||
type: "ybReviewPrescription",
|
||||
data: payload,
|
||||
});
|
||||
|
||||
return {
|
||||
success: Boolean(success),
|
||||
message: message ? message : (success ? '查询成功' : '查询合理用药结果失败'),
|
||||
};
|
||||
} catch (e) {
|
||||
return { success: false, message: `获取处方审核结果失败: ${e.message}` };
|
||||
}
|
||||
}
|
||||
|
||||
async function runOnlineRxExpireSchedule(db) {
|
||||
|
||||
@ -681,39 +681,25 @@ async function uploadWinePurchaseRx(item) {
|
||||
}
|
||||
}
|
||||
|
||||
// hlwuploadprescription
|
||||
async function ybReviewPrescription(item) {
|
||||
try {
|
||||
const url = `${baseUrl}/his/hlw/ybsh`;
|
||||
const { code, data, status_code, message } = await request.main(
|
||||
url,
|
||||
item.data,
|
||||
"POST"
|
||||
);
|
||||
if (status_code == 200 && code == '1' && !message) {
|
||||
const str = Buffer.from(data, 'base64');
|
||||
const dataStr = decode(str, 'gbk');
|
||||
const strData = JSON.parse(dataStr);
|
||||
const result = strData && strData.output && Array.isArray(strData.output.result) ? strData.output.result.filter(Boolean) : [];
|
||||
const advices = result.map(i => ({
|
||||
name: typeof i.rule_name === 'string' ? i.rule_name.trim() : '',
|
||||
text: typeof i.vola_cont === 'string' ? i.vola_cont.trim() : '',
|
||||
})).filter(i => i.name || i.text)
|
||||
const params = { type: "rationalDrugReview", data: item.data };
|
||||
const { status_code, code, data, message } = await request.main(url, params, "POST");
|
||||
if (status_code == 200 && code == '1') {
|
||||
return {
|
||||
success: true,
|
||||
advices,
|
||||
message: "[his]医保审核成功",
|
||||
message: message,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
success: false,
|
||||
message: `[his]医保审核失败: ${message || '未知错误'}`,
|
||||
message: message || '查询合理用药结果失败',
|
||||
};
|
||||
}
|
||||
} catch (err) {
|
||||
return {
|
||||
success: false,
|
||||
message: `[his]医保审核错误: ${err.message || '未知错误'}`,
|
||||
message: `[his]查询合理用药错误: ${err.message || '未知错误'}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user