[CLAUDE] Contract: KHKK man duyet — bo "(N dong)" + cot STT + ma hang muc (Mig 72)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 7m2s

Anh giao qua anh prod man duyet KHKK, 2 diem khoanh do:
 (1) "Bo 1 dong di nhe" -> go hau to "(N dong)" khoi title Section 2.
 (2) "Hien thi stt va ma hang muc (Du an) - ma hang muc chi tiet"
     -> bang 3->4 cot (+STT cot rieng, anh chot), cot HANG MUC them dong
        ma "<ma du an> - <ma chi tiet>" nam TREN ten.

Mig 72 AddMaHangMucToContractSigningPlanLines (anh chot DENORM co migration):
 - +cot MaHangMuc nvarchar(20) = BANG nguon ContractCatalogEntry.Code.
 - backfill Sql() idempotent (WHERE MaHangMuc IS NULL), COY KHONG loc IsDeleted:
   hang muc xoa mem SAU ngay lap phieu thi dong phieu van phai giu duoc ma —
   do chinh la ly do cot nay la denorm. Loc di la bo trong dung dong can cuu nhat.
 - ten bang doi chieu voi ToTable() cua CA HAI configuration truoc khi viet
   (Mig 60 tung backfill soi NHAM BANG, chay sach, phai de Mig 61 va — gotcha #78/#79).

PeWorkItemCode KHONG denorm — noi join WorkItems san co o Features.cs:929, 0 cot moi.
Chup lai vao KHKK la chup mot thu von da la con tro loose-Guid qua PE (Mig 49).

3 write-site denorm sua DU: :527 moi null · :695 gan lai · :805 tao moi.
Sot 1 cho = de dong co ten ma khong co ma, chi lo ra o luong it ai bam.

FE 2 app SHA IDENTICAL (verify identical @HEAD TRUOC khi copy de).
Build BE 0 warning 0 error · 2 app build sach · 644/644 test pass.
Lint 42 van de = NO CO SAN, 0 cai o 2 file luot nay dung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-08-06 14:47:08 +07:00
parent d081681e04
commit 530af22910
10 changed files with 7245 additions and 14 deletions

View File

@ -22,6 +22,9 @@ public class ContractSigningPlanLineConfiguration : IEntityTypeConfiguration<Con
// — denorm mà hẹp hơn nguồn thì tên dài nhất (A3-09 ~150 ký tự) vẫn lọt, nhưng để
// BẰNG nguồn thì không bao giờ phải cắt. Validator lấy số từ ĐÂY (EF = source of truth).
b.Property(x => x.TenHangMuc).HasMaxLength(500);
// [Mig 72 — S177] Cùng lý lẽ BẰNG-NGUỒN như trên: `ContractCatalogEntry.Code` là 20
// (`ContractCatalogEntryConfiguration.cs:18`) ⇒ denorm cũng 20, không bao giờ phải cắt.
b.Property(x => x.MaHangMuc).HasMaxLength(20);
// [K2 Mig 71 — S164] UNIQUE đổi (Plan, Supplier) → (Plan, Supplier, CatalogEntry):
// 1 NCC được nhiều dòng trên cùng phiếu, mỗi dòng 1 hạng mục khác nhau.

View File

@ -0,0 +1,45 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace SolutionErp.Infrastructure.Persistence.Migrations
{
/// <inheritdoc />
public partial class AddMaHangMucToContractSigningPlanLines : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "MaHangMuc",
table: "ContractSigningPlanLines",
type: "nvarchar(20)",
maxLength: 20,
nullable: true);
// [S177] BACKFILL dòng phiếu ĐÃ CÓ: chép `Code` của hạng mục đang trỏ tới.
// 🔴 Tên bảng đã đối chiếu với `ToTable(...)` của CẢ HAI configuration trước khi
// viết — Mig 60 từng backfill soi NHẦM BẢNG, chạy sạch, không ném lỗi, phải đẻ
// Mig 61 vá (gotcha #78/#79). UPDATE sai bảng chỉ đụng 0 dòng rồi báo thành công.
// 🔴 CỐ Ý KHÔNG lọc `c.IsDeleted = 0`: hạng mục bị xoá mềm SAU ngày lập phiếu thì
// dòng phiếu vẫn phải giữ được mã của nó — đó chính là lý do cột này là denorm.
// Lọc đi là tự tay bỏ trống đúng những dòng cần cứu nhất.
// 🔴 Idempotent nhờ `MaHangMuc IS NULL`: chạy lại không đè dòng đã có mã.
migrationBuilder.Sql(@"
UPDATE l
SET l.MaHangMuc = c.Code
FROM ContractSigningPlanLines l
INNER JOIN ContractCatalogEntries c ON c.Id = l.CatalogEntryId
WHERE l.MaHangMuc IS NULL
AND l.CatalogEntryId IS NOT NULL;");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "MaHangMuc",
table: "ContractSigningPlanLines");
}
}
}

View File

@ -742,6 +742,10 @@ namespace SolutionErp.Infrastructure.Persistence.Migrations
b.Property<bool>("IsDeleted")
.HasColumnType("bit");
b.Property<string>("MaHangMuc")
.HasMaxLength(20)
.HasColumnType("nvarchar(20)");
b.Property<string>("Note")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");