[CLAUDE] PE: section Bang so sanh + rename demo email @solutions.com.vn
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m10s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m10s
PART A: Section 'Bang so sanh' (file tong ho so so sanh) User request: 'theo them cho thong tin ve Bang so sanh, cho dinh kem file so sanh tong len'. BE: - PurchaseEvaluationAttachmentPurpose.ComparisonTable = 4 (new enum value) Backend validator IsInEnum pass, khong can migration (int column). FE types (2 app): - PeAttachmentPurpose.ComparisonTable + Label '4: Bang so sanh'. FE PeDetailTabs: - Them section thu 4 'Bang so sanh (file tong)' sau 'Hang muc + Bao gia'. - Component GeneralAttachmentsSection: upload KHONG truyen supplierRowId (BE luu NULL) → purpose=ComparisonTable default. Filter attachments co supplierRowId===null de render. - Card layout khac SupplierAttachmentsCell: full-width card + brand color + purpose chip + date. Upload button to hon ([+ Tai len bang so sanh]). - readOnly hide upload + delete, giu download. PART B: Demo email rebrand @solutionerp.local → @solutions.com.vn User request: 'tao nguoi dung demo theo email cua ben nay'. BE DbInitializer: - Rename 18 email in source: AdminEmail const + 17 demo users (bod/pm/ccm/pro/fin/act/equ/hra/qs/nv) — keep password + role unchanged. - Them BackfillUserEmailDomainAsync (idempotent): scan user co email @solutionerp.local, rename sang @solutions.com.vn, update Email + NormalizedEmail + UserName + NormalizedUserName. Skip neu co conflict user da ton tai voi email moi. Chay truoc SeedAdmin de tranh tao duplicate admin. Admin permission tao user da co san qua /system/users page. Comment input khi duyet da co san o PeWorkflowPanel (Ghi chu tuy chon Textarea) + ContractDetailContent (Yeu cau sua / Duyet tiep dialog).
This commit is contained in:
@ -14,9 +14,39 @@ namespace SolutionErp.Infrastructure.Persistence;
|
||||
|
||||
public static class DbInitializer
|
||||
{
|
||||
public const string AdminEmail = "admin@solutionerp.local";
|
||||
public const string AdminEmail = "admin@solutions.com.vn";
|
||||
public const string AdminPassword = "Admin@123456";
|
||||
|
||||
// Migration helper (Phase 6 rebrand): rename user email
|
||||
// @solutionerp.local → @solutions.com.vn. Idempotent — skip user đã rename.
|
||||
// Password + role + refresh token giữ nguyên. Chạy trước SeedAdmin.
|
||||
private static async Task BackfillUserEmailDomainAsync(
|
||||
UserManager<User> userManager, ILogger logger)
|
||||
{
|
||||
const string OldDomain = "@solutionerp.local";
|
||||
const string NewDomain = "@solutions.com.vn";
|
||||
var oldUsers = userManager.Users
|
||||
.Where(u => u.Email != null && u.Email.EndsWith(OldDomain))
|
||||
.ToList();
|
||||
if (oldUsers.Count == 0) return;
|
||||
|
||||
var renamed = 0;
|
||||
foreach (var u in oldUsers)
|
||||
{
|
||||
var newEmail = u.Email!.Replace(OldDomain, NewDomain);
|
||||
var conflict = await userManager.FindByEmailAsync(newEmail);
|
||||
if (conflict != null && conflict.Id != u.Id) continue;
|
||||
u.Email = newEmail;
|
||||
u.NormalizedEmail = newEmail.ToUpperInvariant();
|
||||
u.UserName = newEmail;
|
||||
u.NormalizedUserName = newEmail.ToUpperInvariant();
|
||||
var res = await userManager.UpdateAsync(u);
|
||||
if (res.Succeeded) renamed++;
|
||||
}
|
||||
if (renamed > 0)
|
||||
logger.LogInformation("Backfilled {Count} user emails -> @solutions.com.vn", renamed);
|
||||
}
|
||||
|
||||
public static async Task InitializeAsync(IServiceProvider services)
|
||||
{
|
||||
using var scope = services.CreateScope();
|
||||
@ -30,6 +60,9 @@ public static class DbInitializer
|
||||
await db.Database.MigrateAsync();
|
||||
|
||||
await SeedRolesAsync(roleManager, logger);
|
||||
// Phase 6 rebrand: rename user email @solutionerp.local → @solutions.com.vn
|
||||
// TRƯỚC SeedAdmin để SeedAdmin tìm theo new email thấy user đã rename → skip create.
|
||||
await BackfillUserEmailDomainAsync(userManager, logger);
|
||||
await SeedAdminAsync(userManager, logger);
|
||||
await SeedDepartmentsAsync(db, logger);
|
||||
await SeedDemoUsersAsync(db, userManager, logger);
|
||||
@ -452,10 +485,10 @@ public static class DbInitializer
|
||||
var fallbackSupplier = suppliersByCode.Values.First();
|
||||
var fallbackProject = projectsByCode.Values.First();
|
||||
|
||||
var qsHoang = await userManager.FindByEmailAsync("qs.hoang@solutionerp.local");
|
||||
var ccmTran = await userManager.FindByEmailAsync("ccm.tran@solutionerp.local");
|
||||
var bodHuynh = await userManager.FindByEmailAsync("bod.huynh@solutionerp.local");
|
||||
var hraDang = await userManager.FindByEmailAsync("hra.dang@solutionerp.local");
|
||||
var qsHoang = await userManager.FindByEmailAsync("qs.hoang@solutions.com.vn");
|
||||
var ccmTran = await userManager.FindByEmailAsync("ccm.tran@solutions.com.vn");
|
||||
var bodHuynh = await userManager.FindByEmailAsync("bod.huynh@solutions.com.vn");
|
||||
var hraDang = await userManager.FindByEmailAsync("hra.dang@solutions.com.vn");
|
||||
var qsDeptId = (await db.Departments.FirstOrDefaultAsync(d => d.Code == "QS"))?.Id;
|
||||
var nowUtc = DateTime.UtcNow;
|
||||
|
||||
@ -704,11 +737,11 @@ public static class DbInitializer
|
||||
}
|
||||
|
||||
// Lookup actor users (per role)
|
||||
var qsHoang = await userManager.FindByEmailAsync("qs.hoang@solutionerp.local");
|
||||
var proPham = await userManager.FindByEmailAsync("pro.pham@solutionerp.local");
|
||||
var ccmTran = await userManager.FindByEmailAsync("ccm.tran@solutionerp.local");
|
||||
var pmNguyen = await userManager.FindByEmailAsync("pm.nguyen@solutionerp.local");
|
||||
var bodHuynh = await userManager.FindByEmailAsync("bod.huynh@solutionerp.local");
|
||||
var qsHoang = await userManager.FindByEmailAsync("qs.hoang@solutions.com.vn");
|
||||
var proPham = await userManager.FindByEmailAsync("pro.pham@solutions.com.vn");
|
||||
var ccmTran = await userManager.FindByEmailAsync("ccm.tran@solutions.com.vn");
|
||||
var pmNguyen = await userManager.FindByEmailAsync("pm.nguyen@solutions.com.vn");
|
||||
var bodHuynh = await userManager.FindByEmailAsync("bod.huynh@solutions.com.vn");
|
||||
var qsDeptId = (await db.Departments.FirstOrDefaultAsync(d => d.Code == "QS"))?.Id;
|
||||
var nowUtc = DateTime.UtcNow;
|
||||
|
||||
@ -1101,28 +1134,28 @@ public static class DbInitializer
|
||||
{
|
||||
// (Email, FullName, DeptCode, Position, RoleNames[])
|
||||
// BOD (3) — director + signer + admin assistant
|
||||
("bod.huynh@solutionerp.local", "Huỳnh Văn Hùng", "BOD", "Tổng Giám đốc", new[] { AppRoles.Director }),
|
||||
("bod.le@solutionerp.local", "Lê Thị Mai", "BOD", "Phó Giám đốc (NĐUQ)", new[] { AppRoles.AuthorizedSigner }),
|
||||
("bod.tran@solutionerp.local", "Trần Quốc Bảo", "BOD", "Phó Giám đốc Kỹ thuật (NĐUQ)", new[] { AppRoles.AuthorizedSigner }),
|
||||
("bod.huynh@solutions.com.vn", "Huỳnh Văn Hùng", "BOD", "Tổng Giám đốc", new[] { AppRoles.Director }),
|
||||
("bod.le@solutions.com.vn", "Lê Thị Mai", "BOD", "Phó Giám đốc (NĐUQ)", new[] { AppRoles.AuthorizedSigner }),
|
||||
("bod.tran@solutions.com.vn", "Trần Quốc Bảo", "BOD", "Phó Giám đốc Kỹ thuật (NĐUQ)", new[] { AppRoles.AuthorizedSigner }),
|
||||
|
||||
// PM (2) — giám đốc dự án
|
||||
("pm.nguyen@solutionerp.local", "Nguyễn Quốc Cường", "PM", "Giám đốc Dự án FLOCK 01", new[] { AppRoles.ProjectManager }),
|
||||
("pm.le@solutionerp.local", "Lê Thanh Tùng", "PM", "Giám đốc Dự án Vinhomes Ocean Park", new[] { AppRoles.ProjectManager }),
|
||||
("pm.nguyen@solutions.com.vn", "Nguyễn Quốc Cường", "PM", "Giám đốc Dự án FLOCK 01", new[] { AppRoles.ProjectManager }),
|
||||
("pm.le@solutions.com.vn", "Lê Thanh Tùng", "PM", "Giám đốc Dự án Vinhomes Ocean Park", new[] { AppRoles.ProjectManager }),
|
||||
|
||||
// CCM/PRO/FIN/ACT/EQU/HRA — Trưởng phòng các phòng ban (1 mỗi)
|
||||
("ccm.tran@solutionerp.local", "Trần Văn Bình", "CCM", "Trưởng phòng Kiểm soát chi phí", new[] { AppRoles.CostControl, AppRoles.DeptManager }),
|
||||
("pro.pham@solutionerp.local", "Phạm Thị Hồng", "PRO", "Trưởng phòng Cung ứng", new[] { AppRoles.Procurement, AppRoles.DeptManager }),
|
||||
("fin.do@solutionerp.local", "Đỗ Minh Tuấn", "FIN", "Trưởng phòng Tài chính", new[] { AppRoles.Finance, AppRoles.DeptManager }),
|
||||
("act.vu@solutionerp.local", "Vũ Thị Lan", "ACT", "Kế toán trưởng", new[] { AppRoles.Accounting, AppRoles.DeptManager }),
|
||||
("equ.bui@solutionerp.local", "Bùi Văn Khánh", "EQU", "Trưởng phòng Thiết bị", new[] { AppRoles.Equipment, AppRoles.DeptManager }),
|
||||
("hra.dang@solutionerp.local", "Đặng Thị Thanh", "HRA", "Trưởng phòng Nhân sự - Hành chính", new[] { AppRoles.HrAdmin, AppRoles.DeptManager }),
|
||||
("ccm.tran@solutions.com.vn", "Trần Văn Bình", "CCM", "Trưởng phòng Kiểm soát chi phí", new[] { AppRoles.CostControl, AppRoles.DeptManager }),
|
||||
("pro.pham@solutions.com.vn", "Phạm Thị Hồng", "PRO", "Trưởng phòng Cung ứng", new[] { AppRoles.Procurement, AppRoles.DeptManager }),
|
||||
("fin.do@solutions.com.vn", "Đỗ Minh Tuấn", "FIN", "Trưởng phòng Tài chính", new[] { AppRoles.Finance, AppRoles.DeptManager }),
|
||||
("act.vu@solutions.com.vn", "Vũ Thị Lan", "ACT", "Kế toán trưởng", new[] { AppRoles.Accounting, AppRoles.DeptManager }),
|
||||
("equ.bui@solutions.com.vn", "Bùi Văn Khánh", "EQU", "Trưởng phòng Thiết bị", new[] { AppRoles.Equipment, AppRoles.DeptManager }),
|
||||
("hra.dang@solutions.com.vn", "Đặng Thị Thanh", "HRA", "Trưởng phòng Nhân sự - Hành chính", new[] { AppRoles.HrAdmin, AppRoles.DeptManager }),
|
||||
|
||||
// Drafter (5) — soạn thảo HĐ ở các phòng khác nhau
|
||||
("qs.hoang@solutionerp.local", "Hoàng Văn Đức", "QS", "QS công trường — soạn thảo HĐ", new[] { AppRoles.Drafter }),
|
||||
("qs.ngo@solutionerp.local", "Ngô Thị Hà", "QS", "QS dự án FLOCK 01", new[] { AppRoles.Drafter }),
|
||||
("nv.cao@solutionerp.local", "Cao Văn Long", "PRO", "Nhân viên Cung ứng", new[] { AppRoles.Drafter }),
|
||||
("nv.dinh@solutionerp.local", "Đinh Thị Yến", "FIN", "Nhân viên Tài chính", new[] { AppRoles.Drafter }),
|
||||
("nv.truong@solutionerp.local", "Trương Minh Quân", "CCM", "Nhân viên Kiểm soát chi phí", new[] { AppRoles.Drafter }),
|
||||
("qs.hoang@solutions.com.vn", "Hoàng Văn Đức", "QS", "QS công trường — soạn thảo HĐ", new[] { AppRoles.Drafter }),
|
||||
("qs.ngo@solutions.com.vn", "Ngô Thị Hà", "QS", "QS dự án FLOCK 01", new[] { AppRoles.Drafter }),
|
||||
("nv.cao@solutions.com.vn", "Cao Văn Long", "PRO", "Nhân viên Cung ứng", new[] { AppRoles.Drafter }),
|
||||
("nv.dinh@solutions.com.vn", "Đinh Thị Yến", "FIN", "Nhân viên Tài chính", new[] { AppRoles.Drafter }),
|
||||
("nv.truong@solutions.com.vn", "Trương Minh Quân", "CCM", "Nhân viên Kiểm soát chi phí", new[] { AppRoles.Drafter }),
|
||||
};
|
||||
|
||||
int created = 0, fixedExisting = 0, failed = 0;
|
||||
|
||||
Reference in New Issue
Block a user