로그인 계열 6종 — 세션 사용자 행을 넓혀 해결. 95종 → 100종 + Dead 1
## 세션 조회 확장(UserContextStore) M_UidMst 행에서 UidLicNum·UidSpcLic 를 더 읽고, 직종명은 레거시 그대로 DtsDtlCod='JOBCOD' 만으로 M_DtsMst 를 조인해(bzDataInterface.vb:17944 — DtsTblCod 조건이 없다) DtsCodNam 을 가져온다. HisUser 에 세 필드 추가. ## 태그 5종 + Dead 1종 - ETC_로그인_의사면허번호(UidLicNum) · 전문의번호(UidSpcLic) · 직종(DtsCodNam) - ETC_로그인_근무부서 = 세션 부서 한글명. 레거시는 개원일(HspStrDte>=20220701)로 DepOfcNam 을 가르지만 개원일 미상 결정에 따라 DepKorNam 갈래다(기존 결정과 동일). - ETC_로그인_근무부서_사용자명 = "부서-이름". 레거시는 UidNam 으로 걸러 동명이인에서 남의 부서가 나올 수 있는데 세션 사용자 행이라 결정적이다(주석 기록). - ETC_로그인_직급 → Dead. 값은 UidNam 을 담고 조건은 UidCod 로 걸어(:17262·17272) 실무상 늘 빈칸이던 태그다. 고치면 없던 값이 갑자기 채워지므로 합의 전까지 레거시 유지. 레거시의 면허·전문의번호 조회는 유효기간 없이 M_DepMst 를 불필요하게 조인해 ORDER BY 없이 첫 행을 집는 비결정 조회였다(조사 문서 risk) — 세션 행(유효기간 검증 완료)에서 읽는 쪽이 결정적이고 값 원천(M_UidMst 같은 행)은 같다. ## 게이트 - dotnet test 338/338 · --edit-smoke 실패 0(이름 검사 100종) - --db-patient 전건 통과 · --db-render P062 md5 불변 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
94bdcc763f
commit
e065c5a645
@@ -68,6 +68,14 @@ public static class TagPreviewCatalog
|
|||||||
["ETC_로그인_사용자ID_사용자명"] = UserField.IdAndName,
|
["ETC_로그인_사용자ID_사용자명"] = UserField.IdAndName,
|
||||||
["ETC_로그인_사용자연락처"] = UserField.MobilePhone,
|
["ETC_로그인_사용자연락처"] = UserField.MobilePhone,
|
||||||
["ETC_로그인_원내연락처"] = UserField.OfficePhone,
|
["ETC_로그인_원내연락처"] = UserField.OfficePhone,
|
||||||
|
// 세션 사용자 행(M_UidMst + 직종 조인)에서 나온다 — 환자 문맥이 필요 없다.
|
||||||
|
// 근무부서는 레거시가 개원일(HspStrDte>=20220701)로 DepOfcNam/DepKorNam 을 가르는데
|
||||||
|
// 개원일은 세션에 없어 빈 값 결정이라 DepKorNam 갈래로 간다(OCM_진료과와 같은 결정).
|
||||||
|
["ETC_로그인_의사면허번호"] = UserField.License,
|
||||||
|
["ETC_로그인_전문의번호"] = UserField.Specialist,
|
||||||
|
["ETC_로그인_직종"] = UserField.Job,
|
||||||
|
["ETC_로그인_근무부서"] = UserField.Department,
|
||||||
|
["ETC_로그인_근무부서_사용자명"] = UserField.DepartmentAndName,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -84,6 +92,11 @@ public static class TagPreviewCatalog
|
|||||||
// 환자를 골라도 영원히 안 나온다. 사유를 정직하게 하려고 넣는다.
|
// 환자를 골라도 영원히 안 나온다. 사유를 정직하게 하려고 넣는다.
|
||||||
["ETC_건강보험증번호_Refer"] = TagPreviewKind.Dead,
|
["ETC_건강보험증번호_Refer"] = TagPreviewKind.Dead,
|
||||||
|
|
||||||
|
// 값은 UidNam 을 담고 조건은 UidCod 로 건다(bzDataInterface.vb:17262·17272) —
|
||||||
|
// 실무상 0건이라 레거시에서 늘 빈칸이던 태그다. 고치면 없던 값이 갑자기 채워지므로
|
||||||
|
// 출시 전 합의 전까지 레거시 동작(항상 빈 값)을 유지한다.
|
||||||
|
["ETC_로그인_직급"] = TagPreviewKind.Dead,
|
||||||
|
|
||||||
// 태그가 아니라 내부 헬퍼 — 우리 카탈로그가 Public Function 을 전수 추출해 섞여 들어왔다.
|
// 태그가 아니라 내부 헬퍼 — 우리 카탈로그가 Public Function 을 전수 추출해 섞여 들어왔다.
|
||||||
// 레거시 태그 목록(fmDataTag)은 PAT_/OCM_/ETC_ 접두어만 올린다.
|
// 레거시 태그 목록(fmDataTag)은 PAT_/OCM_/ETC_ 접두어만 올린다.
|
||||||
["퇴원약DT"] = TagPreviewKind.NotATag,
|
["퇴원약DT"] = TagPreviewKind.NotATag,
|
||||||
@@ -189,6 +202,11 @@ public static class TagPreviewCatalog
|
|||||||
|
|
||||||
/// <summary>로그인 사용자 정보에서 이 태그의 값을 만든다</summary>
|
/// <summary>로그인 사용자 정보에서 이 태그의 값을 만든다</summary>
|
||||||
public static string FromUser(string tag, string id, string name, string mobile, string office)
|
public static string FromUser(string tag, string id, string name, string mobile, string office)
|
||||||
|
=> FromUser(tag, id, name, mobile, office, string.Empty, string.Empty, string.Empty, string.Empty);
|
||||||
|
|
||||||
|
/// <summary>로그인 사용자 정보에서 — 면허·전문의·직종·부서까지 받는 본판</summary>
|
||||||
|
public static string FromUser(string tag, string id, string name, string mobile, string office,
|
||||||
|
string license, string specialist, string job, string depName)
|
||||||
{
|
{
|
||||||
if (!UserTags.TryGetValue(tag, out var field))
|
if (!UserTags.TryGetValue(tag, out var field))
|
||||||
{
|
{
|
||||||
@@ -203,12 +221,19 @@ public static class TagPreviewCatalog
|
|||||||
UserField.IdAndName => $"{id}.{name}",
|
UserField.IdAndName => $"{id}.{name}",
|
||||||
UserField.MobilePhone => mobile,
|
UserField.MobilePhone => mobile,
|
||||||
UserField.OfficePhone => office,
|
UserField.OfficePhone => office,
|
||||||
|
UserField.License => license,
|
||||||
|
UserField.Specialist => specialist,
|
||||||
|
UserField.Job => job,
|
||||||
|
UserField.Department => depName,
|
||||||
|
// 레거시(:17101)는 NVL(DepOfcNam,DepKorNam)||'-'||UidNam — 개원일 미상 결정으로 한글명 고정.
|
||||||
|
// 레거시는 UidNam 으로 걸러 동명이인에서 남의 부서가 나올 수 있는데 여기는 세션 사용자 행이라 결정적이다.
|
||||||
|
UserField.DepartmentAndName => depName.Length > 0 || name.Length > 0 ? $"{depName}-{name}" : string.Empty,
|
||||||
_ => string.Empty,
|
_ => string.Empty,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum ClockFormat { Date, DateTime, DateTimeMask, DateEnglish, Year, YearSuffixed, Month, Day, Hour, Minute, Time }
|
private enum ClockFormat { Date, DateTime, DateTimeMask, DateEnglish, Year, YearSuffixed, Month, Day, Hour, Minute, Time }
|
||||||
|
|
||||||
private enum UserField { Name, Id, IdAndName, MobilePhone, OfficePhone }
|
private enum UserField { Name, Id, IdAndName, MobilePhone, OfficePhone, License, Specialist, Job, Department, DepartmentAndName }
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,13 @@ public sealed record HisUser(
|
|||||||
/// <summary>의사 여부(UidDtrYon=Y) — OCM_User진료과 계열이 로그인 사용자 분기에 쓴다</summary>
|
/// <summary>의사 여부(UidDtrYon=Y) — OCM_User진료과 계열이 로그인 사용자 분기에 쓴다</summary>
|
||||||
string DoctorYn = "",
|
string DoctorYn = "",
|
||||||
/// <summary>부서 공식 명칭(DepOfcNam) — 개원일 조건이 걸리는 병원에서 한글명 대신 쓴다</summary>
|
/// <summary>부서 공식 명칭(DepOfcNam) — 개원일 조건이 걸리는 병원에서 한글명 대신 쓴다</summary>
|
||||||
string DepOfficialName = "")
|
string DepOfficialName = "",
|
||||||
|
/// <summary>의사면허번호(UidLicNum) — ETC_로그인_의사면허번호</summary>
|
||||||
|
string LicenseNumber = "",
|
||||||
|
/// <summary>전문의번호(UidSpcLic) — ETC_로그인_전문의번호</summary>
|
||||||
|
string SpecialistNumber = "",
|
||||||
|
/// <summary>직종명(M_DtsMst JOBCOD 의 DtsCodNam) — ETC_로그인_직종</summary>
|
||||||
|
string JobName = "")
|
||||||
{
|
{
|
||||||
/// <summary>미인증 세션(인자 없이 단독 실행) — DB 쓰기가 차단된다</summary>
|
/// <summary>미인증 세션(인자 없이 단독 실행) — DB 쓰기가 차단된다</summary>
|
||||||
public static readonly HisUser Unknown = new(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty);
|
public static readonly HisUser Unknown = new(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty);
|
||||||
@@ -71,12 +77,16 @@ public sealed class UserContextStore
|
|||||||
"SELECT u.UidCod, NVL(u.UidNam,' '), " +
|
"SELECT u.UidCod, NVL(u.UidNam,' '), " +
|
||||||
" NVL(u.UidDepCod,' '), NVL(d.DepKorNam,' '), " +
|
" NVL(u.UidDepCod,' '), NVL(d.DepKorNam,' '), " +
|
||||||
" NVL(u.UidHspCod,' '), NVL(h.HspInsNam,' '), " +
|
" NVL(u.UidHspCod,' '), NVL(h.HspInsNam,' '), " +
|
||||||
" NVL(u.UidDtrYon,' '), NVL(d.DepOfcNam,' ') " +
|
" NVL(u.UidDtrYon,' '), NVL(d.DepOfcNam,' '), " +
|
||||||
|
" NVL(u.UidLicNum,' '), NVL(u.UidSpcLic,' '), NVL(j.DtsCodNam,' ') " +
|
||||||
"FROM M_UidMst u " +
|
"FROM M_UidMst u " +
|
||||||
"LEFT JOIN M_DepMst d ON d.DepCod = u.UidDepCod " +
|
"LEFT JOIN M_DepMst d ON d.DepCod = u.UidDepCod " +
|
||||||
" AND TO_CHAR(SYSDATE,'YYYYMMDD') BETWEEN d.DepStrDte AND d.DepEndDte " +
|
" AND TO_CHAR(SYSDATE,'YYYYMMDD') BETWEEN d.DepStrDte AND d.DepEndDte " +
|
||||||
"LEFT JOIN M_HspMst h ON h.HspCod = u.UidHspCod " +
|
"LEFT JOIN M_HspMst h ON h.HspCod = u.UidHspCod " +
|
||||||
" AND TO_CHAR(SYSDATE,'YYYYMMDD') BETWEEN h.HspStrDte AND NVL(h.HspEndDte,'99991231') " +
|
" 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 " +
|
"WHERE u.UidCod = :u " +
|
||||||
"AND TO_CHAR(SYSDATE,'YYYYMMDD') BETWEEN u.UidStrDte AND u.UidEndDte";
|
"AND TO_CHAR(SYSDATE,'YYYYMMDD') BETWEEN u.UidStrDte AND u.UidEndDte";
|
||||||
command.Parameters.Add(new OracleParameter("u", uidCod.Trim()));
|
command.Parameters.Add(new OracleParameter("u", uidCod.Trim()));
|
||||||
@@ -90,7 +100,8 @@ public sealed class UserContextStore
|
|||||||
reader.GetString(0).Trim(), reader.GetString(1).Trim(),
|
reader.GetString(0).Trim(), reader.GetString(1).Trim(),
|
||||||
reader.GetString(2).Trim(), reader.GetString(3).Trim(),
|
reader.GetString(2).Trim(), reader.GetString(3).Trim(),
|
||||||
reader.GetString(4).Trim(), reader.GetString(5).Trim(),
|
reader.GetString(4).Trim(), reader.GetString(5).Trim(),
|
||||||
reader.GetString(6).Trim(), reader.GetString(7).Trim());
|
reader.GetString(6).Trim(), reader.GetString(7).Trim(),
|
||||||
|
reader.GetString(8).Trim(), reader.GetString(9).Trim(), reader.GetString(10).Trim());
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,9 @@ public sealed class SessionTagResolver : ITagValueResolver
|
|||||||
var value = TagPreviewCatalog.KindOf(tag) == TagPreviewKind.Clock
|
var value = TagPreviewCatalog.KindOf(tag) == TagPreviewKind.Clock
|
||||||
? TagPreviewCatalog.FromClock(tag, ready.Minute12)
|
? TagPreviewCatalog.FromClock(tag, ready.Minute12)
|
||||||
: TagPreviewCatalog.FromUser(tag, ready.UidCod, ready.UidNam,
|
: TagPreviewCatalog.FromUser(tag, ready.UidCod, ready.UidNam,
|
||||||
ready.MobilePhone, ready.OfficePhone);
|
ready.MobilePhone, ready.OfficePhone,
|
||||||
|
UserSession.Current.LicenseNumber, UserSession.Current.SpecialistNumber,
|
||||||
|
UserSession.Current.JobName, UserSession.Current.DepNam);
|
||||||
return value.Length > 0
|
return value.Length > 0
|
||||||
? new TagValue(true, value)
|
? new TagValue(true, value)
|
||||||
: new TagValue(false, ready.HasClock ? "이 계정에는 값이 비어 있습니다" : "값을 읽지 못했습니다");
|
: new TagValue(false, ready.HasClock ? "이 계정에는 값이 비어 있습니다" : "값을 읽지 못했습니다");
|
||||||
|
|||||||
Reference in New Issue
Block a user