From 9dee00da01e1cd68c3e76a2bcb31dca310c0c291 Mon Sep 17 00:00:00 2001 From: pqhuy1987 Date: Mon, 11 May 2026 09:54:12 +0700 Subject: [PATCH] =?UTF-8?q?[CLAUDE]=20PurchaseEvaluation:=20Chunk=20A=20?= =?UTF-8?q?=E2=80=94=20reorder=20section=20H=E1=BA=A1ng=20m=E1=BB=A5c=20l?= =?UTF-8?q?=C3=AAn=20#2=20+=20auto-t=E1=BA=A1o=201=20row=20m=E1=BA=B7c=20?= =?UTF-8?q?=C4=91=E1=BB=8Bnh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Session 20 UI restructure (3 yêu cầu user). Chunk A xử lý: BE — CreatePurchaseEvaluationCommandHandler thêm 1 PurchaseEvaluationDetail mặc định khi tạo phiếu mới: - GroupCode="01", GroupName="Hạng mục chính" - NoiDung = TenGoiThau (tên gói thầu) - DonGiaNganSach = ThanhTienNganSach = Budget.TongNganSach (nếu link) fallback BudgetManualAmount fallback 0 - DonViTinh="gói", KL=1, Order=1 - Changelog entry kèm theo (audit Insert Detail) FE — Đổi thứ tự 5 section trong PeDetailTabs.tsx (mirror 2 app): 1. Thông tin gói thầu (giữ) 2. Hạng mục + Báo giá (chuyển từ #4 lên #2) 3. Chọn NCC / TP (từ #2 xuống #3) 4. NCC / TP tham gia (từ #3 xuống #4 — Chunk B sẽ gộp vào #2 nested) 5. Ý kiến cấp duyệt (giữ) Q1=a: Giữ Section "Chọn NCC TP thắng thầu" riêng (rõ UX). Q2=a "1 hạng mục trước tiên": auto-seed đủ, multi-hạng-mục defer. Verify: - dotnet build SolutionErp.slnx — 0 warning / 0 error - Test pass mặc định skip (Phase 9 UAT iteration, Q4 user public luôn) Pending Chunk B: Nested grid Hạng mục → NCC expand inline edit Pending Chunk C: Section 5 gộp đồng cấp cùng Phòng (1 box / Step) Pending Chunk D: Docs S20 changelog + STATUS + HANDOFF Co-Authored-By: Claude Opus 4.7 (1M context) --- fe-admin/src/components/pe/PeDetailTabs.tsx | 15 +++++---- fe-user/src/components/pe/PeDetailTabs.tsx | 15 +++++---- .../PurchaseEvaluationFeatures.cs | 32 +++++++++++++++++++ 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/fe-admin/src/components/pe/PeDetailTabs.tsx b/fe-admin/src/components/pe/PeDetailTabs.tsx index dd753d5..2d1689e 100644 --- a/fe-admin/src/components/pe/PeDetailTabs.tsx +++ b/fe-admin/src/components/pe/PeDetailTabs.tsx @@ -161,19 +161,22 @@ export function PeDetailTabs({
- {/* Section 1 — đúng spec form FO-PHIẾU TRÌNH KÝ CHỌN TP/NCC */} + {/* Section order (Session 20): Hạng mục lên đầu sau Thông tin gói thầu. + BE auto-tạo 1 hạng mục mặc định (tên = TenGoiThau, giá trị = ngân sách) + khi Create. NCC tham gia tạm giữ riêng — Chunk B sẽ gộp NCC nested + expand dưới mỗi hạng mục. */}
-
+
+ +
+
-
+
-
- -
{mode === 'workspace' && (
diff --git a/fe-user/src/components/pe/PeDetailTabs.tsx b/fe-user/src/components/pe/PeDetailTabs.tsx index dd753d5..2d1689e 100644 --- a/fe-user/src/components/pe/PeDetailTabs.tsx +++ b/fe-user/src/components/pe/PeDetailTabs.tsx @@ -161,19 +161,22 @@ export function PeDetailTabs({
- {/* Section 1 — đúng spec form FO-PHIẾU TRÌNH KÝ CHỌN TP/NCC */} + {/* Section order (Session 20): Hạng mục lên đầu sau Thông tin gói thầu. + BE auto-tạo 1 hạng mục mặc định (tên = TenGoiThau, giá trị = ngân sách) + khi Create. NCC tham gia tạm giữ riêng — Chunk B sẽ gộp NCC nested + expand dưới mỗi hạng mục. */}
-
+
+ +
+
-
+
-
- -
{mode === 'workspace' && (
diff --git a/src/Backend/SolutionErp.Application/PurchaseEvaluations/PurchaseEvaluationFeatures.cs b/src/Backend/SolutionErp.Application/PurchaseEvaluations/PurchaseEvaluationFeatures.cs index 5381ef3..c37c4e1 100644 --- a/src/Backend/SolutionErp.Application/PurchaseEvaluations/PurchaseEvaluationFeatures.cs +++ b/src/Backend/SolutionErp.Application/PurchaseEvaluations/PurchaseEvaluationFeatures.cs @@ -77,6 +77,7 @@ public class CreatePurchaseEvaluationCommandHandler( // Validate Budget link (nếu có): cùng Project + Phase=DaDuyet (chỉ cho // pick ngân sách đã duyệt mới được dùng làm reference đối chiếu). + decimal? linkedBudgetTotal = null; if (request.BudgetId is Guid bid) { var bg = await db.Budgets.AsNoTracking() @@ -86,6 +87,7 @@ public class CreatePurchaseEvaluationCommandHandler( throw new ConflictException("Ngân sách phải cùng dự án với phiếu."); if (bg.Phase != Domain.Budgets.BudgetPhase.DaDuyet) throw new ConflictException("Chỉ link được ngân sách đã duyệt."); + linkedBudgetTotal = bg.TongNganSach; } var entity = new PurchaseEvaluation @@ -124,6 +126,36 @@ public class CreatePurchaseEvaluationCommandHandler( Summary = $"Tạo phiếu {entity.MaPhieu} — {entity.TenGoiThau}", }); + // Auto-seed 1 Hạng mục mặc định lấy tên + giá trị từ gói thầu / ngân sách + // — user yêu cầu Session 20: hạng mục là đơn vị làm việc chính, NCC expand + // dưới hạng mục → cần có sẵn 1 row khi vào Detail. Có thể edit lại sau. + var defaultBudgetValue = linkedBudgetTotal ?? request.BudgetManualAmount ?? 0m; + var defaultDetail = new PurchaseEvaluationDetail + { + PurchaseEvaluationId = entity.Id, + GroupCode = "01", + GroupName = "Hạng mục chính", + NoiDung = request.TenGoiThau, + DonViTinh = "gói", + KhoiLuongNganSach = 1m, + KhoiLuongThiCong = 1m, + DonGiaNganSach = defaultBudgetValue, + ThanhTienNganSach = defaultBudgetValue, + Order = 1, + }; + db.PurchaseEvaluationDetails.Add(defaultDetail); + + db.PurchaseEvaluationChangelogs.Add(new PurchaseEvaluationChangelog + { + PurchaseEvaluationId = entity.Id, + EntityType = PurchaseEvaluationEntityType.Detail, + EntityId = defaultDetail.Id, + Action = ChangelogAction.Insert, + PhaseAtChange = entity.Phase, + UserId = currentUser.UserId, + Summary = $"Hạng mục mặc định — {defaultDetail.NoiDung}", + }); + await db.SaveChangesAsync(ct); return entity.Id; }