Files
solution-erp/docs/workflow-contract.md
pqhuy1987 e71e0eba65
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m53s
[CLAUDE] Docs: tai cau truc cleanup — archive raw, compact migration-todos, update CLAUDE+flows
User request: 'review cap nhat va tai cau truc lai MD sao cho phu hop
voi hien tai, cac phan thua va da dieu chinh co the bo ra luon hoac
cap nhat lai'.

Cleanup highlights:
1. Archive 2 file Phase 0 raw dump → docs/_archive/ (forms-spec-raw 657
   line + workflow-raw 62 line). Update link reference 2 file goc.
2. Compact migration-todos.md 386 → 114 line (-71%). Collapse Phase 0-5
   + Tier 3 + Sessions detailed thanh 1 bang summary. Detail xem session
   logs. Phase 6 iter 1+2 + Phase 7 active checklist.
3. Compact STATUS.md In Progress: bo ~17 row  done (giu chỉ 5+ task
   pending: 3 PE feature gap + 4 optional polish + 2 Ops). Recently Done
   table giu day du history.
4. Update flows/README — tat ca 6 flow  Implemented + them PE row
   reference architecture.md §9.
5. Update docs/CLAUDE.md — project layout co PurchaseEvaluations, _archive,
   skills 6 (3 dom + 3 ops). Roadmap them Phase 6  + Phase 7 WIP. Lien
   he them prod URL solutions.com.vn + SSH config + login admin.
6. Skill ef-core-migration: 13 migration label.

Net delta: -800 line docs (chu yeu archive + collapse migration-todos).
2026-04-25 14:17:53 +07:00

13 KiB
Raw Blame History

Workflow — Quy trình trình ký Hợp đồng TP/NCC/Tổ đội

Nguồn: QUY_TRINH/QT TRINH KY HOP DONG TP-NCC.docx Raw dump: _archive/workflow-raw.md — Phase 0 (archived) Phase 3 deliverable: Implement state machine + role guard + SLA timer + notification

1. Phạm vi

Áp dụng cho Hợp đồng/Phụ lục HĐ ký với: Thầu phụ (NTP) · Nhà cung cấp (NCC) · Tổ đội (TĐ). Tham chiếu ISO 9001.

2. Glossary (viết tắt)

Nghĩa Role trong system
BOD Ban Giám đốc Director
NĐUQ Người được ủy quyền AuthorizedSigner
CCM Phòng Kiểm soát Chi phí CostControl
PRO Phòng Cung ứng Procurement
FIN Phòng Tài chính Finance
ACT Phòng Kế toán Accounting
EQU Phòng Thiết bị Equipment
HRA Nhân sự - Hành chính (đóng dấu) HR_Admin
PB Phòng ban Department
BCH CT Ban chỉ huy công trường SiteCommand
PD Giám đốc Thi công ProjectDirector
PM Giám đốc Dự án ProjectManager
TPB Trưởng Phòng ban DeptManager
TBP Trưởng Bộ phận SectionLeader
QS/NV.PB QS công trường / Nhân viên PB Drafter (người soạn)
NTP/NCC/TĐ Đối tác ký HĐ Partner (external — không login)

3. State Machine (9 phase)

stateDiagram-v2
    [*] --> DangChon: Tạo mới
    DangChon --> DangSoanThao: Chọn NCC xong (chuyển Drafter)
    DangSoanThao --> DangGopY: Gửi email góp ý (7d)
    DangGopY --> DangDamPhan: Nhận xong comment (7d)
    DangDamPhan --> DangInKy: Thỏa thuận xong (7d)
    DangInKy --> DangKiemTraCCM: Đã ký nháy QS/PD/TPB, chuyển CCM (1d)
    DangKiemTraCCM --> DangTrinhKy: CCM ký nháy xong (3d)
    DangTrinhKy --> DangDongDau: BOD/NĐUQ ký duyệt (1d)
    DangDongDau --> DaPhatHanh: HRA đóng dấu xong
    DaPhatHanh --> [*]: PB scan + gửi bản gốc + lưu Filing

    DangSoanThao --> TuChoi: Cancel
    DangGopY --> DangSoanThao: Revise
    DangKiemTraCCM --> DangSoanThao: CCM reject
    DangTrinhKy --> DangSoanThao: BOD reject
    TuChoi --> [*]

4. Chi tiết từng phase

# Phase (state) Role thực hiện Input Output SLA Form liên quan
1 DangChon — Lựa chọn NTP/NCC PB / BCH CT Yêu cầu công việc Chốt đối tác (theo Quy trình Cung ứng SOL-PRO-SP-001)
2 DangSoanThao — Soạn thảo HĐ Drafter (QS/NV.PB) + TBP/TPB check Template HĐ Dự thảo HĐ 7 ngày FO-002.02/.03/.04/.05/.06 (chọn loại phù hợp)
3 DangGopY — Góp ý nội dung PD/PM/PRO/CCM/FIN/ACT/EQU Dự thảo Comment (email → hệ thống) 7 ngày (đính kèm comment thread)
4 DangDamPhan — Đàm phán Drafter + TBP/TPB/PD/PM Comment Bản cuối thỏa thuận 7 ngày
5 DangInKy — In + đối tác ký Drafter + NTP/NCC/TĐ (external) + PD/PM/TPB ký nháy Bản cuối 2 mặt, có chữ ký đối tác + ký nháy nội bộ 1 ngày FO-002.01 (cover approval)
6 DangKiemTraCCM — CCM kiểm tra CCM (TP.CCM ký nháy) HĐ đã ký nháy HĐ CCM approved 3 ngày FO-002.01
7 DangTrinhKy — BOD ký duyệt BOD hoặc NĐUQ HĐ CCM approved HĐ ký duyệt 1 ngày FO-002.01
8 DangDongDau — Đóng dấu HRA/ISO HĐ đã ký HĐ có dấu
9 DaPhatHanh — Phát hành + lưu trữ PB/BCH CT + CCM HĐ có dấu Scan + bản gốc gửi NCC + lưu Filing System

Tổng SLA: ~19 ngày (phase 2-7) cho 1 HĐ hoàn chỉnh.

5. Role × Phase Matrix (quyền xem/thao tác)

Ký hiệu: R = read, W = write/update draft, A = approve (chuyển phase tiếp), - = không có quyền.

Role \ Phase 1.Chọn 2.Soạn 3.GópÝ 4.ĐàmPhán 5.InKý 6.CCMCheck 7.BODKý 8.ĐóngDấu 9.PhátHành
Drafter (QS/NV.PB) R W,A R W,A W,A R R R W
TBP/TPB R R,A R,A R,A R,A R R R R
PD/PM R R W,A R,A R,A R R R R
PRO/EQU/FIN/ACT A R W,A R - - - - R
CCM - R W,A R R W,A R R W
BOD/NĐUQ - - - - - - A - R
HRA - - - - - - - W,A R
Admin (system) R R R R R R R R R (+ override)

Guard rule:

  • Đặc biệt: HĐ với Chủ đầu tư → có thể bypass phase 3 + 6 (không cần PRO/CCM góp ý + kiểm tra). Cờ BypassProcurementAndCCM: bool ở entity HĐ.
  • Quá SLA mỗi phase không action → auto-approve (chuyển phase tiếp). Gửi notification warning khi còn 2h.
  • Nếu cần kéo dài → bộ phận kiểm tra phải comment vào "Ý kiến" trước khi SLA hết.

6. Notification triggers

Event Người nhận Kênh
Chuyển DangSoanThaoDangGopY Tất cả role góp ý (PD/PM/PRO/CCM/FIN/ACT) email + in-app
Chuyển DangKiemTraCCM CCM email + in-app
Chuyển DangTrinhKy BOD + NĐUQ email + in-app (high priority)
Quá SLA 80% thời gian Role đang giữ phase in-app warning
Quá SLA → auto-approve Drafter + role giữ phase email + in-app (log audit)
Reject (quay về DangSoanThao) Drafter email + in-app

7. Data model implication (cho Phase 3 + Tier 3 versioned)

// Domain
public enum ContractPhase {
    DangChon = 1,
    DangSoanThao,
    DangGopY,
    DangDamPhan,
    DangInKy,
    DangKiemTraCCM,
    DangTrinhKy,
    DangDongDau,
    DaPhatHanh,
    TuChoi
}

public class Contract : AuditableEntity {
    public Guid Id { get; set; }
    public string? MaHopDong { get; set; }  // tự gen theo RG-001
    public ContractType Type { get; set; }  // HDTP, HDGK, NCC, HDDV...
    public ContractPhase Phase { get; set; }
    public Guid SupplierId { get; set; }
    public Guid ProjectId { get; set; }
    public decimal GiaTri { get; set; }
    public bool BypassProcurementAndCCM { get; set; }
    public DateTime? SlaDeadline { get; set; }
    public bool SlaWarningSent { get; set; }

    // Tier 3: pin policy version at create-time cho immutability
    public Guid? WorkflowDefinitionId { get; set; }

    public List<ContractComment> Comments { get; set; }
    public List<ContractApproval> Approvals { get; set; }
    public List<ContractAttachment> Attachments { get; set; }
}

public class ContractApproval {
    public Guid ContractId { get; set; }
    public ContractPhase FromPhase { get; set; }
    public ContractPhase ToPhase { get; set; }
    public Guid? ApproverUserId { get; set; }  // null = system (SLA auto)
    public DateTime? ApprovedAt { get; set; }
    public ApprovalDecision Decision { get; set; }  // Pending | Approve | Reject | AutoApprove
    public string? Comment { get; set; }
}

// ==================== Tier 3: versioned workflow ====================

public class WorkflowDefinition : AuditableEntity {
    public Guid Id { get; set; }
    public string Code { get; set; } = "";       // "QT-MB", "QT-TP", "QT-NCC", ...
    public int Version { get; set; }              // 1, 2, 3, ... auto-increment per Code
    public bool IsActive { get; set; }            // chỉ 1 = true per ContractType
    public ContractType ContractType { get; set; }
    public string Name { get; set; } = "";        // "Quy trình Mua bán v02"
    public string? Description { get; set; }

    public List<WorkflowStep> Steps { get; set; } = new();
}

public class WorkflowStep {
    public Guid Id { get; set; }
    public Guid WorkflowDefinitionId { get; set; }
    public int Order { get; set; }                // thứ tự step trong định nghĩa
    public ContractPhase Phase { get; set; }      // target phase
    public string Name { get; set; } = "";        // "Kiểm tra CCM"
    public int SlaDays { get; set; }              // SLA ngày cho phase này

    public List<WorkflowStepApprover> Approvers { get; set; } = new();
}

public class WorkflowStepApprover {
    public Guid Id { get; set; }
    public Guid WorkflowStepId { get; set; }
    public ApproverKind Kind { get; set; }        // Role | User
    public string AssignmentValue { get; set; } = "";  // RoleName hoặc UserId Guid string
}

public enum ApproverKind { Role = 1, User = 2 }

Service chính:

  • IContractWorkflowService.TransitionAsync(contractId, targetPhase, userId, comment) — resolve policy, check guard, update state, tạo approval, emit notification
  • IContractCodeGenerator.GenerateAsync(projectId, type, supplierId) — SERIALIZABLE transaction tránh race
  • SlaExpiryJob : BackgroundService — 15min, auto-approve quá hạn với Decision=AutoApprove
  • IRealtimeNotifier (SignalR impl) — push vào group User-{Id} khi Notification created

7bis. Policy resolution — versioned workflow

sequenceDiagram
    participant User as Actor
    participant API as ContractsController
    participant WF as ContractWorkflowService
    participant DB as WorkflowDefinitions

    User->>API: POST /contracts/{id}/transitions {targetPhase}
    API->>WF: TransitionAsync(id, targetPhase, userId, comment)

    alt Contract.WorkflowDefinitionId != null (Tier 3 pinned)
        WF->>DB: Include(Steps.Approvers).First(Id == wfId)
        DB-->>WF: def
        WF->>WF: policy = Registry.FromDefinition(def)
    else Admin override in WorkflowTypeAssignments
        WF->>DB: Find(ContractType == c.Type)
        DB-->>WF: override
        WF->>WF: policy = Registry.ByName(override.PolicyName)
    else Legacy fallback
        WF->>WF: policy = Registry.For(c.Type) // hardcoded Standard/SkipCcm
    end

    WF->>WF: check (from, to) ∈ policy.Transitions
    WF->>WF: check actor.Roles ∩ allowedRoles != ∅
    WF->>DB: UPDATE Phase + INSERT ContractApproval + INSERT Notifications
    WF-->>API: 200

7ter. Admin designer flow (tạo version mới)

Admin → /system/workflows → click type "HĐ Mua bán"
→ /system/workflows/MuaBan
→ thấy active version QT-MB-v01 + history
→ click "Tạo phiên bản mới" → Designer modal (có thể Clone từ v01)
  - Code: QT-MB (auto-fill)
  - Version: v02 (auto-compute max+1)
  - Name + Description
  - Steps (repeatable):
    [Order 1] Phase=2 (DangSoanThao) SLA=7 days Approvers: +Role Drafter, +Role DeptManager
    [Order 2] Phase=3 (DangGopY) SLA=7 days Approvers: +Role ProjectManager, +User {userId}
    ...
  - Save → POST /api/workflows
    BE: auto Version=max+1, deactivate QT-MB-v01.IsActive=0, insert v02.IsActive=1, atomic
→ trở về /system/workflows/MuaBan → v02 active, v01 archived "N HĐ còn chạy"
→ HĐ cũ pin v01 vẫn chạy v01 (Contract.WorkflowDefinitionId không đổi)
→ HĐ mới tạo sau đây sẽ pin v02

8. Business rules summary

  1. Một role chỉ có 1 phase active tại 1 thời điểm cho 1 HĐ.
  2. Auto-approve nếu quá SLA — phải log Decision=AutoApprove rõ ràng trong ContractApproval.
  3. Reject → quay về DangSoanThao — Drafter nhận lại, toàn bộ approval trước đó bị invalidate (kept as history).
  4. Không cho xóa HĐ đã qua phase 5 (DangInKy) — chỉ soft delete.
  5. Mã HĐ gen theo forms-spec.md § RG-001 — chỉ gen khi transition sang phase DangDongDau (8).
  6. Audit log — mọi transition đều insert ContractApprovals row với actor + timestamp + phase before/after.
  7. Versioned workflowContract.WorkflowDefinitionId pin tại create-time, không update sau đó. Admin tạo version mới ảnh hưởng HĐ tương lai, HĐ cũ giữ version cũ.
  8. Chỉ 1 active version per ContractType — enforce qua business logic trong CreateWorkflowDefinitionCommand (atomic deactivate + insert).

9. Code pointers (Tier 3)

Domain:

  • Domain/Contracts/WorkflowDefinition.cs
  • Domain/Contracts/WorkflowStep.cs
  • Domain/Contracts/WorkflowStepApprover.cs (+ ApproverKind enum)
  • Domain/Contracts/WorkflowPolicy.cs (record + WorkflowPolicies.Standard/SkipCcm + WorkflowPolicyRegistry.FromDefinition + ForContract)

Application:

  • Application/Contracts/WorkflowAdminFeatures.cs:
    • GetWorkflowAdminOverviewQuery — landing per-type + active + history
    • CreateWorkflowDefinitionCommand — auto Version + atomic deactivate old

Infrastructure:

  • Infrastructure/Services/ContractWorkflowService.csLoadPolicyAsync(contractId) resolution order

Api:

  • Api/Controllers/WorkflowsController.cs — GET overview, GET per-type, POST create-version

FE-Admin:

  • fe-admin/src/pages/system/WorkflowsPage.tsx — URL-driven, landing + per-type
  • fe-admin/src/components/workflow/WorkflowDesigner.tsx — modal Steps + Approvers
  • fe-admin/src/components/workflow/DefinitionCard.tsx — active + history card