diff --git a/src/SheetMe.Data/Stores/PatientContextStore.cs b/src/SheetMe.Data/Stores/PatientContextStore.cs index fcdf861..6ce51d3 100644 --- a/src/SheetMe.Data/Stores/PatientContextStore.cs +++ b/src/SheetMe.Data/Stores/PatientContextStore.cs @@ -198,26 +198,30 @@ public sealed class PatientContextStore } /// - /// 요양기관명 — ETC_요양기관명칭_병원명(bzDataInterface.vb:15792-15860)의 조회. - /// M_DepMst ⨝ M_HspMst(DepHspCod=HspCod) 에서 HspInsNam 하나를 뽑아 Trim. + /// 요양기관 행 — ETC_요양기관명칭_* 12종(bzDataInterface.vb:15656-16709)의 공통 조회. + /// M_DepMst ⨝ M_HspMst(DepHspCod=HspCod) 에서 병원 컬럼들을 뽑는다. /// 진료과 코드로 병원을 찾는 구조다 — 다부지(병원 코드가 다른 진료과) 구성 때문으로 보인다. + /// + /// 레거시는 태그마다 이 조인을 따로 돌린다(12종 = 왕복 12회). + /// 컬럼만 다르므로 한 번에 다 뽑아 행으로 돌려준다 — 값 선택은 해석기가 한다. + /// 컬럼 9개는 전부 각 태그 본문의 SELECT 에서 확인한 것이다. /// - public string HospitalName(string? depCod, string? day) + public IReadOnlyDictionary HospitalRow(string? depCod, string? day) { var code = (depCod ?? string.Empty).Trim(); var date = (day ?? string.Empty).Trim(); if (code.Length == 0 || date.Length < 8) { - return string.Empty; + return new Dictionary(StringComparer.OrdinalIgnoreCase); } using var connection = new OracleConnection(connectionString); connection.Open(); - var row = Row(connection, - "SELECT HspInsNam FROM (SELECT HspInsNam FROM M_DepMst" + return Row(connection, + "SELECT * FROM (SELECT HspInsNam, HspOwnNam, HspTelNum, HspFaxNum," + + " HspKorAdr, HspEngNam, HspEngAdr, HspRgnNum, HspInsNum FROM M_DepMst" + " INNER JOIN M_HspMst ON DepHspCod = HspCod AND :y BETWEEN HspStrDte AND HspEndDte" + " WHERE TRIM(DepCod) = :d AND :y BETWEEN DepStrDte AND DepEndDte) WHERE ROWNUM = 1", ("d", code), ("y", date[..8])); - return PatientContext.Value(row, "HspInsNam"); } /// diff --git a/src/SheetMe.Designer/Diagnostics/DbSmoke.cs b/src/SheetMe.Designer/Diagnostics/DbSmoke.cs index a0f8919..c14d341 100644 --- a/src/SheetMe.Designer/Diagnostics/DbSmoke.cs +++ b/src/SheetMe.Designer/Diagnostics/DbSmoke.cs @@ -2200,8 +2200,9 @@ public static class DbSmoke Check("㉓ 진료과 마스터가 이름을 돌려준다", korNam.Trim().Length > 0, $"코드 '{depCod}' 로 M_DepMst 에서 이름을 못 찾았다"); - var hosp = contexts.HospitalName(depCod, octx.AdpDtm); - lines.Add($" 요양기관명: {hosp.Length}자"); + var hospRow = contexts.HospitalRow(depCod, octx.AdpDtm); + var hosp = PatientContext.Value(hospRow, "HspInsNam"); + lines.Add($" 요양기관: {hospRow.Count}열, 병원명 {hosp.Length}자"); Check("㉔ 요양기관명이 나온다", hosp.Trim().Length > 0, "M_DepMst⨝M_HspMst 조인이 0행 — 유효기간이나 DepHspCod 를 의심할 것"); diff --git a/src/SheetMe.Designer/Services/PatientIdentity.cs b/src/SheetMe.Designer/Services/PatientIdentity.cs index f0299ea..c244d13 100644 --- a/src/SheetMe.Designer/Services/PatientIdentity.cs +++ b/src/SheetMe.Designer/Services/PatientIdentity.cs @@ -154,25 +154,26 @@ public static class PatientIdentity } /// - /// 요양기관명 — 못 읽으면 빈 문자열. + /// 요양기관 행 — 못 읽으면 빈 사전. /// 판정 일자가 진료과와 다르다(bzDataInterface.vb:15815-15825): /// 입원·퇴원(ILV)은 퇴원일시, 입원 중은 지금, 외래는 접수일시 — 문맥의 적용일시가 그 판정과 같다. /// - public static string HospitalNameOf(PatientContext context) + public static IReadOnlyDictionary HospitalRowOf(PatientContext context) { var connection = ConfigService.Current.ConnectionString; + var empty = new Dictionary(StringComparer.OrdinalIgnoreCase); if (connection.Length == 0) { - return string.Empty; + return empty; } try { - return new PatientContextStore(connection).HospitalName( + return new PatientContextStore(connection).HospitalRow( PatientContext.Value(context.CodInf, "CodDepCod"), context.AdpDtm); } catch { - return string.Empty; + return empty; } } diff --git a/src/SheetMe.Designer/Services/PatientSession.cs b/src/SheetMe.Designer/Services/PatientSession.cs index b7dfdd4..1aaa25b 100644 --- a/src/SheetMe.Designer/Services/PatientSession.cs +++ b/src/SheetMe.Designer/Services/PatientSession.cs @@ -67,7 +67,7 @@ public static class PatientSession ? new PatientTagResolver(picked, session, PatientIdentity.ResidentNumberOf(picked), PatientIdentity.AddressOf(picked), PatientIdentity.DoctorOf(picked), PatientIdentity.DepartmentOf(picked), - PatientIdentity.HospitalNameOf(picked), + PatientIdentity.HospitalRowOf(picked), PatientIdentity.DiagnosisSourceFor(picked), PatientIdentity.SurgerySourceFor(picked), PatientIdentity.ReviewDiagnosisSourceFor(picked)) diff --git a/src/SheetMe.Designer/Services/PatientTagResolver.cs b/src/SheetMe.Designer/Services/PatientTagResolver.cs index bcc7e12..d053007 100644 --- a/src/SheetMe.Designer/Services/PatientTagResolver.cs +++ b/src/SheetMe.Designer/Services/PatientTagResolver.cs @@ -160,8 +160,8 @@ public sealed class PatientTagResolver : ITagValueResolver /// 이 내원의 진료과 마스터 행(M_DepMst) — 없으면 빈 사전 private readonly IReadOnlyDictionary department; - /// 요양기관명(HspInsNam) — 못 읽었으면 빈 문자열 - private readonly string hospitalName; + /// 요양기관 행(M_HspMst 컬럼들) — 없으면 빈 사전 + private readonly IReadOnlyDictionary hospital; /// /// 상병 행 공급자 — 주/부/전체 별로 물을 때 한 번만 읽는다. @@ -187,7 +187,8 @@ public sealed class PatientTagResolver : ITagValueResolver public PatientTagResolver(PatientContext context, ITagValueResolver next, string residentNumber = "", IReadOnlyDictionary? address = null, IReadOnlyDictionary? doctor = null, - IReadOnlyDictionary? department = null, string hospitalName = "", + IReadOnlyDictionary? department = null, + IReadOnlyDictionary? hospital = null, Func>>? diagnosisSource = null, Func>>? surgerySource = null, Func>>? reviewSource = null) @@ -198,7 +199,7 @@ public sealed class PatientTagResolver : ITagValueResolver this.address = address ?? new Dictionary(StringComparer.OrdinalIgnoreCase); this.doctor = doctor ?? new Dictionary(StringComparer.OrdinalIgnoreCase); this.department = department ?? new Dictionary(StringComparer.OrdinalIgnoreCase); - this.hospitalName = hospitalName; + this.hospital = hospital ?? new Dictionary(StringComparer.OrdinalIgnoreCase); this.diagnosisSource = diagnosisSource; this.surgerySource = surgerySource; this.reviewSource = reviewSource; @@ -401,10 +402,59 @@ public sealed class PatientTagResolver : ITagValueResolver ? "이 내원의 진료과를 찾지 못했습니다" : "진료과 마스터에 이름이 비어 있습니다"); } + // ── 요양기관 12종 — 같은 조인의 다른 컬럼(bzDataInterface.vb:15656-16709) ── + // 접미·결합도 본문 그대로: 병원장 = 병원명+"장", 귀하 = +"장 귀하", + // 전화_팩스 = "Tel : … FAX : …", 영문판은 "+82 - " 접두가 붙는다. case "ETC_요양기관명칭_병원명": - return hospitalName.Trim().Length > 0 - ? new TagValue(true, hospitalName.Trim()) - : new TagValue(false, "요양기관명을 찾지 못했습니다(M_DepMst·M_HspMst 조인)"); + case "ETC_요양기관명칭_병원명_영문": + case "ETC_요양기관명칭_병원대표자": + case "ETC_요양기관명칭_병원장": + case "ETC_요양기관명칭_병원장귀하": + case "ETC_요양기관명칭_병원전화번호": + case "ETC_요양기관명칭_병원팩스번호": + case "ETC_요양기관명칭_병원전화_팩스번호": + case "ETC_요양기관명칭_영문_병원전화_팩스번호": + case "ETC_요양기관명칭_병원주소": + case "ETC_요양기관명칭_병원주소_영문": + case "ETC_요양기관명칭_사업자등록번호": + case "ETC_요양기관기호": + { + if (hospital.Count == 0) + { + return new TagValue(false, "요양기관 정보를 찾지 못했습니다(M_DepMst·M_HspMst 조인)"); + } + string Hsp(string column) => hospital.TryGetValue(column, out var v) ? v.Trim() : string.Empty; + + var hspValue = tag switch + { + "ETC_요양기관명칭_병원명" => Hsp("HspInsNam"), + "ETC_요양기관명칭_병원명_영문" => Hsp("HspEngNam"), + "ETC_요양기관명칭_병원대표자" => Hsp("HspOwnNam"), + "ETC_요양기관명칭_병원장" => Hsp("HspInsNam") + "장", + "ETC_요양기관명칭_병원장귀하" => Hsp("HspInsNam") + "장 귀하", + "ETC_요양기관명칭_병원전화번호" => Hsp("HspTelNum"), + "ETC_요양기관명칭_병원팩스번호" => Hsp("HspFaxNum"), + "ETC_요양기관명칭_병원전화_팩스번호" => + $"Tel : {Hsp("HspTelNum")} FAX : {Hsp("HspFaxNum")}", + "ETC_요양기관명칭_영문_병원전화_팩스번호" => + $"Tel : +82 - {Hsp("HspTelNum")} FAX : +82 - {Hsp("HspFaxNum")}", + "ETC_요양기관명칭_병원주소" => Hsp("HspKorAdr"), + "ETC_요양기관명칭_병원주소_영문" => Hsp("HspEngAdr"), + "ETC_요양기관명칭_사업자등록번호" => Hsp("HspRgnNum"), + _ => Hsp("HspInsNum"), + }; + // 병원장·전화_팩스는 접두·접미가 붙어 "장"만 남을 수 있다 — 재료 컬럼으로 빈 값을 판정한다 + var material = tag switch + { + "ETC_요양기관명칭_병원장" or "ETC_요양기관명칭_병원장귀하" => Hsp("HspInsNam"), + "ETC_요양기관명칭_병원전화_팩스번호" or "ETC_요양기관명칭_영문_병원전화_팩스번호" + => Hsp("HspTelNum") + Hsp("HspFaxNum"), + _ => hspValue, + }; + return material.Trim().Length > 0 + ? new TagValue(true, hspValue) + : new TagValue(false, "요양기관 행은 있는데 그 값이 비어 있습니다"); + } // ── User 계열 — 로그인 사용자가 의사면 사용자의 과·이름, 아니면 환자의 것 ── // (bzDataInterface.vb:5697-5826). 개원일 조건(HspStrDte>=20220701)은 세션에 없어 @@ -642,6 +692,12 @@ public sealed class PatientTagResolver : ITagValueResolver "PAT_우편번호", "PAT_도로명주소", "PAT_지번주소", "PAT_영문도로명주소", "OCM_담당의사", "OCM_담당의사_담당의사코드", "OCM_담당의사_연락처", "OCM_진료과", "ETC_요양기관명칭_병원명", + "ETC_요양기관명칭_병원명_영문", "ETC_요양기관명칭_병원대표자", + "ETC_요양기관명칭_병원장", "ETC_요양기관명칭_병원장귀하", + "ETC_요양기관명칭_병원전화번호", "ETC_요양기관명칭_병원팩스번호", + "ETC_요양기관명칭_병원전화_팩스번호", "ETC_요양기관명칭_영문_병원전화_팩스번호", + "ETC_요양기관명칭_병원주소", "ETC_요양기관명칭_병원주소_영문", + "ETC_요양기관명칭_사업자등록번호", "ETC_요양기관기호", "OCM_담당의사_영문", "OCM_담당의사면허번호", "OCM_담당의사전문의번호", "OCM_User진료과", "OCM_User진료과_한글명칭", "OCM_User진료의사명", "OCM_상병명_가로", "OCM_상병명_세로", "OCM_상병명_영어_가로", "OCM_상병명_영어_세로", diff --git a/src/SheetMe.Designer/Views/PreviewWindow.xaml.cs b/src/SheetMe.Designer/Views/PreviewWindow.xaml.cs index 416c972..01da328 100644 --- a/src/SheetMe.Designer/Views/PreviewWindow.xaml.cs +++ b/src/SheetMe.Designer/Views/PreviewWindow.xaml.cs @@ -224,7 +224,7 @@ public partial class PreviewWindow : Window : new PatientTagResolver(picked, session, PatientIdentity.ResidentNumberOf(picked), PatientIdentity.AddressOf(picked), PatientIdentity.DoctorOf(picked), PatientIdentity.DepartmentOf(picked), - PatientIdentity.HospitalNameOf(picked), + PatientIdentity.HospitalRowOf(picked), PatientIdentity.DiagnosisSourceFor(picked), PatientIdentity.SurgerySourceFor(picked), PatientIdentity.ReviewDiagnosisSourceFor(picked));