10 KiB
门诊医生站手术申请未生成预收费明细记录问题深度分析报告
一、问题概述
门诊医生站手术申请保存后,门诊收费系统无法查询到对应的预收费明细记录。
二、已做的修复
已将 SurgeryAppServiceImpl.java 中的 ChargeItem 状态从 DRAFT 改为 PLANNED:
// 第350行
chargeItem.setStatusEnum(ChargeItemStatus.PLANNED.getValue()); // 收费状态:待收费
三、深入分析发现的问题
3.1 前端提交数据检查
文件: openhis-ui-vue3/src/views/doctorstation/components/surgery/surgeryApplication.vue
前端表单包含费用字段:
surgeryFee- 手术费用(第419行)anesthesiaFee- 麻醉费用(第426行)totalFee- 总费用(通过计算属性totalCalculatedFee自动计算并同步到表单,第564-583行)
提交时调用 API:
- 新增:
addSurgery(form.value)(第1050行) - 修改:
updateSurgery(form.value)(第1066行)
结论: 前端正确传递了费用字段,问题不在前端。
3.2 后端收费生成逻辑分析
文件: openhis-server-new/openhis-application/src/main/java/com/openhis/web/clinicalmanage/appservice/impl/SurgeryAppServiceImpl.java
手术申请生成 ChargeItem 的代码(第348-369行):
ChargeItem chargeItem = new ChargeItem();
chargeItem.setStatusEnum(ChargeItemStatus.PLANNED.getValue()); // 收费状态:待收费
chargeItem.setBusNo("CI" + serviceRequest.getBusNo());
chargeItem.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue());
chargeItem.setPatientId(surgeryDto.getPatientId());
chargeItem.setContextEnum(3); // 类型:3-诊疗
chargeItem.setEncounterId(surgeryDto.getEncounterId());
chargeItem.setAccountId(accountId);
chargeItem.setDefinitionId(surgeryId);
chargeItem.setEntererId(practitionerId);
chargeItem.setEnteredDate(curDate);
chargeItem.setServiceTable(CommonConstants.TableName.WOR_SERVICE_REQUEST);
chargeItem.setServiceId(serviceRequest.getId());
chargeItem.setProductTable("cli_surgery"); // 【问题1】产品表是手术表
chargeItem.setProductId(surgeryId); // 【问题2】产品ID是手术ID
chargeItem.setRequestingOrgId(orgId);
chargeItem.setQuantityValue(BigDecimal.valueOf(1));
chargeItem.setQuantityUnit("次");
chargeItem.setUnitPrice(surgeryDto.getSurgeryFee() != null ? surgeryDto.getSurgeryFee() : new BigDecimal("0.0"));
chargeItem.setTotalPrice(surgeryDto.getTotalFee() != null ? surgeryDto.getTotalFee() : new BigDecimal("0.0"));
chargeItemService.save(chargeItem);
3.3 门诊收费查询逻辑分析
文件: openhis-server-new/openhis-application/src/main/resources/mapper/chargemanage/OutpatientChargeAppMapper.xml
关键 SQL 查询(第67-148行):
SELECT T1.encounter_id, T1.id, T1.patient_id, T1.context_enum, T1.status_enum, ...
CASE
WHEN T1.context_enum = #{activity} THEN T2."name"
WHEN T1.context_enum = #{medication} THEN T3."name"
WHEN T1.context_enum = #{device} THEN T4."name"
END AS item_name,
FROM adm_charge_item AS T1
LEFT JOIN wor_activity_definition AS T2
ON T1.context_enum = #{activity}
AND T1.product_id = T2.id
LEFT JOIN med_medication_definition AS T3
ON T1.context_enum = #{medication}
AND T1.product_id = T3.id
LEFT JOIN adm_device_definition AS T4
ON T1.context_enum = #{device}
AND T1.product_id = T4.id
-- ... 其他条件
WHERE T1.encounter_id = #{encounterId}
AND T1.status_enum IN (#{planned}, #{billable}, #{billed}, #{refunding}, #{refunded}, #{partRefund})
AND T1.context_enum != #{register}
AND T1.delete_flag = '0'
参数值:
activity= 3 (ChargeItemContext.ACTIVITY.getValue())planned= 1 (ChargeItemStatus.PLANNED.getValue())
3.4 核心问题定位
问题1:ChargeItemContext 枚举定义
文件: openhis-common/src/main/java/com/openhis/common/enums/ChargeItemContext.java
public enum ChargeItemContext implements HisEnumInterface {
MEDICATION(1, "1", "药品"),
DEVICE(2, "2", "耗材"),
ACTIVITY(3, "3", "项目"), // 诊疗项目
REGISTER(4, "4", "挂号");
}
问题2:数据关联不匹配(根本原因)
手术申请生成的 ChargeItem:
| 字段 | 值 | 说明 |
|---|---|---|
| contextEnum | 3 | ACTIVITY(项目) |
| productTable | "cli_surgery" | 手术表 |
| productId | surgeryId | 手术ID |
门诊收费 SQL 查询逻辑:
- 当
context_enum = 3 (ACTIVITY)时,关联wor_activity_definition表 - SQL:
LEFT JOIN wor_activity_definition AS T2 ON T1.context_enum = #{activity} AND T1.product_id = T2.id
核心问题:
- 手术申请保存的
product_id是手术ID(cli_surgery表的ID) - 但 SQL 查询时关联的是
wor_activity_definition表 - 手术ID在
wor_activity_definition表中不存在 - 导致 LEFT JOIN 返回 NULL,手术收费记录无法显示
3.5 对比其他申请类型的收费生成
检查申请(ExamApplyController.java)
chargeItem.setContextEnum(2); // 类型:2=耗材(不是诊疗!)
chargeItem.setProductTable(CommonConstants.TableName.WOR_ACTIVITY_DEFINITION);
chargeItem.setProductId(0L);
住院申请单(RequestFormManageAppServiceImpl.java)
surgeryChargeItem.setContextEnum(3); // 3-诊疗
surgeryChargeItem.setProductTable(CommonConstants.TableName.WOR_ACTIVITY_DEFINITION);
surgeryChargeItem.setProductId(activityList.get(0).getAdviceDefinitionId()); // 诊疗定义ID
差异总结:
| 申请类型 | contextEnum | productTable | productId |
|---|---|---|---|
| 手术申请(门诊) | 3 (ACTIVITY) | cli_surgery | surgeryId |
| 检查申请 | 2 (DEVICE) | wor_activity_definition | 0L |
| 住院申请单 | 3 (ACTIVITY) | wor_activity_definition | adviceDefinitionId |
四、解决方案
方案1:修改手术申请的 productTable 和 productId(推荐)
修改 SurgeryAppServiceImpl.java 第362-363行:
// 修改前
chargeItem.setProductTable("cli_surgery");
chargeItem.setProductId(surgeryId);
// 修改后
chargeItem.setProductTable(CommonConstants.TableName.WOR_ACTIVITY_DEFINITION);
// 需要获取手术对应的诊疗项目定义ID
chargeItem.setProductId(surgeryDefinitionId); // 从手术项目定义表中获取
注意:此方案需要手术项目与诊疗项目定义有对应关系。
方案2:修改门诊收费查询 SQL
修改 OutpatientChargeAppMapper.xml,增加对 cli_surgery 表的关联:
<select id="selectEncounterPatientPrescription" ...>
SELECT T1.encounter_id, ...,
CASE
WHEN T1.context_enum = #{activity} THEN T2."name"
WHEN T1.context_enum = #{medication} THEN T3."name"
WHEN T1.context_enum = #{device} THEN T4."name"
END AS item_name,
-- 增加:从手术表获取名称
T5.name AS surgery_name
FROM adm_charge_item AS T1
LEFT JOIN wor_activity_definition AS T2 ...
LEFT JOIN med_medication_definition AS T3 ...
LEFT JOIN adm_device_definition AS T4 ...
-- 增加手术表关联
LEFT JOIN cli_surgery AS T5
ON T1.product_table = 'cli_surgery'
AND T1.product_id = T5.id
WHERE ...
</select>
方案3:修改 ChargeItem 保存逻辑(临时方案)
如果手术项目暂时没有对应的诊疗项目定义,可以:
// 设置 productTable 为 wor_activity_definition,但 productId 设为 0
chargeItem.setProductTable(CommonConstants.TableName.WOR_ACTIVITY_DEFINITION);
chargeItem.setProductId(0L);
// 在 item_name 或其他字段中保存手术名称
五、额外发现的问题
5.1 检查申请的 contextEnum 设置错误
在 ExamApplyController.java 第249行:
chargeItem.setContextEnum(2); // 类型:2=诊疗
但实际上 2 对应的是 ChargeItemContext.DEVICE(耗材),不是诊疗。正确的应该是:
chargeItem.setContextEnum(ChargeItemContext.ACTIVITY.getValue()); // 3
5.2 手术申请缺少处方号
对比检查申请,手术申请的 ChargeItem 没有设置 prescriptionNo 字段,可能导致收费查询时无法关联到处方信息。
六、修复建议优先级
- 高优先级:修改手术申请的
productTable和productId,使其与门诊收费 SQL 查询兼容 - 中优先级:增加手术申请 ChargeItem 的
prescriptionNo字段设置 - 低优先级:修复检查申请的
contextEnum设置错误
七、验证步骤
- 修改代码后,重新编译部署
- 在门诊医生站创建新的手术申请
- 检查
adm_charge_item表,确认记录已生成且字段正确 - 在门诊收费系统查询该患者的收费明细,确认手术费用能正常显示
- 测试收费、结算流程是否正常
八、相关文件清单
| 文件路径 | 说明 |
|---|---|
openhis-ui-vue3/src/views/doctorstation/components/surgery/surgeryApplication.vue |
前端手术申请组件 |
openhis-server-new/openhis-application/src/main/java/com/openhis/web/clinicalmanage/appservice/impl/SurgeryAppServiceImpl.java |
手术申请服务实现 |
openhis-server-new/openhis-application/src/main/resources/mapper/chargemanage/OutpatientChargeAppMapper.xml |
门诊收费查询Mapper |
openhis-server-new/openhis-application/src/main/java/com/openhis/web/chargemanage/appservice/impl/OutpatientChargeAppServiceImpl.java |
门诊收费服务实现 |
openhis-server-new/openhis-common/src/main/java/com/openhis/common/enums/ChargeItemContext.java |
收费项目类型枚举 |
openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/domain/ChargeItem.java |
收费项实体类 |
openhis-server-new/openhis-application/src/main/java/com/openhis/web/check/controller/ExamApplyController.java |
检查申请控制器(对比参考) |
openhis-server-new/openhis-application/src/main/java/com/openhis/web/regdoctorstation/appservice/impl/RequestFormManageAppServiceImpl.java |
住院申请单服务(对比参考) |