진단서 의사·수술일자·외래실진료일 16종 — 193종 → 209종 (조사 라운드 6)
진단서 계열 8종(bzDataInterface.vb:4380-4845): 로그인 사용자가 의사(UidDtrYon='Y')면 로그인 사용자의 값, 아니면 담당의의 값 — 시점·기준일(입원 CodEndDtm·외래 접수일)이 담당의 프리페치와 같은 판정이라 그 행을 재사용한다. 의사명(UidNam)·명_외래(입원이면 조회 없이 빈)·영문(UidEngNam)·면허(UidLicNum)·전문의(UidSpcLic)· 세부전문의(UidDtlSpcLic)·전문과목(개원일 2022-07-01 분기, TYRCH 미이식)·청구진료과목_로그인(DepBilCod→BDPTBL, 원문의 같은 쿼리 2회 실행은 1회로). 로그인 행에 영문명·세부전문의번호 컬럼 2개 추가. 값 5종: OCM_당뇨식칼로리_List(:3569 — 원문부터 결정적), OCM_수술일자(:2977 Case Else — 첫 수술 OprKey ASC; PURME·BSGH· HIMCHAN·GJHNSS 분기 미이식), OCM_수술일자_마지막수술(:2999), OCM_외래실진료일/_과목별(:1217/:1503 — 신환 첫 접수(폴백 전체 첫 접수)~마지막 접수 구간의 과 매칭 접수일 전부 "YYYY/MM/DD" ", " 결합. 같은 날 중복 출력도 원문 그대로. 본체 종료일 쿼리의 문자열 연결은 같은 값이라 바인드로 정상화). 사유 완결 3종: OCM_외래실진료일수(:1645 — 차트번호 자리에 시작일 바인드 + 없는 컬럼(OcmAcpDtm) 정렬, 상시 ORA-00904→빈 값인 레거시 결함), ETC_승인의사(:3892 — EmrKey 의존, 미리보기 부재), OCM_수술소독간호사(:3028 — PURME 전용, 그 외 병원은 빈 SQL 실행). - dotnet test 338/338 · --edit-smoke 실패 0 (이름 검사 209종) - --db-patient ①~㉟ 전건 통과 (㉟ 4종 추가 — 청구과목 실값 4자) - --db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 불변 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
4e6e086ece
commit
7dcc4c2e48
@@ -2444,6 +2444,10 @@ public static class DbSmoke
|
||||
("퇴원약오더", () => owner2 is null ? "-" : extra.DischargeMedicationOrderDate(owner2.Value).Length.ToString()),
|
||||
("응급증상", () => owner2 is null ? "-" : (extra.EmergencySymptomInsYon(owner2.Value) ?? "[없음]")),
|
||||
("전과내역", () => owner2 is null ? "-" : extra.TransferHistory(owner2.Value).Count.ToString()),
|
||||
("당뇨식이", () => extra.DiabetesMealCalorie(extraOwner).Length.ToString()),
|
||||
("수술일자", () => owner2 is null ? "-" : extra.SurgeryDate(owner2.Value, false).Length.ToString()),
|
||||
("외래실진료일", () => extra.OutpatientVisitDays(extraOwner, "999912312359", "05", false).Count.ToString()),
|
||||
("청구과목", () => extra.BillingDepartmentName("0506").Length.ToString()),
|
||||
};
|
||||
var shapes2 = new List<string>();
|
||||
var failed = new List<string>();
|
||||
|
||||
@@ -352,6 +352,10 @@ public sealed class PatientTagResolver : ITagValueResolver
|
||||
{
|
||||
return bodyValue;
|
||||
}
|
||||
if (FromCertificate(tag) is { } certValue)
|
||||
{
|
||||
return certValue;
|
||||
}
|
||||
if (Computed.TryGetValue(tag, out var compute))
|
||||
{
|
||||
var made = compute(context);
|
||||
@@ -959,6 +963,121 @@ public sealed class PatientTagResolver : ITagValueResolver
|
||||
: new TagValue(false, "수술일자 값이 형식에 맞지 않습니다");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 진단서 의사 계열 8종(bzDataInterface.vb:4380-4845).
|
||||
///
|
||||
/// <b>로그인 사용자가 의사면 로그인 사용자의 값이다</b>(UidDtrYon='Y' — 진단서는
|
||||
/// 보는 의사 이름으로 나간다). 아니면 담당의 — 시점(퇴원/현재/접수)과 기준일
|
||||
/// (입원 CodEndDtm·외래 접수일)이 담당의 프리페치와 같은 판정이라 그 행을 재사용한다.
|
||||
/// </summary>
|
||||
private TagValue? FromCertificate(string tag)
|
||||
{
|
||||
if (tag is not ("OCM_진단서의사명" or "OCM_진단서의사명_외래" or "OCM_진단서의사_영문"
|
||||
or "OCM_진단서의사면허번호" or "OCM_진단서의사전문의번호" or "OCM_진단서의사세부전문의번호"
|
||||
or "OCM_진단서전문과목" or "OCM_진단서청구진료과목_로그인"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var loginDoctor = UserSession.Current.DoctorYn == "Y";
|
||||
string Doc(string column) => doctor.TryGetValue(column, out var v) ? v.Trim() : string.Empty;
|
||||
TagValue FromColumn(string column, string loginValue)
|
||||
{
|
||||
if (loginDoctor)
|
||||
{
|
||||
return loginValue.Length > 0
|
||||
? new TagValue(true, loginValue)
|
||||
: new TagValue(false, "로그인 사용자 행에 이 값이 비어 있습니다");
|
||||
}
|
||||
if (tag == "OCM_진단서의사명_외래" && Com(context, "ComPatTyp") == "I")
|
||||
{
|
||||
return new TagValue(true, string.Empty); // 입원은 레거시가 조회 없이 "" 다(:4418)
|
||||
}
|
||||
if (doctor.Count == 0)
|
||||
{
|
||||
return new TagValue(false, "이 내원의 담당의를 찾지 못했습니다");
|
||||
}
|
||||
var value = Doc(column);
|
||||
return value.Length > 0
|
||||
? new TagValue(true, value)
|
||||
: new TagValue(false, $"담당의 행에 {column} 값이 비어 있습니다");
|
||||
}
|
||||
switch (tag)
|
||||
{
|
||||
case "OCM_진단서의사명":
|
||||
case "OCM_진단서의사명_외래":
|
||||
return FromColumn("UidNam", UserSession.Current.UidNam);
|
||||
case "OCM_진단서의사_영문":
|
||||
return FromColumn("UidEngNam", UserSession.Current.EnglishName);
|
||||
case "OCM_진단서의사면허번호":
|
||||
return FromColumn("UidLicNum", UserSession.Current.LicenseNumber);
|
||||
case "OCM_진단서의사전문의번호":
|
||||
return FromColumn("UidSpcLic", UserSession.Current.SpecialistNumber);
|
||||
case "OCM_진단서의사세부전문의번호":
|
||||
return FromColumn("UidDtlSpcLic", UserSession.Current.DetailSpecialistNumber);
|
||||
case "OCM_진단서전문과목":
|
||||
{
|
||||
// 로그인 의사면 로그인 부서, 아니면 담당의 진료과(:4663-4725).
|
||||
// TYRCH(대외명칭만) 분기는 미이식 — Else 갈래: 개원일 2022-07-01 이후면
|
||||
// 대외명칭 우선(비면 한글명), 이전이면 한글명.
|
||||
string office, korean;
|
||||
if (loginDoctor)
|
||||
{
|
||||
office = UserSession.Current.DepOfficialName;
|
||||
korean = UserSession.Current.DepNam;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (doctor.Count == 0)
|
||||
{
|
||||
return new TagValue(false, "이 내원의 담당의를 찾지 못했습니다");
|
||||
}
|
||||
if (department.Count == 0)
|
||||
{
|
||||
return new TagValue(false, "이 내원의 진료과를 찾지 못했습니다");
|
||||
}
|
||||
office = PatientContext.Value(department, "DepOfcNam").Trim();
|
||||
korean = PatientContext.Value(department, "DepKorNam").Trim();
|
||||
}
|
||||
var open = PatientContext.Value(hospital, "HspStrDte");
|
||||
var name = string.CompareOrdinal(open, "20220701") >= 0 && office.Length > 0
|
||||
? office : korean;
|
||||
return name.Length > 0
|
||||
? new TagValue(true, name)
|
||||
: new TagValue(false, "진료과 이름이 비어 있습니다");
|
||||
}
|
||||
default: // OCM_진단서청구진료과목_로그인
|
||||
{
|
||||
var depCod = loginDoctor
|
||||
? UserSession.Current.DepCod
|
||||
: PatientContext.Value(context.CodInf, "CodDepCod");
|
||||
if (depCod.Length == 0)
|
||||
{
|
||||
return new TagValue(false, loginDoctor
|
||||
? "로그인 사용자에 부서 코드가 없습니다"
|
||||
: "이 내원의 진료과 코드를 읽지 못했습니다");
|
||||
}
|
||||
if (!loginDoctor && doctor.Count == 0)
|
||||
{
|
||||
return new TagValue(false, "이 내원의 담당의를 찾지 못했습니다"); // 레거시도 즉시 ""(:4820)
|
||||
}
|
||||
if (extraStoreSource?.Invoke() is not { } billingStore)
|
||||
{
|
||||
return new TagValue(false, "부가정보 조회가 연결되지 않았습니다");
|
||||
}
|
||||
try
|
||||
{
|
||||
return billingStore.BillingDepartmentName(depCod) is { Length: > 0 } billing
|
||||
? new TagValue(true, billing)
|
||||
: new TagValue(false, "청구 코드표(BDPTBL)에 짝이 되는 행이 없습니다");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new TagValue(false, $"청구과목 조회에 실패했습니다: {ex.GetType().Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// BST·BMI·체중 파생 6종(bzDataInterface.vb:12042-12420).
|
||||
///
|
||||
@@ -1383,6 +1502,9 @@ public sealed class PatientTagResolver : ITagValueResolver
|
||||
"OCM_계산유형", "OCM_보험유형", "OCM_수납일시",
|
||||
"OCM_진료기간", "OCM_진료기간_진료과",
|
||||
"OCM_응급증상여부_YES", "OCM_응급증상여부_NO", "OCM_전과내역",
|
||||
"OCM_당뇨식칼로리_List", "OCM_수술일자", "OCM_수술일자_마지막수술",
|
||||
"OCM_외래실진료일", "OCM_외래실진료일_과목별", "OCM_외래실진료일수",
|
||||
"ETC_승인의사", "OCM_수술소독간호사",
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -1767,6 +1889,60 @@ public sealed class PatientTagResolver : ITagValueResolver
|
||||
return new TagValue(true,
|
||||
(tag == "OCM_응급증상여부_YES") == yes ? "Y" : string.Empty);
|
||||
}
|
||||
case "OCM_당뇨식칼로리_List":
|
||||
return Wrap(store.DiabetesMealCalorie(chtNum), "당뇨식 식이 기록(O_ImlInf)이 없습니다");
|
||||
case "OCM_수술일자":
|
||||
case "OCM_수술일자_마지막수술":
|
||||
{
|
||||
// 본체는 첫 수술(OprKey ASC), 마지막수술은 최신(:2977/:2999).
|
||||
// PURME(마취 오더)·BSGH/HIMCHAN/GJHNSS(내림차순) 분기는 미이식.
|
||||
var comNum = PatientContext.Value(context.ComInf, "ComNum");
|
||||
if (!decimal.TryParse(comNum, out var m))
|
||||
{
|
||||
return new TagValue(false, "이 내원의 내원번호를 읽지 못했습니다");
|
||||
}
|
||||
var opDate = store.SurgeryDate(m, latestFirst: tag == "OCM_수술일자_마지막수술");
|
||||
return opDate.Length >= 8
|
||||
? new TagValue(true, Hyphenate(opDate[..8]))
|
||||
: new TagValue(false, "확정(OprStt='E')된 수술 신청(S_OprInf)이 없습니다");
|
||||
}
|
||||
case "OCM_외래실진료일":
|
||||
case "OCM_외래실진료일_과목별":
|
||||
{
|
||||
var acp = PatientContext.Value(context.ComInf, "ComAcpDtm");
|
||||
var depCod = PatientContext.Value(context.CodInf, "CodDepCod");
|
||||
if (acp.Length < 8 || depCod.Length == 0)
|
||||
{
|
||||
return new TagValue(false, "이 내원의 접수일시·진료과를 읽지 못했습니다");
|
||||
}
|
||||
// 본체는 과 앞 2자, 과목별은 전체 코드 일치(:1331/:1617)
|
||||
var exact = tag == "OCM_외래실진료일_과목별";
|
||||
var days = store.OutpatientVisitDays(chtNum, acp,
|
||||
exact ? depCod : depCod[..Math.Min(2, depCod.Length)], exact);
|
||||
if (days.Count == 0)
|
||||
{
|
||||
return new TagValue(false, "구간 안에 이 진료과의 접수가 없습니다");
|
||||
}
|
||||
// "YYYY/MM/DD" 를 ", " 로 — 마지막 뒤에는 없음(:1341-1350). DISTINCT 가
|
||||
// 없어 같은 날 복수 접수는 중복 출력된다(레거시 그대로).
|
||||
return new TagValue(true, string.Join(", ",
|
||||
days.Select(d => $"{d[..4]}/{d[4..6]}/{d[6..8]}")));
|
||||
}
|
||||
case "OCM_외래실진료일수":
|
||||
// 원문(:1645-1762)의 건수 쿼리가 차트번호 자리에 시작일을 바인드하고
|
||||
// (ComChtNum = :sStrDte) 존재하지 않는 컬럼(OcmAcpDtm)으로 정렬한다 —
|
||||
// 실행마다 ORA-00904 → 오류창 → 빈 값이다. 고치면 없던 값이 생긴다.
|
||||
return new TagValue(false,
|
||||
"레거시 결함(잘못된 바인드·없는 컬럼 정렬)으로 항상 빈 값인 태그입니다");
|
||||
case "ETC_승인의사":
|
||||
// 저장된 기록(EmrKey+ShtCod)의 승인자와 현재 작업자를 비교한다(:3892) —
|
||||
// 미리보기에는 저장된 기록 키가 없다. Cosign 과 같은 이유로 완결.
|
||||
return new TagValue(false,
|
||||
"저장된 기록에서만 값이 됩니다 — 미리보기에는 기록 키(EmrKey)가 없습니다");
|
||||
case "OCM_수술소독간호사":
|
||||
// PURME 전용(:3028) — 그 밖의 병원은 빈 SQL 을 실행해 항상 빈 값이다
|
||||
return new TagValue(false,
|
||||
"PURME 전용 태그입니다 — 그 밖의 병원에서는 레거시도 항상 빈 값입니다");
|
||||
case "OCM_전과내역":
|
||||
{
|
||||
var comNum = PatientContext.Value(context.ComInf, "ComNum");
|
||||
@@ -1973,6 +2149,12 @@ public sealed class PatientTagResolver : ITagValueResolver
|
||||
"OCM_병실인실", "OCM_병실차액", "OCM_진료과_전화번호", "OCM_전과일시", "OCM_전과일자",
|
||||
"OCM_계산유형", "OCM_보험유형", "OCM_수납일시", "OCM_진료기간", "OCM_진료기간_진료과",
|
||||
"OCM_응급증상여부_YES", "OCM_응급증상여부_NO", "OCM_전과내역",
|
||||
"OCM_진단서의사명", "OCM_진단서의사명_외래", "OCM_진단서의사_영문",
|
||||
"OCM_진단서의사면허번호", "OCM_진단서의사전문의번호", "OCM_진단서의사세부전문의번호",
|
||||
"OCM_진단서전문과목", "OCM_진단서청구진료과목_로그인",
|
||||
"OCM_당뇨식칼로리_List", "OCM_수술일자", "OCM_수술일자_마지막수술",
|
||||
"OCM_외래실진료일", "OCM_외래실진료일_과목별", "OCM_외래실진료일수",
|
||||
"ETC_승인의사", "OCM_수술소독간호사",
|
||||
"OCM_입원시간", "OCM_입원일시", "OCM_입원일시_영문", "OCM_입실시간",
|
||||
"OCM_의사퇴원예고일시", "OCM_퇴원예정일시", "OCM_퇴원시간", "OCM_퇴원일시",
|
||||
"OCM_퇴원예고일시", "OCM_재원일수", "OCM_퇴원예고재원일수", "OCM_입원일자_낮병동",
|
||||
|
||||
Reference in New Issue
Block a user