diff --git a/src/SheetMe.Data/Stores/PatientExtraStore.cs b/src/SheetMe.Data/Stores/PatientExtraStore.cs index d34e2f6..1f26831 100644 --- a/src/SheetMe.Data/Stores/PatientExtraStore.cs +++ b/src/SheetMe.Data/Stores/PatientExtraStore.cs @@ -839,6 +839,39 @@ public sealed class PatientExtraStore + " FROM O_PrgInf WHERE PrgComNum = :m ORDER BY PrgUpdDtf DESC) WHERE ROWNUM = 1", ("m", comNum)); + /// + /// 낮병동 신청 구간(OCM_재원일수_낮병동, :8083) — 시작·종료일 두 컬럼. + /// 입원일자_낮병동과 같은 조건이고 결정 규칙(시작일 최신)도 같다. + /// + public IReadOnlyDictionary DayCareRange(decimal comNum) + => Row( + "SELECT * FROM (SELECT DcpStrDte, DcpEndDte FROM P_ComInf" + + " INNER JOIN P_DcpInf ON ComChtNum = DcpChtNum" + + " AND ComAcpDtm BETWEEN DcpStrDte AND DcpEndDte || '2359'" + + " AND DcpAcpStt = 'A'" + + " WHERE ComNum = :m AND ComAcpStt <> 'OC' AND ComDayCar = 'Y'" + + " ORDER BY DcpStrDte DESC) WHERE ROWNUM = 1", + ("m", comNum)); + + /// + /// 로그인 부서의 수간호사 이름(ETC_로그인사용자_병동_수간호사, :15507) — + /// 직급 코드표(PSTCOD)에서 '수간호사'/'간호수선생' 코드를 찾아 그 직급의 재직자. + /// 레거시는 두 쿼리 모두 정렬 없는 Rows(0) — 코드·사용자 코드 순으로 고정하고 + /// 한 왕복으로 접었다(레거시도 첫 직급 코드 하나만 쓴다). + /// + public string WardHeadNurse(string depCod) + => depCod.Trim().Length == 0 ? string.Empty + : Scalar( + "SELECT v FROM (SELECT UidNam v FROM M_UidMst" + + " WHERE TRIM(UidDepCod) = :d" + + " AND UidPstCod IN (SELECT c FROM (SELECT DtsCod c FROM M_DtsMst" + + " WHERE TO_CHAR(SYSDATE, 'YYYYMMDD') BETWEEN DtsStrDte AND DtsExpDte" + + " AND DtsDtlCod = 'PSTCOD' AND DtsCodNam IN ('수간호사','간호수선생')" + + " ORDER BY DtsCod) WHERE ROWNUM = 1)" + + " AND TO_CHAR(SYSDATE, 'YYYYMMDD') BETWEEN UidStrDte AND UidEndDte" + + " ORDER BY UidCod) WHERE ROWNUM = 1", + ("d", depCod.Trim())); + /// 스칼라 1칸 — 0행이거나 NULL 이면 빈 문자열. 잔여 공백은 걷는다(문맥 행과 같은 규칙) private string Scalar(string sql, params (string Name, object Value)[] binds) { diff --git a/src/SheetMe.Designer/Diagnostics/DbSmoke.cs b/src/SheetMe.Designer/Diagnostics/DbSmoke.cs index 760b513..b0798da 100644 --- a/src/SheetMe.Designer/Diagnostics/DbSmoke.cs +++ b/src/SheetMe.Designer/Diagnostics/DbSmoke.cs @@ -2480,6 +2480,8 @@ public static class DbSmoke ("특수계산코드", () => extra.SpecialNonInsuredCalCodes().Count.ToString()), ("그룹과목", () => extra.GroupSubjectRow("0506").Count.ToString()), ("임신정보", () => owner2 is null ? "-" : extra.PregnancyRow(owner2.Value).Count.ToString()), + ("낮병동구간", () => owner2 is null ? "-" : extra.DayCareRange(owner2.Value).Count.ToString()), + ("수간호사", () => extra.WardHeadNurse("0506").Length.ToString()), ("적용진료과", () => extra.AppliedDepartmentName("0506", "202601011200").Length.ToString()), ("전과목록", () => owner2 is null ? "-" : extra.TransferList(owner2.Value).Count.ToString()), ("간호과거력", () => owner2 is null ? "-" : extra.NurseHistoryRow(owner2.Value).Count.ToString()), diff --git a/src/SheetMe.Designer/Services/PatientTagResolver.cs b/src/SheetMe.Designer/Services/PatientTagResolver.cs index 8ae72f1..4dc1ad5 100644 --- a/src/SheetMe.Designer/Services/PatientTagResolver.cs +++ b/src/SheetMe.Designer/Services/PatientTagResolver.cs @@ -1592,7 +1592,7 @@ public sealed class PatientTagResolver : ITagValueResolver { if (tag is not ("OCM_입원시간" or "OCM_입원일시" or "OCM_입원일시_영문" or "OCM_입실시간" or "OCM_의사퇴원예고일시" or "OCM_퇴원예정일시" or "OCM_퇴원시간" or "OCM_퇴원일시" - or "OCM_퇴원예고일시" or "OCM_재원일수" or "OCM_퇴원예고재원일수")) + or "OCM_퇴원예고일시" or "OCM_재원일수" or "OCM_퇴원예고재원일수" or "OCM_재원일수_단입법")) { return null; } @@ -1653,6 +1653,13 @@ public sealed class PatientTagResolver : ITagValueResolver ? NeedFacility() ?? (string.CompareOrdinal(openDate, "20200901") >= 0 ? StayDays(acp, today) : Ask()) : NeedFacility() ?? StayDays(acp, today); + case "OCM_재원일수_단입법": + // 재원일수와 같은 분기인데 +1 이 없다(:7947 — 끝날을 세지 않는다) + return prg == "ILV" ? StayDaysExclusive(acp, lev) + : inpatient + ? NeedFacility() ?? (string.CompareOrdinal(openDate, "20200901") >= 0 + ? StayDaysExclusive(acp, today) : Ask()) + : NeedFacility() ?? StayDaysExclusive(acp, today); default: // OCM_퇴원예고재원일수 return prg == "ILV" ? StayDays(acp, lev) : prg == "ILP" ? StayDays(acp, sch) @@ -1692,6 +1699,15 @@ public sealed class PatientTagResolver : ITagValueResolver return new TagValue(true, ((end - start).Days + 1).ToString()); } + /// 단입법 재원일수 — +1 없이 날짜 차이만(:7947) + private static TagValue StayDaysExclusive(string from, string to) + { + var days = ResidentNumber.DaysSince(from, to); + return days is null + ? new TagValue(false, "재원일수를 만들 날짜를 읽지 못했습니다") + : new TagValue(true, days.Value.ToString()); + } + /// 가 담당하는 태그들 — 전부 자기 SQL 이거나 그 조합 private static readonly HashSet ExtraTags = new(StringComparer.Ordinal) { @@ -1721,6 +1737,7 @@ public sealed class PatientTagResolver : ITagValueResolver "OCM_퇴원약_코드", "OCM_퇴원약_명칭", "OCM_퇴원약_용량", "OCM_퇴원약_횟수", "OCM_퇴원약_일수", "OCM_퇴원약_용법", "OCM_퇴원약", "OCM_퇴원약_New", "OCM_비급여처방", "OCM_진단서전문그룹과목", "OCM_청구진료과목", "OCM_임신주기", + "OCM_재원일수_낮병동", "ETC_로그인사용자_병동_수간호사", }; /// @@ -2443,6 +2460,34 @@ public sealed class PatientTagResolver : ITagValueResolver return Wrap(store.CodeName("BDPTBL", billCod), "청구 코드표(BDPTBL)에 이름이 없습니다"); } + case "OCM_재원일수_낮병동": + { + // 낮병동 신청 구간 일수 + 1(:8083) — 구간이 없으면 레거시도 빈 값 + var comNum = PatientContext.Value(context.ComInf, "ComNum"); + if (!decimal.TryParse(comNum, out var m)) + { + return new TagValue(false, "이 내원의 내원번호를 읽지 못했습니다"); + } + var range = store.DayCareRange(m); + if (range.Count == 0) + { + return new TagValue(false, "낮병동 신청(P_DcpInf) 구간이 이 내원을 포함하지 않습니다"); + } + var days = ResidentNumber.DaysSince( + PatientContext.Value(range, "DcpStrDte"), + PatientContext.Value(range, "DcpEndDte")); + return days is null + ? new TagValue(false, "낮병동 구간 날짜를 읽지 못했습니다") + : new TagValue(true, (days.Value + 1).ToString()); + } + case "ETC_로그인사용자_병동_수간호사": + { + // 로그인 부서의 수간호사(:15507) — 환자와 무관한 세션 태그다 + var nurse = store.WardHeadNurse(UserSession.Current.DepCod); + return nurse.Length > 0 + ? new TagValue(true, nurse) + : new TagValue(false, "로그인 부서에 수간호사 직급 재직자가 없습니다"); + } case "OCM_임신주기": { var comNum = PatientContext.Value(context.ComInf, "ComNum"); @@ -2802,6 +2847,7 @@ public sealed class PatientTagResolver : ITagValueResolver "OCM_퇴원약_코드", "OCM_퇴원약_명칭", "OCM_퇴원약_용량", "OCM_퇴원약_횟수", "OCM_퇴원약_일수", "OCM_퇴원약_용법", "OCM_퇴원약", "OCM_퇴원약_New", "OCM_비급여처방", "OCM_진단서전문그룹과목", "OCM_청구진료과목", "OCM_임신주기", + "OCM_재원일수_낮병동", "ETC_로그인사용자_병동_수간호사", "OCM_재원일수_단입법", "OCM_입원시간", "OCM_입원일시", "OCM_입원일시_영문", "OCM_입실시간", "OCM_의사퇴원예고일시", "OCM_퇴원예정일시", "OCM_퇴원시간", "OCM_퇴원일시", "OCM_퇴원예고일시", "OCM_재원일수", "OCM_퇴원예고재원일수", "OCM_입원일자_낮병동",