[CLAUDE] Contract: K7 SP-002 bridge KHKK->HD hoi-2-khoa + Line.ContractId + grant seeder (gate PASS-WITH-FLAGS 10, F-8 fixed)
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Has been cancelled
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Has been cancelled
BE: POST {id}/create-contract (Contracts.Create AND KeHoachKyKet.Read) + guard 4-ve IsActive/IsUserSelectable
+ Line.ContractId write-site DAU TIEN + list-DTO ContractIds + SeedContractCreateAccessAsync (Drafter/
Procurement/Admin upgrade-only, cau III default cho ratify). FE x2 app SHA-pair 3/3: nut bridge gate 2-khoa
+ dialog khuon-san + cay GD3/GD4 doc TAP contractIds (union pe.contractId legacy). Test +17 (12 bridge T1-T12
+ 5 authz) suite 639/0; ngoai-le CreateContract trong AuthorizePolicyRegressionTests (#85).
Gate F-8 fixed truoc commit: neo so-dong :2516 chet-luc-land -> neo ten ham (3 cho) + 13/13->12/13 theo do
prod + khai chu-dich CanRead + sua tro-nham-ham. No mang theo (0-blocker): MAJOR-race-2-request-dong-thoi
(chong-trung in-memory, phuong an unique/RowVersion = nhip sau) + DraftData-khong-carry + a11y/O(n.m) FE.
UAT-NOI-TRUOC: nut sang sau restart + user RE-LOGIN (menu cache); acceptance seeder log = 0 added + 2 upgraded.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@ -2353,6 +2353,14 @@ public static class DbInitializer
|
||||
// @S159 ⇒ nhánh insert skip-existing = NO-OP im lặng ⇒ 403 giết dry-run (gotcha #44).
|
||||
await SeedKeHoachKyKetAccessAsync(db, roleManager, logger);
|
||||
|
||||
// [K7 — S167 2026-08-01] Cầu GĐ2 → GĐ3 golive: cấp `Contracts.Create` cho Drafter +
|
||||
// Procurement + Admin (câu III default — chờ anh ratify, đổi bộ vai TRONG method).
|
||||
// CHẠY SAU revoke cùng lý do 2 seeder trên. Không có nó thì nút "Đưa vào Hợp đồng"
|
||||
// 403 với 12/13 role (`SeedAllRolesReviewReadPermissionsAsync` để CanCreate=false cho key
|
||||
// `Contracts`; Admin qua nhờ bypass + prod sẵn row CanCreate=True — đo @gate-K7) —
|
||||
// nghiệm thu = restart THẬT rồi đếm row, không đọc code (#75/#76).
|
||||
await SeedContractCreateAccessAsync(db, roleManager, logger);
|
||||
|
||||
// [S65 2026-06-16] CHẠY SAU revoke để THẮNG: mở lại quyền XEM "Hồ sơ Nhân sự"
|
||||
// (+ root nhóm "Nhân sự") cho MỌI role — anh chốt public module Nhân sự cho
|
||||
// user thường tra cứu hồ sơ. Dashboard NS (Hrm_Dashboard) + 6 catalog
|
||||
@ -2728,6 +2736,88 @@ public static class DbInitializer
|
||||
}
|
||||
}
|
||||
|
||||
// [K7 — S167 2026-08-01] Cấp `Contracts.Create` cho các vai được bấm "Đưa vào Hợp đồng"
|
||||
// (cầu GĐ2 → GĐ3, `ContractSigningPlansController` `POST {id}/create-contract`).
|
||||
//
|
||||
// 🔴 LÝ DO PHẢI CÓ HÀM NÀY: trước S167 **KHÔNG role nào** mang `Contracts.Create` —
|
||||
// `SeedAllRolesReviewReadPermissionsAsync` (grep tên hàm, đừng neo số dòng) tạo row key
|
||||
// `Contracts` với `CanCreate = isPe` mà `isPe` = false cho key này ⇒ nút bridge 403 với
|
||||
// 12/13 role (kể cả Drafter); Admin qua nhờ bypass và prod ĐÃ sẵn row CanCreate=True cho
|
||||
// Admin (đo prod @gate-K7). Đây là lỗ ĐO ĐƯỢC, không phải suy đoán.
|
||||
// CanRead nâng KÈM là CHỦ ĐÍCH, không phải tràn-nhãn: vai được tạo HĐ phải THẤY menu
|
||||
// "Hợp đồng" để mở HĐ vừa tạo từ cầu KHKK — CanRead là cờ hiển thị menu (2-tầng #82).
|
||||
//
|
||||
// ⏳ [K7 — câu III default, chờ anh ratify] Bộ vai = Drafter + Procurement + Admin
|
||||
// ("người có quyền tạo HĐ"): Drafter = người soạn HĐ, Procurement = Mua hàng chủ trì cầu
|
||||
// NCC, Admin = quản trị/UAT. Anh chốt khác thì SỬA ĐÚNG mảng `roleNames` dưới đây (1 chỗ),
|
||||
// KHÔNG đụng controller — máy BE không đổi theo câu trả lời, chỉ đổi ai thấy nút.
|
||||
//
|
||||
// Khuôn = `SeedKeHoachKyKetAccessAsync` (W1 S161): UPGRADE-ONLY (row có sẵn → NÂNG cờ
|
||||
// desired, KHÔNG hạ cờ nào, KHÔNG đụng Update/Delete), row chưa có (fresh DB) → tạo
|
||||
// Read+Create. CẤM SQL tay (#84): grant tay bị seeder/revoker lật ở restart kế (bài S159
|
||||
// Run #423 — 447/494 row rơi). Chạy SAU `RevokeTemporarilyHiddenModulesAsync` để thắng
|
||||
// revoke (revoker hiện KHÔNG còn nhánh `Contracts` từ S159, nhưng giữ thứ tự cho an toàn).
|
||||
// Thu hồi khi cần: xoá call trong `SeedAdminPermissionsAsync` (gate-K7 bắt bản đầu trỏ nhầm SeedAsync).
|
||||
private static async Task SeedContractCreateAccessAsync(
|
||||
ApplicationDbContext db, RoleManager<Role> roleManager, ILogger logger)
|
||||
{
|
||||
// CHỈ key root `Contracts` — đó là key mà policy `Contracts.Create` của endpoint đọc
|
||||
// (`MenuPermissionHandler` so khớp CHÍNH XÁC 1 key, KHÔNG kế thừa xuống `Ct_*`).
|
||||
// Cấp thêm cho `Ct_*` là cấp thừa: không endpoint nào gate bằng key con đó.
|
||||
const string key = MenuKeys.Contracts;
|
||||
var roleNames = new[] { AppRoles.Drafter, AppRoles.Procurement, AppRoles.Admin };
|
||||
|
||||
var roles = await roleManager.Roles
|
||||
.Where(r => r.Name != null && roleNames.Contains(r.Name))
|
||||
.ToListAsync();
|
||||
if (roles.Count == 0)
|
||||
{
|
||||
logger.LogWarning("SeedContractCreateAccessAsync: skip — chưa seed role nào trong {Roles}.",
|
||||
string.Join("/", roleNames));
|
||||
return;
|
||||
}
|
||||
|
||||
var roleIds = roles.Select(r => r.Id).ToList();
|
||||
var existing = (await db.Permissions
|
||||
.Where(p => p.MenuKey == key && roleIds.Contains(p.RoleId))
|
||||
.ToListAsync())
|
||||
.ToDictionary(p => p.RoleId);
|
||||
|
||||
var added = 0;
|
||||
var upgraded = 0;
|
||||
foreach (var role in roles)
|
||||
{
|
||||
if (existing.TryGetValue(role.Id, out var row))
|
||||
{
|
||||
var changed = false;
|
||||
if (!row.CanRead) { row.CanRead = true; changed = true; }
|
||||
if (!row.CanCreate) { row.CanCreate = true; changed = true; }
|
||||
if (changed) upgraded++;
|
||||
continue;
|
||||
}
|
||||
|
||||
db.Permissions.Add(new Permission
|
||||
{
|
||||
RoleId = role.Id,
|
||||
MenuKey = key,
|
||||
CanRead = true,
|
||||
CanCreate = true,
|
||||
CanUpdate = false,
|
||||
CanDelete = false,
|
||||
});
|
||||
added++;
|
||||
}
|
||||
|
||||
if (added > 0 || upgraded > 0)
|
||||
{
|
||||
await db.SaveChangesAsync();
|
||||
logger.LogInformation(
|
||||
"Seeded Contracts.Create access: {Added} added + {Upgraded} upgraded " +
|
||||
"(K7 cầu KHKK→HĐ — {Roles}; câu III default chờ ratify)",
|
||||
added, upgraded, string.Join("/", roleNames));
|
||||
}
|
||||
}
|
||||
|
||||
// [S65 2026-06-16] Mở quyền XEM (Read-only) "Hồ sơ Nhân sự" cho MỌI role: anh chốt
|
||||
// public module Nhân sự (trọng tâm Hồ sơ NS) để user thường tra cứu hồ sơ nhân sự.
|
||||
// CHẠY SAU RevokeTemporarilyHiddenModulesAsync (SeedAsync) để THẮNG revoke: revoke
|
||||
|
||||
Reference in New Issue
Block a user