'수정'을 되살린다 — 지금 쓰이는 버전을 제자리에서 고친다
레거시 TK_MODIFY('기록지 수정'). SheetMe 에는 저장만 있었고 이것이 없었다.
DbSmoke.cs:1072 가 그 부재를 이미 적어 뒀다 — 실측 ShtCneYon='Y' 40건, 현역 19건.
<b>먼저 내 앞선 설명을 고친다.</b> 나는 수정이 ShtCneYon 제자리 갱신 경로라고 했는데 틀렸다.
수정 경로는 ShtCneYon 을 <b>읽지도 않는다</b>. 그 컬럼은 저장이 버저닝이냐 제자리냐만 가른다.
저장과 수정은 이력 방향이 반대다.
저장: 옛 행을 SdgDelYon='Y' 로 내리고 <b>새 행이 활성</b>이 된다(SdgKey 바뀜)
수정: <b>활성 행을 제자리에서 갱신</b>하고 옛 XML 을 담은 새 행이 이력이 된다(SdgKey 유지)
SdgKey 가 유지되므로 EMR 이 참조하던 키가 그대로다 — 그게 이 동작의 존재 이유다.
E_SctMst 를 건드리지 않는다(레거시 :170-174 주석 처리). 그것이 "글자만 수정 가능"이라는
경고문의 기술적 근거다 — 기존 매핑 행은 SdgKey 가 그대로라 유효하지만 새 컨트롤은 행이 안 생긴다.
<b>레거시 버그 둘은 복제하지 않는다.</b>
① 감사 컬럼이 뒤집혀 있었다 — 활성 행에는 아무것도 안 쓰고 <b>옛 디자인을 담은 이력 행</b>이
현재 사용자·시각을 받았다(:162-163). 이력 패널이 "누가 언제 이 버전을 만들었는가"를 거꾸로 보여 준다.
활성 행에 기록하고 이력 행은 원래 값을 지킨다.
② Rows(0) 을 개수 검사보다 먼저 읽어 활성 행이 없으면 IndexOutOfRange 였다(:150).
먼저 확인하고 "수정 대신 저장을 쓰세요"로 안내한다.
<b>새 컨트롤은 막는다.</b> 레거시는 산문으로만 경고하고 막지 않았다 —
경고문을 읽지 않으면 그대로 번진다. SctMstXmlWalker 로 문서의 컨트롤 이름을 뽑아
활성 SdgKey 의 E_SctMst 행과 대조한다. 판정 근거를 저장이 행을 만드는 규칙과 같은 것으로 통일해서,
"행이 원래 안 생기는 종류"를 새 컨트롤로 오인하지 않는다.
<b>권한 게이트는 유지한다.</b> 레거시가 이 버튼만 전산실에 묶어 둔 이유가 위와 같다
(frmSheetDesigner.vb:1029-1060, 주석 '전산실만 사용가능'). 저장 버튼에는 그런 분기가 없다.
규칙을 Core 의 순수 함수로 옮겨 표로 고정했다 — 병원·부서 조합이 세 갈래라
화면에서 즉석 판정하면 어느 갈래가 왜 막혔는지 확인할 방법이 없다.
막힌 이유도 갈래마다 다르게 말한다("권한 없음"만으로는 누구에게 물어야 할지 모른다).
<b>HspStrDte 는 세션에 없다.</b> 레거시는 그 값으로 "2025-05-01 이후 개원 병원은 사내 계정만"을 가른다.
빈 문자열로 두면 그 갈래가 안 걸리고 부서 규칙(EDPS)으로 떨어진다 — 레거시의 다수 경로와 같다.
없는 값을 지어내 더 조이지 않고, 이 사실을 코드와 테스트에 적어 뒀다.
게이트: 테스트 298/298(신규 7), --edit-smoke 0실패, --dialog-shots FAIL 0 대조군 4/4,
--modal-check 0실패, --cleartype 11/11, --maxrect 0실패, --scale-budget 5/5, 빌드 경고 0,
--db-smoke 1271건 diff 0, --db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 동일.
<b>실DB 수정 경로는 아직 안 돌려 봤다</b> — 운영 테이블에 쓰는 동작이라 --db-* 진단으로
왕복 검증을 붙이는 것이 다음 일이다.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a386c5504b
commit
ae2f8f2f61
@@ -0,0 +1,66 @@
|
||||
namespace SheetMe.Core.Catalog;
|
||||
|
||||
/// <summary>
|
||||
/// '수정'(제자리 정정)을 누가 쓸 수 있는가 — 레거시 <c>TK_MODIFY</c> 가시성 규칙을 옮긴 것.
|
||||
///
|
||||
/// <b>왜 저장과 다른가.</b> 수정은 활성 <c>SdgKey</c> 를 그대로 두고 그 행의 디자인만 바꾼다.
|
||||
/// EMR 이 참조하던 키가 유지되므로 <b>되돌릴 표식이 남지 않는 쓰기</b>에 가깝고,
|
||||
/// <c>E_SctMst</c> 를 건드리지 않아 새 컨트롤은 매핑 행이 생기지 않는다.
|
||||
/// 레거시가 이 버튼만 전산실에 묶어 둔 이유가 그것이다
|
||||
/// (<c>frmSheetDesigner.vb:1029-1060</c>, 주석 <c>'[추가] 박성한 20150302 전산실만 사용가능</c>).
|
||||
/// 저장 버튼에는 이런 분기가 없다.
|
||||
///
|
||||
/// 규칙을 여기 순수 함수로 두는 이유: 병원 코드·부서 코드 조합이 세 갈래라 화면에서 즉석 판정하면
|
||||
/// 어느 갈래가 왜 막혔는지 확인할 방법이 없다. 여기라면 표로 고정할 수 있다.
|
||||
/// </summary>
|
||||
public static class ModifyPolicy
|
||||
{
|
||||
#region Member Fields
|
||||
/// <summary>이 두 병원은 전산실 외에 총무·구매 부서도 쓴다(레거시 :1033-1038)</summary>
|
||||
private static readonly string[] WideHospitals = { "HANKOOK", "GNRH" };
|
||||
|
||||
private static readonly string[] WideDepartments = { "EDPS", "SALO", "SAVE" };
|
||||
|
||||
/// <summary>이 날짜 이후 개원한 병원은 사내 계정만(레거시 :1042-1048)</summary>
|
||||
private const string VendorOnlyFrom = "20250501";
|
||||
|
||||
private const string VendorUid = "MSYS";
|
||||
|
||||
private const string ItDepartment = "EDPS";
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
/// <summary>
|
||||
/// 이 사용자가 '수정'을 쓸 수 있는가.
|
||||
/// <paramref name="hospitalStartDate"/> 는 <c>HspStrDte</c>(YYYYMMDD) — 모르면 빈 문자열.
|
||||
/// </summary>
|
||||
public static bool CanModify(string hospitalCode, string departmentCode, string uidCod,
|
||||
string hospitalStartDate)
|
||||
{
|
||||
if (Array.Exists(WideHospitals, h => string.Equals(h, hospitalCode, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return Array.Exists(WideDepartments,
|
||||
d => string.Equals(d, departmentCode, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
if (string.CompareOrdinal(hospitalStartDate, VendorOnlyFrom) >= 0)
|
||||
{
|
||||
return string.Equals(uidCod, VendorUid, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
return string.Equals(departmentCode, ItDepartment, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>왜 막혔는지 — 화면이 "권한이 없습니다"만 말하면 누구에게 물어야 할지 모른다</summary>
|
||||
public static string DenyReason(string hospitalCode, string uidCod, string hospitalStartDate)
|
||||
{
|
||||
if (Array.Exists(WideHospitals, h => string.Equals(h, hospitalCode, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return "이 병원에서는 전산실·총무·구매 부서만 수정할 수 있습니다.";
|
||||
}
|
||||
if (string.CompareOrdinal(hospitalStartDate, VendorOnlyFrom) >= 0)
|
||||
{
|
||||
return $"이 병원에서는 {VendorUid} 계정만 수정할 수 있습니다.";
|
||||
}
|
||||
return "전산실 소속만 수정할 수 있습니다.";
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user