[CLAUDE] PurchaseEvaluation: Plan AE — fix Changelog UserName 9 sites (Budget Adjust + 8 preventive)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m25s

Bro UAT 2026-05-19 post-S25 Plan AD: "Điều chỉnh ngân sách" entry trong
Lịch sử thay đổi show "Hệ thống" thay vì tên user thật (Phan Văn Chương /
NV CCM). Audit phát hiện systemic bug — 9 Changelog.Add sites trong PE
features MISSING UserName field, FE fallback "Hệ thống" toàn bộ.

Fix Plan AE — preventive batch (8 sites khác chắc chắn bro sẽ phát hiện sau):

PurchaseEvaluationFeatures.cs (4 sites):
- line 120 Tạo phiếu
- line 149 Hạng mục mặc định
- line 228 Cập nhật thông tin phiếu (UpdateDraft)
- line 379 Điều chỉnh ngân sách (Budget Adjust) — bro feedback chính

PurchaseEvaluationDetailFeatures.cs (5 sites):
- line 167 Thêm hạng mục (Detail Insert)
- line 225 Cập nhật hạng mục (Detail Update)
- line 257 Xóa hạng mục (Detail Delete)
- line 317 Cập nhật báo giá (Quote Update — inside if block, 16-space indent)
- line 342 Thêm báo giá (Quote Insert)
- line 377 Xóa báo giá (Quote Delete)
- line 416 Chọn NCC trúng thầu (Select Winner)

Pattern: `UserName = currentUser.FullName ?? currentUser.Email` — ICurrentUser
đã có FullName + Email từ JWT claims, KHÔNG cần inject userManager mới.

Verify:
- dotnet build clean 0 err 2 warn (pre-existing DocxRenderer)
- dotnet test 111/111 PASS

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-05-19 12:32:53 +07:00
parent 0aaf2df04a
commit 9ea62be6a7
2 changed files with 13 additions and 0 deletions

View File

@ -165,6 +165,7 @@ public class AddPurchaseEvaluationDetailCommandHandler(
Action = ChangelogAction.Insert, Action = ChangelogAction.Insert,
PhaseAtChange = evaluation.Phase, PhaseAtChange = evaluation.Phase,
UserId = currentUser.UserId, UserId = currentUser.UserId,
UserName = currentUser.FullName ?? currentUser.Email,
Summary = $"Thêm hạng mục {request.GroupCode} — {request.NoiDung}", Summary = $"Thêm hạng mục {request.GroupCode} — {request.NoiDung}",
}); });
@ -222,6 +223,7 @@ public class UpdatePurchaseEvaluationDetailCommandHandler(
Action = ChangelogAction.Update, Action = ChangelogAction.Update,
PhaseAtChange = evaluation.Phase, PhaseAtChange = evaluation.Phase,
UserId = currentUser.UserId, UserId = currentUser.UserId,
UserName = currentUser.FullName ?? currentUser.Email,
Summary = $"Cập nhật hạng mục {request.GroupCode} — {request.NoiDung}{approverNote}", Summary = $"Cập nhật hạng mục {request.GroupCode} — {request.NoiDung}{approverNote}",
}); });
@ -253,6 +255,7 @@ public class DeletePurchaseEvaluationDetailCommandHandler(
Action = ChangelogAction.Delete, Action = ChangelogAction.Delete,
PhaseAtChange = evaluation.Phase, PhaseAtChange = evaluation.Phase,
UserId = currentUser.UserId, UserId = currentUser.UserId,
UserName = currentUser.FullName ?? currentUser.Email,
Summary = $"Xóa hạng mục {entity.GroupCode} — {entity.NoiDung}{approverNote}", Summary = $"Xóa hạng mục {entity.GroupCode} — {entity.NoiDung}{approverNote}",
}); });
@ -312,6 +315,7 @@ public class UpsertPurchaseEvaluationQuoteCommandHandler(
Action = ChangelogAction.Update, Action = ChangelogAction.Update,
PhaseAtChange = evaluation.Phase, PhaseAtChange = evaluation.Phase,
UserId = currentUser.UserId, UserId = currentUser.UserId,
UserName = currentUser.FullName ?? currentUser.Email,
Summary = $"Cập nhật báo giá cho hạng mục {detail.GroupCode}{approverNote}", Summary = $"Cập nhật báo giá cho hạng mục {detail.GroupCode}{approverNote}",
}); });
await db.SaveChangesAsync(ct); await db.SaveChangesAsync(ct);
@ -337,6 +341,7 @@ public class UpsertPurchaseEvaluationQuoteCommandHandler(
Action = ChangelogAction.Insert, Action = ChangelogAction.Insert,
PhaseAtChange = evaluation.Phase, PhaseAtChange = evaluation.Phase,
UserId = currentUser.UserId, UserId = currentUser.UserId,
UserName = currentUser.FullName ?? currentUser.Email,
Summary = $"Thêm báo giá cho hạng mục {detail.GroupCode}{approverNote}", Summary = $"Thêm báo giá cho hạng mục {detail.GroupCode}{approverNote}",
}); });
await db.SaveChangesAsync(ct); await db.SaveChangesAsync(ct);
@ -371,6 +376,7 @@ public class DeletePurchaseEvaluationQuoteCommandHandler(
Action = ChangelogAction.Delete, Action = ChangelogAction.Delete,
PhaseAtChange = evaluation.Phase, PhaseAtChange = evaluation.Phase,
UserId = currentUser.UserId, UserId = currentUser.UserId,
UserName = currentUser.FullName ?? currentUser.Email,
Summary = $"Xóa báo giá{approverNote}", Summary = $"Xóa báo giá{approverNote}",
}); });
@ -409,6 +415,7 @@ public class SelectPurchaseEvaluationWinnerCommandHandler(
Action = ChangelogAction.Update, Action = ChangelogAction.Update,
PhaseAtChange = entity.Phase, PhaseAtChange = entity.Phase,
UserId = currentUser.UserId, UserId = currentUser.UserId,
UserName = currentUser.FullName ?? currentUser.Email,
Summary = "Chọn NCC trúng thầu", Summary = "Chọn NCC trúng thầu",
}); });

View File

@ -124,6 +124,7 @@ public class CreatePurchaseEvaluationCommandHandler(
Action = ChangelogAction.Insert, Action = ChangelogAction.Insert,
PhaseAtChange = entity.Phase, PhaseAtChange = entity.Phase,
UserId = currentUser.UserId, UserId = currentUser.UserId,
UserName = currentUser.FullName ?? currentUser.Email,
Summary = $"Tạo phiếu {entity.MaPhieu} — {entity.TenGoiThau}", Summary = $"Tạo phiếu {entity.MaPhieu} — {entity.TenGoiThau}",
}); });
@ -154,6 +155,7 @@ public class CreatePurchaseEvaluationCommandHandler(
Action = ChangelogAction.Insert, Action = ChangelogAction.Insert,
PhaseAtChange = entity.Phase, PhaseAtChange = entity.Phase,
UserId = currentUser.UserId, UserId = currentUser.UserId,
UserName = currentUser.FullName ?? currentUser.Email,
Summary = $"Hạng mục mặc định — {defaultDetail.NoiDung}", Summary = $"Hạng mục mặc định — {defaultDetail.NoiDung}",
}); });
@ -232,6 +234,7 @@ public class UpdatePurchaseEvaluationDraftCommandHandler(
Action = ChangelogAction.Update, Action = ChangelogAction.Update,
PhaseAtChange = entity.Phase, PhaseAtChange = entity.Phase,
UserId = currentUser.UserId, UserId = currentUser.UserId,
UserName = currentUser.FullName ?? currentUser.Email,
Summary = "Cập nhật thông tin phiếu", Summary = "Cập nhật thông tin phiếu",
}); });
@ -376,6 +379,8 @@ public class AdjustPurchaseEvaluationBudgetCommandHandler(
} }
var diffSummary = parts.Count == 0 ? "không đổi" : string.Join(", ", parts); var diffSummary = parts.Count == 0 ? "không đổi" : string.Join(", ", parts);
// Plan AE S25 — set UserName để FE hiện đúng tên user thay vì "Hệ thống"
// fallback. ICurrentUser đã có FullName + Email sẵn từ JWT claims.
db.PurchaseEvaluationChangelogs.Add(new PurchaseEvaluationChangelog db.PurchaseEvaluationChangelogs.Add(new PurchaseEvaluationChangelog
{ {
PurchaseEvaluationId = entity.Id, PurchaseEvaluationId = entity.Id,
@ -383,6 +388,7 @@ public class AdjustPurchaseEvaluationBudgetCommandHandler(
Action = ChangelogAction.Update, Action = ChangelogAction.Update,
PhaseAtChange = entity.Phase, PhaseAtChange = entity.Phase,
UserId = currentUser.UserId, UserId = currentUser.UserId,
UserName = currentUser.FullName ?? currentUser.Email,
Summary = $"Điều chỉnh ngân sách: {diffSummary} {actorTag}", Summary = $"Điều chỉnh ngân sách: {diffSummary} {actorTag}",
}); });