상병 11종을 옮긴다 — SQL 은 원문에서 기계 추출했다. 40종 → 51종
## Okd_상병쿼리(bzDataInterface.vb:14160-14623)의 이식 구조: 블록1(M_KcdMst 와 맞는 상병, INNER JOIN) UNION 블록2(마스터에 없는 코드 — LEFT JOIN 후 KcdCod IS NULL). 주/부 필터(OkdDspSeq='1' / <>'1')가 <b>각 블록에, ROW_NUMBER 접기 앞에</b> 붙는다. 그래서 전체(T)를 받아 클라이언트에서 가르면 안 된다 — 같은 코드가 주·부 양쪽에 있으면 RN 접기가 한쪽을 지워 결과가 갈린다. 갈래(T/M/S)별로 따로 조회하되, 태그가 물을 때 한 번만 읽고 캐시한다. SQL 은 손으로 다시 치지 않고 <b>VB 원문에서 기계 추출했다</b>(Select Case 를 Case Else 경로로 시뮬레이션, AppendLine 페이로드만 수집) — 55줄이 공백까지 원문 그대로다. ## 병원 분기를 얼버무리지 않는다 원문은 쿼리 자체가 6갈래(KIMEYE·NYJB·SYBS·HIMCHAN_CW·SPHH·Else)로 갈리고, 이름 규칙이 JEGG(배제 접미), 코드 규칙이 BSGH(KcdSeqCod)에서 또 갈린다. 이 DB(SRCH)의 Case Else 만 옮겼고, 그 병원들에서는 <b>미이식이라고 말한다</b> — Else 로 뭉개면 그 병원 서식에 다른 모양의 상병이 조용히 찍힌다. NYJB 갈래에는 사용자 코드를 SQL 에 <b>문자열로 잇는</b> 주입 구멍도 있다(:14235) — 옮길 때 바인드로 바꿔야 한다는 것을 조사 문서가 이미 적어 뒀다. ## 태그 11종 (전부 본문에서 결합 규칙 확인) 상병명_가로/세로 · 영어_가로/세로 · 코드_가로/세로 전체(T) 부상병코드 · 부상병POA 부(S) 주상병명 · 주상병코드 · 주상병POA 주(M) 첫 행 가로 = ", " 구분, 세로 = 줄바꿈. 한글명에만 확→(확진)·의→(의증) 접미. 주상병명은 접미 없이 KcdKorNam(:10126), 주상병코드는 KcdElcCod(:9744). ## 실DB 확인 (--db-patient ㉕~㉗ 신규) O_OkdInf 에 행을 가진 내원을 찾아 걸었다(행 없는 내원으로 판정하는 함정을 이미 두 번 밟았다). 내원 6005266: 전체 1행 = 주 1 + 부 0, 한글명 11자. 주/부 필터 분해가 전체와 일치한다. ## 게이트 - dotnet test 338/338 · --edit-smoke 실패 0(이름 검사 51종) - --db-patient ①~㉗ 전건 통과 - --db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 불변 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
9278b39a6d
commit
0da3305a75
@@ -0,0 +1,128 @@
|
||||
using Oracle.ManagedDataAccess.Client;
|
||||
|
||||
namespace SheetMe.Data.Stores;
|
||||
|
||||
/// <summary>
|
||||
/// 상병(진단) 조회 — 레거시 <c>Okd_상병쿼리</c>(bzDataInterface.vb:14160-14623)의 이식.
|
||||
///
|
||||
/// <b>이 DB(SRCH)가 타는 Case Else 갈래만 옮겼다.</b> 원문은 병원 코드로 여섯 갈래
|
||||
/// (KIMEYE·NYJB·SYBS·HIMCHAN_CW·SPHH·Else)로 갈리는데, 그 다섯은 SELECT 목록·이름 결합이
|
||||
/// 제각각이라 각각 별도 이식이다. 그 병원에서는 태그가 <b>미이식이라고 말한다</b> —
|
||||
/// Else 갈래로 얼버무리면 그 병원 서식에 다른 모양의 상병명이 조용히 찍힌다.
|
||||
///
|
||||
/// <b>SQL 은 원문에서 기계 추출했다</b>(Select Case 를 Case Else 경로로 시뮬레이션) —
|
||||
/// 손으로 다시 치면 공백·결합 규칙이 달라진다. 구조는:
|
||||
/// 블록1(M_KcdMst 와 맞는 상병) UNION 블록2(마스터에 없는 코드 — LEFT JOIN 후 KcdCod IS NULL)
|
||||
/// 각 블록에 주/부 필터가 붙고 블록마다 ROW_NUMBER=1 로 접은 뒤 OkdDspSeq 순으로 정렬한다.
|
||||
///
|
||||
/// 값은 이 저장소가 만들지 않는다 — 행 목록만 돌려주고 결합(가로/세로·확진/의증 접미)은
|
||||
/// 해석기가 한다. 태그 8종이 같은 결과셋을 다르게 자를 뿐이기 때문이다.
|
||||
/// </summary>
|
||||
public sealed class DiagnosisStore
|
||||
{
|
||||
#region Member Fields
|
||||
/// <summary>주/부 구분 — 레거시 psOkdTyp(T=전체, M=주상병, S=부상병)</summary>
|
||||
public enum Scope { All, Main, Sub }
|
||||
|
||||
private readonly string connectionString;
|
||||
|
||||
/// <summary>원문 그대로의 쿼리 틀 — {TYPE} 자리에 주/부 필터가 들어간다</summary>
|
||||
private const string Template = @"
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT OkdKcdCod, OkdNam, OkdKcdSeq, OkdDspSeq, OkdCfmSus, OkdEntDtf, OkdVeeCod
|
||||
, KcdCod, KcdElcCod, KcdKorNam, KcdEngNam, KcdElcCod || '-' || TRIM(KcdSeq) AS KcdSeqCod, OkdPoaTyp
|
||||
, OkdDtrNam
|
||||
, ROW_NUMBER() OVER(PARTITION BY KcdCod ORDER BY KcdStrDte DESC) AS OKD_RN
|
||||
FROM O_OkdInf
|
||||
INNER JOIN P_ComInf
|
||||
ON OkdComNum = ComNum
|
||||
INNER JOIN M_KcdMst
|
||||
ON KcdCod = TRIM(OkdKcdCod)
|
||||
AND TRIM(OkdKcdSeq) = KcdSeq
|
||||
AND KcdEndDte >= SUBSTR(ComAcpDtm, 1, 8)
|
||||
AND KcdStrDte <= SUBSTR(ComAcpDtm, 1, 8)
|
||||
WHERE OkdComNum = :piComNum
|
||||
AND OkdStt = 'E'
|
||||
{TYPE}
|
||||
) OKD
|
||||
WHERE OKD_RN = 1
|
||||
|
||||
UNION
|
||||
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT OkdKcdCod, OkdNam, OkdKcdSeq, OkdDspSeq, OkdCfmSus, OkdEntDtf, OkdVeeCod
|
||||
, KCD.KcdCod, KCD.KcdElcCod, KCD.KcdKorNam, KCD.KcdEngNam, KCD.KcdElcCod || '-' || TRIM(KCD.KcdSeq) AS KcdSeqCod, OkdPoaTyp
|
||||
, OkdDtrNam
|
||||
, ROW_NUMBER() OVER(PARTITION BY KCD.KcdCod ORDER BY KCD.KcdStrDte DESC) AS OKD_RN
|
||||
FROM (
|
||||
SELECT OkdKcdCod, OkdNam, OkdKcdSeq, OkdDspSeq, OkdCfmSus, OkdEntDtf, OkdVeeCod
|
||||
, KcdCod, KcdElcCod, KcdKorNam, KcdEngNam, KcdSeq, OkdPoaTyp
|
||||
, OkdDtrNam
|
||||
FROM O_OkdInf
|
||||
INNER JOIN P_ComInf
|
||||
ON OkdComNum = ComNum
|
||||
LEFT JOIN M_KcdMst
|
||||
ON KcdCod = TRIM(OkdKcdCod)
|
||||
AND TRIM(OkdKcdSeq) = KcdSeq
|
||||
AND KcdEndDte >= SUBSTR(ComAcpDtm, 1, 8)
|
||||
AND KcdStrDte <= SUBSTR(ComAcpDtm, 1, 8)
|
||||
WHERE OkdComNum = :piComNum
|
||||
AND OkdStt = 'E'
|
||||
) OKD
|
||||
INNER JOIN M_KcdMst KCD
|
||||
ON KCD.KcdCod = TRIM(OkdKcdCod)
|
||||
AND OkdKcdSeq = KCD.KcdSeq
|
||||
WHERE 1=1
|
||||
AND (OKD.KcdCod IS NULL OR OKD.KcdCod = ' ')
|
||||
{TYPE}
|
||||
) OKD
|
||||
WHERE OKD_RN = 1
|
||||
)
|
||||
ORDER BY OkdDspSeq
|
||||
";
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public DiagnosisStore(string connectionString) => this.connectionString = connectionString;
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
/// <summary>이 내원의 상병 행들 — 표시 순서(OkdDspSeq)대로. 없으면 빈 목록</summary>
|
||||
public List<Dictionary<string, string>> Diagnoses(decimal comNum, Scope scope = Scope.All)
|
||||
{
|
||||
var filter = scope switch
|
||||
{
|
||||
Scope.Main => " AND OkdDspSeq = '1' ",
|
||||
Scope.Sub => " AND OkdDspSeq <> '1' ",
|
||||
_ => string.Empty,
|
||||
};
|
||||
var sql = Template.Replace("{TYPE}", filter);
|
||||
|
||||
using var connection = new OracleConnection(connectionString);
|
||||
connection.Open();
|
||||
using var command = connection.CreateCommand();
|
||||
command.BindByName = true;
|
||||
command.CommandText = sql;
|
||||
command.Parameters.Add(new OracleParameter("piComNum", comNum));
|
||||
|
||||
var rows = new List<Dictionary<string, string>>();
|
||||
using var reader = command.ExecuteReader();
|
||||
while (reader.Read())
|
||||
{
|
||||
var row = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
for (var i = 0; i < reader.FieldCount; i++)
|
||||
{
|
||||
row[reader.GetName(i)] = reader.IsDBNull(i)
|
||||
? string.Empty
|
||||
: reader.GetValue(i).ToString()!.Trim();
|
||||
}
|
||||
rows.Add(row);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -2204,6 +2204,39 @@ public static class DbSmoke
|
||||
lines.Add($" 요양기관명: {hosp.Length}자");
|
||||
Check("㉔ 요양기관명이 나온다", hosp.Trim().Length > 0,
|
||||
"M_DepMst⨝M_HspMst 조인이 0행 — 유효기간이나 DepHspCod 를 의심할 것");
|
||||
|
||||
// ㉕ 상병 — 원문 기계 추출 SQL 이 실제로 돈다.
|
||||
// 이 내원에 상병이 없을 수 있으므로 O_OkdInf 에 행을 가진 내원을 찾아 건다
|
||||
// (앞서 두 번 밟은 "행 없는 내원으로 판정" 함정).
|
||||
var okdOwner = FirstComNum(conn, "O_OkdInf", "OkdComNum", "OkdComNum");
|
||||
if (okdOwner is null)
|
||||
{
|
||||
Check("㉕ 상병 — O_OkdInf 에 행이 없어 확인 불가", false,
|
||||
"이 DB 로는 이 갈래를 확인할 수 없다");
|
||||
}
|
||||
else
|
||||
{
|
||||
var diag = new DiagnosisStore(conn);
|
||||
var all = diag.Diagnoses(okdOwner.Value);
|
||||
var main = diag.Diagnoses(okdOwner.Value, DiagnosisStore.Scope.Main);
|
||||
var sub = diag.Diagnoses(okdOwner.Value, DiagnosisStore.Scope.Sub);
|
||||
lines.Add($" 상병: 내원 {okdOwner.Value:F0} → 전체 {all.Count}행,"
|
||||
+ $" 주 {main.Count}행, 부 {sub.Count}행");
|
||||
Check("㉕ 상병 쿼리(전체)가 행을 돌려준다", all.Count > 0,
|
||||
"OkdStt='E' 조건이나 UNION 결합을 의심할 것");
|
||||
Check("㉖ 주/부 필터가 실제로 가른다", main.Count + sub.Count == all.Count
|
||||
&& main.Count <= all.Count,
|
||||
$"주 {main.Count} + 부 {sub.Count} ≠ 전체 {all.Count} — RN 접기 전 필터 규칙 확인");
|
||||
if (all.Count > 0)
|
||||
{
|
||||
var okdKorNam = all[0].TryGetValue("KcdKorNam", out var kn) ? kn : "";
|
||||
lines.Add($" 첫 상병: 한글명 {okdKorNam.Length}자,"
|
||||
+ $" 코드 {(all[0].TryGetValue("KcdElcCod", out var kc) ? kc.Length : 0)}자"
|
||||
+ " (값은 기록하지 않는다)");
|
||||
Check("㉗ 상병 한글명이 나온다", okdKorNam.Trim().Length > 0,
|
||||
"M_KcdMst 조인이 빈 이름을 냈다");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +94,21 @@ public static class PatientIdentity
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 상병 행 공급자 — 해석기가 <b>필요할 때</b> 갈래(전체/주/부)별로 부른다.
|
||||
/// 여기서 미리 읽지 않는 이유는 상병 태그가 없는 서식이 다수이기 때문이다.
|
||||
/// 실패는 던진다 — 해석기가 잡아 사유로 바꾼다(조용히 빈 목록을 주면
|
||||
/// "상병이 없다"와 "조회가 죽었다"를 화면에서 못 가른다).
|
||||
/// </summary>
|
||||
public static Func<DiagnosisStore.Scope, IReadOnlyList<Dictionary<string, string>>>
|
||||
DiagnosisSourceFor(PatientContext context)
|
||||
{
|
||||
var connection = ConfigService.Current.ConnectionString;
|
||||
return scope => connection.Length == 0
|
||||
? new List<Dictionary<string, string>>()
|
||||
: new DiagnosisStore(connection).Diagnoses(context.ComNum, scope);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이 내원의 진료과 마스터 행 — 못 읽으면 빈 사전.
|
||||
/// 진료과 코드는 문맥의 CodInf(적용일시로 고른 행)에서, 유효기간 일자는
|
||||
|
||||
@@ -67,7 +67,8 @@ public static class PatientSession
|
||||
? new PatientTagResolver(picked, session,
|
||||
PatientIdentity.ResidentNumberOf(picked), PatientIdentity.AddressOf(picked),
|
||||
PatientIdentity.DoctorOf(picked), PatientIdentity.DepartmentOf(picked),
|
||||
PatientIdentity.HospitalNameOf(picked))
|
||||
PatientIdentity.HospitalNameOf(picked),
|
||||
PatientIdentity.DiagnosisSourceFor(picked))
|
||||
: session;
|
||||
return (tags, new MDataTableRunner(document, Variables()));
|
||||
}
|
||||
|
||||
@@ -163,10 +163,22 @@ public sealed class PatientTagResolver : ITagValueResolver
|
||||
/// <summary>요양기관명(HspInsNam) — 못 읽었으면 빈 문자열</summary>
|
||||
private readonly string hospitalName;
|
||||
|
||||
/// <summary>
|
||||
/// 상병 행 공급자 — 주/부/전체 별로 <b>물을 때 한 번만</b> 읽는다.
|
||||
/// 세 갈래를 미리 다 읽지 않는 이유: 상병 태그가 없는 서식이 다수인데
|
||||
/// 환자를 붙일 때마다 왕복 셋을 무조건 내는 것은 낭비다.
|
||||
/// 전체(T)에서 주/부를 클라이언트에서 가르지 <b>않는</b> 이유: 레거시는 필터를
|
||||
/// ROW_NUMBER 접기 <b>앞</b>에 넣으므로 같은 코드가 주·부 양쪽에 있으면 결과가 갈린다.
|
||||
/// </summary>
|
||||
private readonly Func<DiagnosisStore.Scope, IReadOnlyList<Dictionary<string, string>>>? diagnosisSource;
|
||||
|
||||
private readonly Dictionary<DiagnosisStore.Scope, IReadOnlyList<Dictionary<string, string>>> diagnosisCache = new();
|
||||
|
||||
public PatientTagResolver(PatientContext context, ITagValueResolver next,
|
||||
string residentNumber = "", IReadOnlyDictionary<string, string>? address = null,
|
||||
IReadOnlyDictionary<string, string>? doctor = null,
|
||||
IReadOnlyDictionary<string, string>? department = null, string hospitalName = "")
|
||||
IReadOnlyDictionary<string, string>? department = null, string hospitalName = "",
|
||||
Func<DiagnosisStore.Scope, IReadOnlyList<Dictionary<string, string>>>? diagnosisSource = null)
|
||||
{
|
||||
this.context = context;
|
||||
this.next = next;
|
||||
@@ -175,6 +187,7 @@ public sealed class PatientTagResolver : ITagValueResolver
|
||||
this.doctor = doctor ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
this.department = department ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
this.hospitalName = hospitalName;
|
||||
this.diagnosisSource = diagnosisSource;
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -198,6 +211,10 @@ public sealed class PatientTagResolver : ITagValueResolver
|
||||
{
|
||||
return facilityValue;
|
||||
}
|
||||
if (FromDiagnosis(tag) is { } diagnosisValue)
|
||||
{
|
||||
return diagnosisValue;
|
||||
}
|
||||
if (Computed.TryGetValue(tag, out var compute))
|
||||
{
|
||||
var made = compute(context);
|
||||
@@ -404,6 +421,88 @@ public sealed class PatientTagResolver : ITagValueResolver
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 상병 11종 — 해당 태그가 아니면 null. 같은 결과셋을 다르게 자를 뿐이다.
|
||||
///
|
||||
/// 결합 규칙(전부 본문에서 확인):
|
||||
/// · 가로 = ", " 구분(:OCM_상병명_가로 else 가지), 세로 = 줄바꿈(AppendLine)
|
||||
/// · 한글명에는 확→(확진)·의→(의증) 접미, 영어명·코드에는 접미 없음
|
||||
/// · 주상병(첫 행): 명은 접미 없이 KcdKorNam(:10126 Case Else), 코드는 KcdElcCod(:9744)
|
||||
///
|
||||
/// <b>병원 분기를 얼버무리지 않는다.</b> 쿼리 자체가 갈리는 5병원과
|
||||
/// 이름·코드 규칙이 갈리는 JEGG·BSGH 는 미이식이라고 말한다 —
|
||||
/// Else 갈래로 뭉개면 그 병원 서식에 다른 모양의 상병이 조용히 찍힌다.
|
||||
/// </summary>
|
||||
private TagValue? FromDiagnosis(string tag)
|
||||
{
|
||||
var scope = tag switch
|
||||
{
|
||||
"OCM_상병명_가로" or "OCM_상병명_세로" or "OCM_상병명_영어_가로" or "OCM_상병명_영어_세로"
|
||||
or "OCM_상병코드_가로" or "OCM_상병코드_세로" => DiagnosisStore.Scope.All,
|
||||
"OCM_부상병코드" or "OCM_부상병POA" => DiagnosisStore.Scope.Sub,
|
||||
"OCM_주상병명" or "OCM_주상병코드" or "OCM_주상병POA" => DiagnosisStore.Scope.Main,
|
||||
_ => (DiagnosisStore.Scope?)null,
|
||||
} is { } s ? s : (DiagnosisStore.Scope?)null;
|
||||
if (scope is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var hsp = UserSession.Current.HspCod;
|
||||
if (hsp is "KIMEYE" or "NYJB" or "SYBS" or "HIMCHAN_CW" or "SPHH"
|
||||
|| (hsp == "JEGG" && tag is "OCM_상병명_세로" or "OCM_주상병명")
|
||||
|| (hsp == "BSGH" && tag == "OCM_주상병코드"))
|
||||
{
|
||||
return new TagValue(false, $"이 병원({hsp})의 상병 분기는 아직 옮기지 않았습니다");
|
||||
}
|
||||
if (diagnosisSource is null)
|
||||
{
|
||||
return new TagValue(false, "상병 조회가 연결되지 않았습니다");
|
||||
}
|
||||
if (!diagnosisCache.TryGetValue(scope.Value, out var rows))
|
||||
{
|
||||
try
|
||||
{
|
||||
rows = diagnosisSource(scope.Value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new TagValue(false, $"상병 조회에 실패했습니다: {ex.GetType().Name}");
|
||||
}
|
||||
diagnosisCache[scope.Value] = rows;
|
||||
}
|
||||
if (rows.Count == 0)
|
||||
{
|
||||
return new TagValue(false, "이 내원에 등록된 상병이 없습니다");
|
||||
}
|
||||
|
||||
static string Cell(Dictionary<string, string> r, string c) => r.TryGetValue(c, out var v) ? v.Trim() : string.Empty;
|
||||
|
||||
static string Suffix(Dictionary<string, string> r) => Cell(r, "OkdCfmSus") switch
|
||||
{
|
||||
"확" => "(확진)",
|
||||
"의" => "(의증)",
|
||||
_ => string.Empty,
|
||||
};
|
||||
|
||||
var value = tag switch
|
||||
{
|
||||
"OCM_상병명_가로" => string.Join(", ", rows.Select(r => Cell(r, "KcdKorNam") + Suffix(r))),
|
||||
"OCM_상병명_세로" => string.Join(Environment.NewLine, rows.Select(r => Cell(r, "KcdKorNam") + Suffix(r))),
|
||||
"OCM_상병명_영어_가로" => string.Join(", ", rows.Select(r => Cell(r, "KcdEngNam"))),
|
||||
"OCM_상병명_영어_세로" => string.Join(Environment.NewLine, rows.Select(r => Cell(r, "KcdEngNam"))),
|
||||
"OCM_상병코드_가로" => string.Join(", ", rows.Select(r => Cell(r, "KcdElcCod"))),
|
||||
"OCM_상병코드_세로" => string.Join(Environment.NewLine, rows.Select(r => Cell(r, "KcdElcCod"))),
|
||||
"OCM_부상병코드" => string.Join(Environment.NewLine, rows.Select(r => Cell(r, "KcdElcCod"))),
|
||||
"OCM_부상병POA" => string.Join(Environment.NewLine, rows.Select(r => Cell(r, "OkdPoaTyp"))),
|
||||
"OCM_주상병명" => Cell(rows[0], "KcdKorNam"),
|
||||
"OCM_주상병코드" => Cell(rows[0], "KcdElcCod"),
|
||||
_ => Cell(rows[0], "OkdPoaTyp"),
|
||||
};
|
||||
return value.Trim().Length > 0
|
||||
? new TagValue(true, value)
|
||||
: new TagValue(false, "상병 행은 있는데 그 값이 비어 있습니다");
|
||||
}
|
||||
|
||||
/// <summary>주민번호에서 나온 값 — 비면 <b>왜</b> 비었는지 말한다</summary>
|
||||
private TagValue Wrap(string value) => value.Length > 0
|
||||
? new TagValue(true, value)
|
||||
@@ -421,6 +520,9 @@ public sealed class PatientTagResolver : ITagValueResolver
|
||||
"OCM_진료과", "ETC_요양기관명칭_병원명",
|
||||
"OCM_담당의사_영문", "OCM_담당의사면허번호", "OCM_담당의사전문의번호",
|
||||
"OCM_User진료과", "OCM_User진료과_한글명칭", "OCM_User진료의사명",
|
||||
"OCM_상병명_가로", "OCM_상병명_세로", "OCM_상병명_영어_가로", "OCM_상병명_영어_세로",
|
||||
"OCM_상병코드_가로", "OCM_상병코드_세로", "OCM_부상병코드", "OCM_부상병POA",
|
||||
"OCM_주상병명", "OCM_주상병코드", "OCM_주상병POA",
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -224,7 +224,8 @@ 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.HospitalNameOf(picked),
|
||||
PatientIdentity.DiagnosisSourceFor(picked));
|
||||
// 러너를 <b>새로</b> 만든다. 같은 러너를 재사용하면 옛 환자의 조회 결과가 캐시에 남아
|
||||
// 환자를 바꿨는데 표는 그대로가 된다 — 태그만 바뀌고 표는 안 바뀌면 아무도 눈치채지 못한다.
|
||||
fields = new MDataTableRunner(designer.Document,
|
||||
|
||||
Reference in New Issue
Block a user