Product & BOM / Aggregates / product-aggregate.html
Aggregate Root

Product Aggregate

Đặc tả cấu trúc chi tiết, thuộc tính, và các ràng buộc toàn vẹn dữ liệu (Invariants) của thực thể gốc Product trong mô hình R&D.

🧬 Mô Hình Cấu Trúc Các Lớp (Tactical Model)

Sơ đồ quan hệ nội bộ của Product Aggregate. Tất cả các thao tác thay đổi trạng thái linh kiện hoặc biến thể bắt buộc phải thông qua Aggregate Root Product để đảm bảo tính toàn vẹn giao dịch.

Product AGGREGATE ROOT ProductStructure ENTITY (1 - N) Component (Chi tiết vật lý) Variant ENTITY (1 - N) VariantCompAttr (VCA VO)

🛡️ Ràng Buộc Nghiệp Vụ Tĩnh (Invariants)

Các luật nghiệp vụ bắt buộc phải kiểm tra và thỏa mãn trước khi lưu dữ liệu hoặc phê duyệt bản vẽ kết cấu.

  • Luật 1 (Ràng buộc FrameType):

    Mọi Component thành phần của kết cấu gỗ bắt buộc phải khai báo thuộc tính frameTypeId hợp lệ. Đây là cơ sở tiên quyết để hệ thống MRP quy đổi đơn vị tính tồn kho WIP từ diện tích/thể tích sang số lượng khi chạy kế hoạch xưởng.

  • Luật 2 (Ràng buộc xóa Component):

    Không được phép xóa Component khi đang có thực thể Variant ở trạng thái ACTIVE liên kết đến kết cấu chứa Component đó. Hành động này sẽ gây lỗi mồ côi (orphaned config) trong MRP sản xuất.

  • Luật 3 (Ràng buộc Versioning & Approval):

    Khi cập nhật kết cấu vẽ vật lý của Product, trạng thái bản vẽ phải chuyển về DRAFT hoặc PENDING_APPROVAL. Chỉ những bản vẽ ở trạng thái APPROVED mới được phép sử dụng để cấu hình BOM cho Lệnh sản xuất.

🔄 Vòng Đời Trạng Thái (State Machine)

Quy trình luân chuyển trạng thái phê duyệt kết cấu vật lý và biến thể của Product.

DRAFT Gửi duyệt PENDING_APPROVAL Phê duyệt ACTIVE Từ chối bản vẽ

💻 Cấu Trúc Khai Báo Model (TypeScript / NestJS Context)

Đoạn code định nghĩa Domain Entity của Product phục vụ AI định vị và lập trình chính xác logic nghiệp vụ.

// src/product-management/domain/models/product.model.ts
export class Product {
  private id: string;
  private code: string;
  private name: string;
  private status: ProductStatus;
  private structures: ProductStructure[];
  private variants: Variant[];

  // Invariant: Kiểm tra kết cấu gỗ phải có frameTypeId
  public validateWoodFrameStructure(): boolean {
    for (const struct of this.structures) {
      if (struct.isWoodMaterial() && !struct.getFrameTypeId()) {
        throw new DomainException("Cấu phần gỗ bắt buộc phải có thuộc tính frameTypeId");
      }
    }
    return true;
  }
}