Files
solution-erp/.claude/skills/form-engine/SKILL.md
pqhuy1987 2abbc1d867 [CLAUDE] Docs+Skill: chốt session 6 — 3 skill refresh + 2 rule audit định kỳ
Pure docs work — 0 thay đổi code/test. 77 test vẫn pass (Domain 54 + Infra 23).

3 skill refresh stale (audit định kỳ §6.4 + §9.4 phát hiện):
- form-engine: "Phase 2 MVP missing PDF + form builder" → "Tier 3 feature-complete"
  + bỏ section duplicate "Gen mã HĐ chưa implement" (đã DONE Phase 3+6)
- permission-matrix: 12 menu cũ → ~60 menu key (Bg_*/Pe_*/PeWf_*/Catalogs)
  + inheritance roots 4 group + Budgets KHÔNG inherit (gotcha #35)
- ef-core-migration: "24 DbSet" → "52 bảng (15 migration)"

2 rule mới chốt:
- rules.md §6.4 — Audit + compact MD định kỳ (cadence + checklist + anti-pattern)
  Triết lý: KHÔNG rewrite toàn bộ. Compact + patch drift.
  Cron solution-erp-skill-audit-monthly mở rộng scope (skill + doc drift combined)
- rules.md §9.4 mở rộng cross-ref §6.4

Update STATUS Session 7+ priority + HANDOFF cảnh báo session 7 + migration-todos
Phase 9 Session 6 done sub.

Cron 2026-05-01 fire mai → combined audit theo checklist §6.4 + §9.4.

Session log đầy đủ: docs/changelog/sessions/2026-04-30-chot-session-6-md-audit-compact.md

Commit MD-only → CI skip (path filter gotcha #41).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 01:18:51 +07:00

5.3 KiB

name, description, when-to-use
name description when-to-use
form-engine Template engine render 8 form hợp đồng ra .docx/.xlsx giống 100% mẫu gốc. Placeholder syntax {{field}}. Dùng khi export HĐ, upload template mới, debug render lỗi format, gen mã HĐ theo RG-001.
export contract to word
render template docx
xuất đơn đặt hàng excel
placeholder không replace
upload template mới
gen mã hợp đồng

Form Engine Skill

Status (post Session 6 — 2026-04-30): Tier 3 FEATURE-COMPLETE. Placeholder replace + split-runs handling, FieldSpec JSON, Form builder FE (admin upload), DynamicForm renderer (Form↔JSON toggle), PDF export qua LibreOffice headless, .doc/.xls auto-convert tới .docx/.xlsx. Missing (low priority): loop {{#loop}}...{{/loop}} cho table lặp (chưa cần — 8 form hiện không có table dynamic), Export PE phiếu PDF (Phase 9 carry over, không quan trọng).

Tech stack

Layer Tech Purpose
.docx render DocumentFormat.OpenXml 3.x Free, maintained by MS
.xlsx render ClosedXML 0.105+ Free LGPL, dễ dùng, support formula/style
PDF convert LibreOffice headless (chưa implement) soffice --headless --convert-to pdf — Phase 4
.doc.docx Word COM (PowerShell) Chạy offline 1 lần trên dev machine

Placeholder syntax

Template (.docx hoặc .xlsx) chứa {{fieldName}} — regex \{\{([a-zA-Z0-9_\.]+)\}\}:

Hợp đồng số: {{maHopDong}}
Bên A: {{benA_tenCongTy}}
Giá trị: {{giaTri}}

Data dictionary:

{
  "maHopDong": "FLOCK 01/HĐGK/SOL&PVL/03",
  "benA_tenCongTy": "Công ty TNHH Xây dựng Solutions",
  "giaTri": "150,000,000 VND"
}

Null value → replace bằng rỗng. Key không có trong data → giữ nguyên placeholder.

Code pointers

  • src/Backend/SolutionErp.Application/Forms/Services/IFormRenderer.cs — interface
  • src/Backend/SolutionErp.Infrastructure/Forms/DocxRenderer.cs — OpenXml-based
  • src/Backend/SolutionErp.Infrastructure/Forms/XlsxRenderer.cs — ClosedXML-based
  • src/Backend/SolutionErp.Infrastructure/Forms/FormRenderer.cs — router theo format
  • src/Backend/SolutionErp.Application/Forms/FormFeatures.cs — CQRS list/get/render
  • src/Backend/SolutionErp.Api/Controllers/FormsController.cs — REST endpoints
  • src/Backend/SolutionErp.Infrastructure/Persistence/DbInitializer.csSeedContractTemplatesAsync
  • fe-admin/src/pages/forms/FormsPage.tsx — UI list + render test
  • src/Backend/SolutionErp.Api/wwwroot/templates/ — file templates vật lý

API endpoints

Method Path Purpose
GET /api/forms/templates?type=&onlyActive= List templates
GET /api/forms/templates/{id} Get single
POST /api/forms/templates/{id}/render Render với data dictionary → return file

Key algorithm — Placeholder split fix

Word thường split placeholder thành nhiều <w:t> runs (vì style, typo check…). DocxRenderer xử lý bằng:

foreach (var para in root.Descendants<Paragraph>()) {
    var textElements = para.Descendants<Text>().ToList();
    var combined = string.Concat(textElements.Select(t => t.Text));
    if (!combined.Contains("{{")) continue;

    var replaced = Regex.Replace(combined, @"\{\{([a-zA-Z0-9_\.]+)\}\}", match =>
        data.TryGetValue(match.Groups[1].Value, out var v) ? (v ?? "") : match.Value);

    if (replaced != combined) {
        textElements[0].Text = replaced;         // gán vào text đầu
        textElements[0].Space = ...Preserve;     // giữ space
        for (var i = 1; i < textElements.Count; i++)
            textElements[i].Text = "";            // clear phần còn lại
    }
}

Workflow thêm template mới

  1. Upload file .docx / .xlsxwwwroot/templates/{formCode}.{ext}
  2. Insert row vào ContractTemplates:
    INSERT INTO ContractTemplates (FormCode, Name, ContractType, FileName, StoragePath, Format, IsActive, CreatedAt)
    VALUES ('SOL-CCM-FO-002.XX', 'Tên', 1, 'file.docx', 'templates/file.docx', 'docx', 1, GETUTCDATE());
    
  3. Template tự động xuất hiện ở /forms FE

Known limitations

# Limitation Status
1 Không support {{#loop}}...{{/loop}} cho table lặp Pending (chưa cần)
2 Không handle .docm (macro) — chỉ accept .docx / .xlsx By design (security)
3 BE phải format số/tiền trước khi pass data (template không format) By design — caller responsibility
4 PE Export phiếu PDF chưa wire Phase 9 carry over (không quan trọng)

Common pitfalls (xem gotchas.md)

  • Placeholder bị split runs → đã handle trong DocxRenderer
  • SpaceProcessingModeValues namespace — xem gotcha #9
  • Word COM stuck — gotcha #12
  • SaveAs type conversion — gotcha #11
  • Template file không tồn tại → throw NotFoundException ở RenderCommandHandler

Gen mã HĐ (RG-001) — DONE Phase 3 + Phase 6 PE

Đã implement: ContractCodeGenerator + PurchaseEvaluationCodeGenerator (atomic SERIALIZABLE). Detail trong skill contract-workflow (HĐ) + format PE PE/{YYYY}/{A|B}/{Seq:D3}. 17 unit test cover (Infrastructure.Tests/Services).

Xem docs/forms-spec.md §RG-001 cho format spec từng ContractType.