using FnbEngine.Domain.Events; using FnbEngine.Domain.Exceptions; using FnbEngine.Domain.SeedWork; namespace FnbEngine.Domain.AggregatesModel.SampleAggregate; /// /// EN: Sample aggregate root demonstrating DDD patterns. /// VI: Sample aggregate root minh họa các pattern DDD. /// public class Sample : Entity, IAggregateRoot { // EN: Private fields for encapsulation // VI: Fields private để đóng gói private string _name = null!; private string? _description; private SampleStatus _status = null!; private DateTime _createdAt; private DateTime? _updatedAt; /// /// EN: Sample name (required). /// VI: Tên sample (bắt buộc). /// public string Name => _name; /// /// EN: Optional description. /// VI: Mô tả tùy chọn. /// public string? Description => _description; /// /// EN: Current status. /// VI: Trạng thái hiện tại. /// public SampleStatus Status => _status; /// /// EN: Status ID for EF Core mapping. /// VI: ID trạng thái cho EF Core mapping. /// public int StatusId { get; private set; } /// /// EN: Creation timestamp. /// VI: Thời gian tạo. /// public DateTime CreatedAt => _createdAt; /// /// EN: Last update timestamp. /// VI: Thời gian cập nhật cuối. /// public DateTime? UpdatedAt => _updatedAt; /// /// EN: Private constructor for EF Core. /// VI: Constructor private cho EF Core. /// protected Sample() { } /// /// EN: Create a new Sample with required information. /// VI: Tạo một Sample mới với thông tin bắt buộc. /// /// EN: Sample name / VI: Tên sample /// EN: Optional description / VI: Mô tả tùy chọn public Sample(string name, string? description = null) : this() { if (string.IsNullOrWhiteSpace(name)) throw new SampleDomainException("Sample name cannot be empty"); Id = Guid.NewGuid(); _name = name; _description = description; _status = SampleStatus.Draft; StatusId = SampleStatus.Draft.Id; _createdAt = DateTime.UtcNow; // EN: Add domain event for creation // VI: Thêm domain event cho việc tạo AddDomainEvent(new SampleCreatedDomainEvent(this)); } /// /// EN: Update sample information. /// VI: Cập nhật thông tin sample. /// public void Update(string name, string? description) { if (string.IsNullOrWhiteSpace(name)) throw new SampleDomainException("Sample name cannot be empty"); if (_status == SampleStatus.Cancelled) throw new SampleDomainException("Cannot update a cancelled sample"); _name = name; _description = description; _updatedAt = DateTime.UtcNow; } /// /// EN: Activate the sample. /// VI: Kích hoạt sample. /// public void Activate() { if (_status != SampleStatus.Draft) throw new SampleDomainException("Only draft samples can be activated"); var previousStatus = _status; _status = SampleStatus.Active; StatusId = SampleStatus.Active.Id; _updatedAt = DateTime.UtcNow; AddDomainEvent(new SampleStatusChangedDomainEvent(Id, previousStatus, _status)); } /// /// EN: Complete the sample. /// VI: Hoàn thành sample. /// public void Complete() { if (_status != SampleStatus.Active) throw new SampleDomainException("Only active samples can be completed"); var previousStatus = _status; _status = SampleStatus.Completed; StatusId = SampleStatus.Completed.Id; _updatedAt = DateTime.UtcNow; AddDomainEvent(new SampleStatusChangedDomainEvent(Id, previousStatus, _status)); } /// /// EN: Cancel the sample. /// VI: Hủy sample. /// public void Cancel() { if (_status == SampleStatus.Completed) throw new SampleDomainException("Cannot cancel a completed sample"); if (_status == SampleStatus.Cancelled) throw new SampleDomainException("Sample is already cancelled"); var previousStatus = _status; _status = SampleStatus.Cancelled; StatusId = SampleStatus.Cancelled.Id; _updatedAt = DateTime.UtcNow; AddDomainEvent(new SampleStatusChangedDomainEvent(Id, previousStatus, _status)); } }