using Oracle.ManagedDataAccess.Client; namespace SheetMe.Data.Stores; /// /// HIS 로그인 사용자 — 감사 컬럼(SdgUidCod/ShtUpdUid 등)에 기록되는 UidCod 의 유일한 출처. /// 부서·병원은 표시 전용이며 없어도 인증은 성립한다(레거시 bzLogIn 과 동일 의미론). /// public sealed record HisUser( string UidCod, string UidNam, string DepCod, string DepNam, string HspCod, string HspNam, /// 의사 여부(UidDtrYon=Y) — OCM_User진료과 계열이 로그인 사용자 분기에 쓴다 string DoctorYn = "", /// 부서 공식 명칭(DepOfcNam) — 개원일 조건이 걸리는 병원에서 한글명 대신 쓴다 string DepOfficialName = "", /// 의사면허번호(UidLicNum) — ETC_로그인_의사면허번호 string LicenseNumber = "", /// 전문의번호(UidSpcLic) — ETC_로그인_전문의번호 string SpecialistNumber = "", /// 직종명(M_DtsMst JOBCOD 의 DtsCodNam) — ETC_로그인_직종 string JobName = "", /// 부서 전화번호(M_DepMst.DepTelNum) — ETC_접속유저_부서번호(이름과 달리 전화번호다) string DepPhone = "", /// 영문 이름(UidEngNam) — 진단서의사_영문의 로그인 의사 갈래 string EnglishName = "", /// 세부전문의번호(UidDtlSpcLic) — 진단서의사세부전문의번호 string DetailSpecialistNumber = "", /// 싸인 이미지 원격 경로(UidImgPth) — 로그인 사용자 싸인 계열 string SignaturePath = "") { /// 미인증 세션(인자 없이 단독 실행) — DB 쓰기가 차단된다 public static readonly HisUser Unknown = new(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty); /// HIS 사용자로 확인되었는지 public bool IsAuthenticated => UidCod.Length > 0; /// 표시용 — "홍길동(MSYS)" 형태, 미인증이면 안내 문구 public string Display => IsAuthenticated ? (UidNam.Length > 0 ? $"{UidNam}({UidCod})" : UidCod) : "사용자 미확인"; } /// /// 사용자 컨텍스트 조회 — 레거시 bzLogIn.LogIn(uid, autoLogin) 의 신규 대응물. /// 레거시도 자동 로그인에서는 비밀번호를 확인하지 않고 M_UidMst 행 존재 + 유효기간만 판정한다 /// (daLogIn.vb: SELECT * FROM M_UidMst WHERE UidCod=:u AND :adp BETWEEN UidStrDte AND UidEndDte). /// public sealed class UserContextStore { #region Member Fields private readonly string connectionString; #endregion #region Constructors public UserContextStore(string connectionString) { this.connectionString = connectionString; } #endregion #region Methods /// /// UidCod 검증 + 표시 정보 조회 — 미존재이거나 유효기간 밖이면 null. /// 적용일자는 서버 시각을 쓴다(단말 시계가 밀리면 유효 계정이 거부될 수 있다). /// 부서·병원은 LEFT JOIN 이라 마스터에 행이 없어도 인증 자체는 성립한다. /// public HisUser? Resolve(string uidCod) { if (string.IsNullOrWhiteSpace(uidCod)) { return null; } using var connection = new OracleConnection(connectionString); connection.Open(); using var command = connection.CreateCommand(); command.BindByName = true; // 레거시와 두 가지가 의도적으로 다르다(워크플로 검증이 짚었고, 받아들이기로 했다): // · 유효기간 판정 일자 — 레거시는 로그인 시점(GetAdpDtm 앞 8자, clsCommonLib.vb:10622), // 여기는 SYSDATE. 자정을 넘겨 계속 켜 둔 세션에서만 갈린다. // · Trim — 레거시는 UidCod/UidNam 을 무가공으로 쓰고(bzDataInterface.vb:16713, 16720) // 여기는 걷는다. CHAR 잔여 공백이 종이에 찍히는 쪽이 더 이상하다고 판단했다. command.CommandText = "SELECT u.UidCod, NVL(u.UidNam,' '), " + " NVL(u.UidDepCod,' '), NVL(d.DepKorNam,' '), " + " NVL(u.UidHspCod,' '), NVL(h.HspInsNam,' '), " + " NVL(u.UidDtrYon,' '), NVL(d.DepOfcNam,' '), " + " NVL(u.UidLicNum,' '), NVL(u.UidSpcLic,' '), NVL(j.DtsCodNam,' '), " + " NVL(d.DepTelNum,' '), NVL(u.UidEngNam,' '), NVL(u.UidDtlSpcLic,' '), " + " NVL(u.UidImgPth,' ') " + "FROM M_UidMst u " + "LEFT JOIN M_DepMst d ON d.DepCod = u.UidDepCod " + " AND TO_CHAR(SYSDATE,'YYYYMMDD') BETWEEN d.DepStrDte AND d.DepEndDte " + "LEFT JOIN M_HspMst h ON h.HspCod = u.UidHspCod " + " AND TO_CHAR(SYSDATE,'YYYYMMDD') BETWEEN h.HspStrDte AND NVL(h.HspEndDte,'99991231') " + // 직종 조인은 레거시 그대로 DtsDtlCod 만으로 건다(bzDataInterface.vb:17944 — DtsTblCod 조건이 없다) "LEFT JOIN M_DtsMst j ON j.DtsDtlCod = 'JOBCOD' AND j.DtsCod = u.UidJobCod " + " AND TO_CHAR(SYSDATE,'YYYYMMDD') BETWEEN j.DtsStrDte AND j.DtsExpDte " + "WHERE u.UidCod = :u " + "AND TO_CHAR(SYSDATE,'YYYYMMDD') BETWEEN u.UidStrDte AND u.UidEndDte"; command.Parameters.Add(new OracleParameter("u", uidCod.Trim())); using var reader = command.ExecuteReader(); if (!reader.Read()) { return null; } return new HisUser( reader.GetString(0).Trim(), reader.GetString(1).Trim(), reader.GetString(2).Trim(), reader.GetString(3).Trim(), reader.GetString(4).Trim(), reader.GetString(5).Trim(), reader.GetString(6).Trim(), reader.GetString(7).Trim(), reader.GetString(8).Trim(), reader.GetString(9).Trim(), reader.GetString(10).Trim(), reader.GetString(11).Trim(), reader.GetString(12).Trim(), reader.GetString(13).Trim(), reader.GetString(14).Trim()); } #endregion }