[CLAUDE] PurchaseEvaluation: Chunk A — reorder section Hạng mục lên #2 + auto-tạo 1 row mặc định
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m20s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m20s
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) <noreply@anthropic.com>
This commit is contained in:
@ -161,19 +161,22 @@ export function PeDetailTabs({
|
||||
</div>
|
||||
|
||||
<div className="divide-y divide-slate-200">
|
||||
{/* 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. */}
|
||||
<Section title="1. Thông tin gói thầu">
|
||||
<InfoTab ev={evaluation} readOnly={readOnly} autoEdit={autoEditHeader} />
|
||||
</Section>
|
||||
<Section title="2. Chọn NCC / TP">
|
||||
<Section title={`2. Hạng mục + Báo giá (${evaluation.details.length})`}>
|
||||
<ItemsTab ev={evaluation} readOnly={readOnly} />
|
||||
</Section>
|
||||
<Section title="3. Chọn NCC / TP">
|
||||
<ChonNccSection ev={evaluation} readOnly={readOnly} />
|
||||
</Section>
|
||||
<Section title={`3. NCC / TP tham gia (${evaluation.suppliers.length})`}>
|
||||
<Section title={`4. NCC / TP tham gia (${evaluation.suppliers.length})`}>
|
||||
<SuppliersTab ev={evaluation} readOnly={readOnly} />
|
||||
</Section>
|
||||
<Section title={`4. Hạng mục + Báo giá (${evaluation.details.length})`}>
|
||||
<ItemsTab ev={evaluation} readOnly={readOnly} />
|
||||
</Section>
|
||||
<Section title="5. Ý kiến cấp duyệt (sign-off theo workflow)">
|
||||
{mode === 'workspace' && (
|
||||
<div className="mb-3 rounded border border-amber-200 bg-amber-50 px-3 py-2 text-[12px] text-amber-800">
|
||||
|
||||
@ -161,19 +161,22 @@ export function PeDetailTabs({
|
||||
</div>
|
||||
|
||||
<div className="divide-y divide-slate-200">
|
||||
{/* 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. */}
|
||||
<Section title="1. Thông tin gói thầu">
|
||||
<InfoTab ev={evaluation} readOnly={readOnly} autoEdit={autoEditHeader} />
|
||||
</Section>
|
||||
<Section title="2. Chọn NCC / TP">
|
||||
<Section title={`2. Hạng mục + Báo giá (${evaluation.details.length})`}>
|
||||
<ItemsTab ev={evaluation} readOnly={readOnly} />
|
||||
</Section>
|
||||
<Section title="3. Chọn NCC / TP">
|
||||
<ChonNccSection ev={evaluation} readOnly={readOnly} />
|
||||
</Section>
|
||||
<Section title={`3. NCC / TP tham gia (${evaluation.suppliers.length})`}>
|
||||
<Section title={`4. NCC / TP tham gia (${evaluation.suppliers.length})`}>
|
||||
<SuppliersTab ev={evaluation} readOnly={readOnly} />
|
||||
</Section>
|
||||
<Section title={`4. Hạng mục + Báo giá (${evaluation.details.length})`}>
|
||||
<ItemsTab ev={evaluation} readOnly={readOnly} />
|
||||
</Section>
|
||||
<Section title="5. Ý kiến cấp duyệt (sign-off theo workflow)">
|
||||
{mode === 'workspace' && (
|
||||
<div className="mb-3 rounded border border-amber-200 bg-amber-50 px-3 py-2 text-[12px] text-amber-800">
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user