[CLAUDE] Contract: K2 SP-002 phieu KHKK mang hang-muc + nhom duyet N1-8 (Mig 71) + FE x2 app + 11 test
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 6m12s

Mig 71 AddKhkkApprovalGroupCatalogAndFinalizeRuntime: +ApprovalGroup (backfill=1)
+EndedByLevelFinalize (K2 de, K3 tieu - ghost-window khai) + Line +CatalogEntryId/
TenHangMuc + unique (Plan,Supplier,CatalogEntry) filtered IsDeleted=0. Rao
1-PE-1-phieu doi (PeId,ApprovalGroup) 2 site + picker OG-7 ExistingGroups + nut
'Tao them cho nhom khac'. Submit-guard va-5 (CHAN null, thang nen cho-qua-legacy;
ghost-window K2->K4b khai) + dem-so-khop (gate F-1: bit duong hang-muc xoa-mem).
List ?group= end-to-end + Tong-Approved list (va-8). FE: select nhom default 1 +
badge N{g} + cot Hang-muc + cot Tong-duyet, SHA-pair 5/5. Gate K2 PASS-WITH-FLAGS
10f: F-1 guard fix + 2 test bit (xoa-mem chan + reflection ?group=); F-2/F-5/F-7/
F-8/F-9 comment-honest; F-3/F-4 docs-delta. Suite 609/0 (45D+564I). Wave co #53 x5,
artifact + relaunch-cat-got cuu 100% (0 mat cong).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-07-31 17:05:27 +07:00
parent 89b5bbee8a
commit 0779f2d45a
23 changed files with 8905 additions and 109 deletions

View File

@ -193,11 +193,17 @@ public class ContractSigningPlanSchemaTests
db.ContractSigningPlans.Add(plan);
var supplierId = Guid.NewGuid();
// [K2 Mig 71] UNIQUE nay 3 cột (PlanId, SupplierId, CatalogEntryId). CẢ HAI vế của test
// dùng CatalogEntryId NON-NULL GIỐNG NHAU để phép đo độc lập provider: SQLite coi
// NULL ≠ NULL trong unique (cặp NULL không nổ) còn SQL Server coi bằng nhau — cặp NULL
// do SUBMIT-GUARD (WorkflowService) chặn ở tầng nghiệp vụ, không đo ở đây.
var catalogId = Guid.NewGuid(); // loose-Guid — index test không cần row danh mục thật
db.ContractSigningPlanLines.Add(new ContractSigningPlanLine
{
Id = Guid.NewGuid(),
ContractSigningPlanId = plan.Id,
SupplierId = supplierId,
CatalogEntryId = catalogId,
PeReferenceAmount = 100_000_000m,
ProposedAmount = 95_000_000m,
});
@ -217,13 +223,14 @@ public class ContractSigningPlanSchemaTests
Id = Guid.NewGuid(),
ContractSigningPlanId = plan.Id,
SupplierId = supplierId,
CatalogEntryId = catalogId, // trùng cả 3 cột với dòng đã XOÁ MỀM
PeReferenceAmount = 100_000_000m,
ProposedAmount = 90_000_000m,
});
var act = async () => await db.SaveChangesAsync();
await act.Should().NotThrowAsync(
"UNIQUE (PlanId, SupplierId) phải là filtered `WHERE [IsDeleted] = 0` — gotcha #57");
"UNIQUE (PlanId, SupplierId, CatalogEntryId) phải là filtered `WHERE [IsDeleted] = 0` — gotcha #57");
db.ContractSigningPlanLines.AsNoTracking()
.Count(x => x.ContractSigningPlanId == plan.Id)
@ -246,23 +253,48 @@ public class ContractSigningPlanSchemaTests
};
db.ContractSigningPlans.Add(plan2);
var dupSupplierId = Guid.NewGuid();
foreach (var _ in new[] { 1, 2 })
var dupCatalogId = Guid.NewGuid();
db.ContractSigningPlanLines.Add(new ContractSigningPlanLine
{
db.ContractSigningPlanLines.Add(new ContractSigningPlanLine
{
Id = Guid.NewGuid(),
ContractSigningPlanId = plan2.Id,
SupplierId = dupSupplierId,
PeReferenceAmount = 1m,
ProposedAmount = 1m,
});
}
Id = Guid.NewGuid(),
ContractSigningPlanId = plan2.Id,
SupplierId = dupSupplierId,
CatalogEntryId = dupCatalogId,
PeReferenceAmount = 1m,
ProposedAmount = 1m,
});
await db.SaveChangesAsync(); // dòng 1 sống — mốc đối chứng
db.ContractSigningPlanLines.Add(new ContractSigningPlanLine
{
Id = Guid.NewGuid(),
ContractSigningPlanId = plan2.Id,
SupplierId = dupSupplierId,
CatalogEntryId = dupCatalogId, // TRÙNG cả 3 cột, cả 2 còn SỐNG
PeReferenceAmount = 1m,
ProposedAmount = 1m,
});
var actDup = async () => await db.SaveChangesAsync();
await actDup.Should().ThrowAsync<DbUpdateException>(
"2 dòng SỐNG cùng (PlanId, SupplierId) phải bị UNIQUE chặn — vế này chứng "
"2 dòng SỐNG cùng (PlanId, SupplierId, CatalogEntryId) phải bị UNIQUE chặn — vế này chứng "
+ "index thật sự tồn tại, nên vế 'xoá mềm rồi thêm lại KHÔNG nổ' ở trên "
+ "là do FILTER chứ không phải do thiếu index");
db.ChangeTracker.Clear();
// [K2 Mig 71] Vế MỞ — chính tính năng K2: CÙNG (Plan, NCC) nhưng KHÁC hạng mục = 2 dòng
// hợp lệ (tách 1 NCC theo nhiều hạng mục). Unique 2 cột cũ CẤM ca này — nay phải QUA.
db.ContractSigningPlanLines.Add(new ContractSigningPlanLine
{
Id = Guid.NewGuid(),
ContractSigningPlanId = plan2.Id,
SupplierId = dupSupplierId,
CatalogEntryId = Guid.NewGuid(), // hạng mục KHÁC ⇒ được phép
PeReferenceAmount = 1m,
ProposedAmount = 1m,
});
var actSplit = async () => await db.SaveChangesAsync();
await actSplit.Should().NotThrowAsync(
"unique 3 cột phải CHO PHÉP cùng (Plan, NCC) khác CatalogEntryId — mục đích của Mig 71");
}
// ===================================================================