package cn.lihu.jh.module.ecg.service.appointment;
|
|
import org.junit.Test;
|
|
import java.lang.reflect.Method;
|
import java.util.HashMap;
|
import java.util.Map;
|
|
import static org.junit.Assert.*;
|
|
/**
|
* 锁定 S050401/S050501(检查预约)报文中检查类型的解析行为。
|
*
|
* <h3>背景(2026-10 排查结论)</h3>
|
* 体检/门诊的 S050401 单若**先于** S0201ECG 到达,会走
|
* {@code insertAppointmentFromCheckAppointment} 容错新增;
|
* 而该路径原先**完全不解析检查类型**,导致 {@code appointment.book_check_type} 永远为空。
|
* <p>实测:{@code id=213466 / apply_no=8826092420371106}(2026-10-08 07:15 容错新增),
|
* 报文 {@code ZDY} 里明明有 {@code jcxmcode=201652, jcxmname=平板运动试验},
|
* 应映射为本地 {@code book_check_type=400}(平板运动心电)。
|
* 全库同类记录 279 条(2026-09-29 ~ 10-09)。
|
*
|
* <p>本次修复新增 {@code resolveBookCheckTypeFromZdy(ZDY, applyNo)},并接入两条路径:
|
* <ol>
|
* <li>容错新增({@code insertAppointmentFromCheckAppointment});</li>
|
* <li>更新已有记录({@code handleCheckAppointmentUpdate})。</li>
|
* </ol>
|
* 两条路径均遵循**仅在为空时补**(不覆盖已有值)。
|
*/
|
public class HisCheckAppointmentCheckTypeTest {
|
|
private Integer invokeResolve(Map<String, Object> zdy) throws Exception {
|
AppointmentServiceImpl svc = new AppointmentServiceImpl();
|
Method m = AppointmentServiceImpl.class.getDeclaredMethod(
|
"resolveBookCheckTypeFromZdy", Map.class, String.class);
|
m.setAccessible(true);
|
return (Integer) m.invoke(svc, zdy, "TEST-APPLY-NO");
|
}
|
|
private Map<String, Object> zdy(String name, String code) {
|
Map<String, Object> m = new HashMap<>();
|
if (name != null) {
|
m.put("jcxmname", name);
|
}
|
if (code != null) {
|
m.put("jcxmcode", code);
|
}
|
return m;
|
}
|
|
/** 真实故障样本:平板运动试验 → 400(走名称映射) */
|
@Test
|
public void testRealCase_pingBanYunDong_shouldMapTo400() throws Exception {
|
Integer v = invokeResolve(zdy("平板运动试验", "201652"));
|
assertNotNull("真实故障单的检查类型必须能解析出来", v);
|
assertEquals("平板运动试验 应映射为 400(平板运动心电)", Integer.valueOf(400), v);
|
System.out.println("[真实样本] jcxmname=平板运动试验 jcxmcode=201652 -> " + v);
|
}
|
|
/** HIS 改名场景:仅给代码 201652 也要能映射(名称映射不到时按代码兜底) */
|
@Test
|
public void testNameUnmappable_shouldFallbackToCode() throws Exception {
|
Integer v = invokeResolve(zdy("某个HIS新叫法未收录", "201652"));
|
assertEquals("名称映射不到时应按代码兜底为 400", Integer.valueOf(400), v);
|
System.out.println("[代码兜底] jcxmname=未收录 jcxmcode=201652 -> " + v);
|
}
|
|
/** 代码带 Y 前缀(S0201ECG 形态)也要兼容 */
|
@Test
|
public void testCodeWithYPrefix_shouldBeCompatible() throws Exception {
|
assertEquals(Integer.valueOf(400), invokeResolve(zdy(null, "Y201652")));
|
System.out.println("[前缀兼容] jcxmcode=Y201652 -> 400");
|
}
|
|
/** 多值:取第一个能映射成功的(实测 S0405 存在 jcxmcode=1080,3016,3014 形态) */
|
@Test
|
public void testMultiValue_shouldPickFirstMappable() throws Exception {
|
// 第一个是无关代码,第二个才是心电项目
|
Integer v = invokeResolve(zdy(null, "999999,201652"));
|
assertEquals("多值应取第一个能映射的", Integer.valueOf(400), v);
|
System.out.println("[多值] jcxmcode=999999,201652 -> " + v);
|
}
|
|
/** 名称多值(中文逗号)也要支持 */
|
@Test
|
public void testMultiValueName_shouldPickFirstMappable() throws Exception {
|
Integer v = invokeResolve(zdy("胸部CT平扫,平板运动试验", null));
|
assertEquals("名称多值应取第一个能映射的", Integer.valueOf(400), v);
|
System.out.println("[多值名称] jcxmname=胸部CT平扫,平板运动试验 -> " + v);
|
}
|
|
/** 其它心电项目也应正确映射(防只看一个样本) */
|
@Test
|
public void testOtherCheckTypes_shouldMapCorrectly() throws Exception {
|
assertEquals(Integer.valueOf(100), invokeResolve(zdy("常规心电图", "691133607")));
|
assertEquals(Integer.valueOf(200), invokeResolve(zdy("24小时动态心电图", "201605")));
|
assertEquals(Integer.valueOf(300), invokeResolve(zdy("动态血压", "200327")));
|
assertEquals(Integer.valueOf(1100), invokeResolve(zdy("常规心电图-心电向量图", "559542128")));
|
System.out.println("[多项目] 100/200/300/1100 均映射正确");
|
}
|
|
/** 无法映射时返回 null(调用方保持原值,不写坏数据)且不抛异常 */
|
@Test
|
public void testUnmappable_shouldReturnNullQuietly() throws Exception {
|
assertNull("非心电项目应返回 null", invokeResolve(zdy("胸部CT平扫", "1080")));
|
assertNull("空 ZDY 应返回 null", invokeResolve(new HashMap<>()));
|
assertNull("null ZDY 应返回 null 且不抛异常", invokeResolve(null));
|
System.out.println("[健壮性] 无法映射/空/null 均返回 null 且不抛异常");
|
}
|
}
|