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));