diff --git a/services/booking-service-net/src/BookingService.API/Application/Commands/ChangeSampleStatusCommand.cs b/services/booking-service-net/src/BookingService.API/Application/Commands/ChangeSampleStatusCommand.cs
deleted file mode 100644
index c2d393cc..00000000
--- a/services/booking-service-net/src/BookingService.API/Application/Commands/ChangeSampleStatusCommand.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using MediatR;
-
-namespace BookingService.API.Application.Commands;
-
-///
-/// EN: Command to change status of a Sample.
-/// VI: Command để thay đổi trạng thái của Sample.
-///
-/// EN: Sample ID / VI: ID sample
-/// EN: New status (activate, complete, cancel) / VI: Trạng thái mới (activate, complete, cancel)
-public record ChangeSampleStatusCommand(
- Guid SampleId,
- string NewStatus
-) : IRequest;
diff --git a/services/booking-service-net/src/BookingService.API/Application/Commands/ChangeSampleStatusCommandHandler.cs b/services/booking-service-net/src/BookingService.API/Application/Commands/ChangeSampleStatusCommandHandler.cs
deleted file mode 100644
index 7c2be169..00000000
--- a/services/booking-service-net/src/BookingService.API/Application/Commands/ChangeSampleStatusCommandHandler.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using MediatR;
-using BookingService.Domain.AggregatesModel.SampleAggregate;
-
-namespace BookingService.API.Application.Commands;
-
-///
-/// EN: Handler for ChangeSampleStatusCommand.
-/// VI: Handler cho ChangeSampleStatusCommand.
-///
-public class ChangeSampleStatusCommandHandler : IRequestHandler
-{
- private readonly ISampleRepository _sampleRepository;
- private readonly ILogger _logger;
-
- public ChangeSampleStatusCommandHandler(
- ISampleRepository sampleRepository,
- ILogger logger)
- {
- _sampleRepository = sampleRepository ?? throw new ArgumentNullException(nameof(sampleRepository));
- _logger = logger ?? throw new ArgumentNullException(nameof(logger));
- }
-
- public async Task Handle(
- ChangeSampleStatusCommand request,
- CancellationToken cancellationToken)
- {
- _logger.LogInformation(
- "Changing status of sample {SampleId} to {NewStatus} / Thay đổi trạng thái sample {SampleId} thành {NewStatus}",
- request.SampleId, request.NewStatus);
-
- // EN: Get existing sample / VI: Lấy sample đã tồn tại
- var sample = await _sampleRepository.GetAsync(request.SampleId);
-
- if (sample is null)
- {
- _logger.LogWarning(
- "Sample {SampleId} not found / Sample {SampleId} không tìm thấy",
- request.SampleId);
- return false;
- }
-
- // EN: Change status based on action / VI: Thay đổi trạng thái dựa trên action
- switch (request.NewStatus.ToLowerInvariant())
- {
- case "activate":
- sample.Activate();
- break;
- case "complete":
- sample.Complete();
- break;
- case "cancel":
- sample.Cancel();
- break;
- default:
- _logger.LogWarning(
- "Invalid status action: {NewStatus} / Action trạng thái không hợp lệ: {NewStatus}",
- request.NewStatus);
- return false;
- }
-
- // EN: Save changes / VI: Lưu thay đổi
- await _sampleRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);
-
- _logger.LogInformation(
- "Sample {SampleId} status changed to {NewStatus} / Trạng thái sample {SampleId} đã đổi thành {NewStatus}",
- request.SampleId, request.NewStatus);
-
- return true;
- }
-}
diff --git a/services/booking-service-net/src/BookingService.API/Application/Commands/CreateSampleCommand.cs b/services/booking-service-net/src/BookingService.API/Application/Commands/CreateSampleCommand.cs
deleted file mode 100644
index 3ece960b..00000000
--- a/services/booking-service-net/src/BookingService.API/Application/Commands/CreateSampleCommand.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using MediatR;
-
-namespace BookingService.API.Application.Commands;
-
-///
-/// EN: Command to create a new Sample.
-/// VI: Command để tạo một Sample mới.
-///
-/// EN: Sample name / VI: Tên sample
-/// EN: Optional description / VI: Mô tả tùy chọn
-public record CreateSampleCommand(
- string Name,
- string? Description
-) : IRequest;
-
-///
-/// EN: Result of CreateSampleCommand.
-/// VI: Kết quả của CreateSampleCommand.
-///
-/// EN: Created sample ID / VI: ID sample đã tạo
-public record CreateSampleCommandResult(Guid Id);
diff --git a/services/booking-service-net/src/BookingService.API/Application/Commands/CreateSampleCommandHandler.cs b/services/booking-service-net/src/BookingService.API/Application/Commands/CreateSampleCommandHandler.cs
deleted file mode 100644
index c386e30c..00000000
--- a/services/booking-service-net/src/BookingService.API/Application/Commands/CreateSampleCommandHandler.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using MediatR;
-using BookingService.Domain.AggregatesModel.SampleAggregate;
-
-namespace BookingService.API.Application.Commands;
-
-///
-/// EN: Handler for CreateSampleCommand.
-/// VI: Handler cho CreateSampleCommand.
-///
-public class CreateSampleCommandHandler : IRequestHandler
-{
- private readonly ISampleRepository _sampleRepository;
- private readonly ILogger _logger;
-
- public CreateSampleCommandHandler(
- ISampleRepository sampleRepository,
- ILogger logger)
- {
- _sampleRepository = sampleRepository ?? throw new ArgumentNullException(nameof(sampleRepository));
- _logger = logger ?? throw new ArgumentNullException(nameof(logger));
- }
-
- public async Task Handle(
- CreateSampleCommand request,
- CancellationToken cancellationToken)
- {
- _logger.LogInformation(
- "Creating new sample with name: {Name} / Tạo sample mới với tên: {Name}",
- request.Name);
-
- // EN: Create domain entity / VI: Tạo domain entity
- var sample = new Sample(request.Name, request.Description);
-
- // EN: Add to repository / VI: Thêm vào repository
- _sampleRepository.Add(sample);
-
- // EN: Save changes (dispatches domain events) / VI: Lưu thay đổi (dispatch domain events)
- await _sampleRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);
-
- _logger.LogInformation(
- "Sample created successfully with ID: {SampleId} / Sample đã tạo thành công với ID: {SampleId}",
- sample.Id);
-
- return new CreateSampleCommandResult(sample.Id);
- }
-}
diff --git a/services/booking-service-net/src/BookingService.API/Application/Commands/DeleteSampleCommand.cs b/services/booking-service-net/src/BookingService.API/Application/Commands/DeleteSampleCommand.cs
deleted file mode 100644
index d99b2340..00000000
--- a/services/booking-service-net/src/BookingService.API/Application/Commands/DeleteSampleCommand.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using MediatR;
-
-namespace BookingService.API.Application.Commands;
-
-///
-/// EN: Command to delete a Sample.
-/// VI: Command để xóa một Sample.
-///
-/// EN: Sample ID to delete / VI: ID sample cần xóa
-public record DeleteSampleCommand(Guid SampleId) : IRequest;
diff --git a/services/booking-service-net/src/BookingService.API/Application/Commands/DeleteSampleCommandHandler.cs b/services/booking-service-net/src/BookingService.API/Application/Commands/DeleteSampleCommandHandler.cs
deleted file mode 100644
index 5f4b6dd8..00000000
--- a/services/booking-service-net/src/BookingService.API/Application/Commands/DeleteSampleCommandHandler.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using MediatR;
-using BookingService.Domain.AggregatesModel.SampleAggregate;
-
-namespace BookingService.API.Application.Commands;
-
-///
-/// EN: Handler for DeleteSampleCommand.
-/// VI: Handler cho DeleteSampleCommand.
-///
-public class DeleteSampleCommandHandler : IRequestHandler
-{
- private readonly ISampleRepository _sampleRepository;
- private readonly ILogger _logger;
-
- public DeleteSampleCommandHandler(
- ISampleRepository sampleRepository,
- ILogger logger)
- {
- _sampleRepository = sampleRepository ?? throw new ArgumentNullException(nameof(sampleRepository));
- _logger = logger ?? throw new ArgumentNullException(nameof(logger));
- }
-
- public async Task Handle(
- DeleteSampleCommand request,
- CancellationToken cancellationToken)
- {
- _logger.LogInformation(
- "Deleting sample {SampleId} / Xóa sample {SampleId}",
- request.SampleId);
-
- // EN: Get existing sample / VI: Lấy sample đã tồn tại
- var sample = await _sampleRepository.GetAsync(request.SampleId);
-
- if (sample is null)
- {
- _logger.LogWarning(
- "Sample {SampleId} not found / Sample {SampleId} không tìm thấy",
- request.SampleId);
- return false;
- }
-
- // EN: Delete sample / VI: Xóa sample
- _sampleRepository.Delete(sample);
-
- // EN: Save changes / VI: Lưu thay đổi
- await _sampleRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);
-
- _logger.LogInformation(
- "Sample {SampleId} deleted successfully / Sample {SampleId} đã xóa thành công",
- request.SampleId);
-
- return true;
- }
-}
diff --git a/services/booking-service-net/src/BookingService.API/Application/Commands/UpdateSampleCommand.cs b/services/booking-service-net/src/BookingService.API/Application/Commands/UpdateSampleCommand.cs
deleted file mode 100644
index bde94f72..00000000
--- a/services/booking-service-net/src/BookingService.API/Application/Commands/UpdateSampleCommand.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using MediatR;
-
-namespace BookingService.API.Application.Commands;
-
-///
-/// EN: Command to update an existing Sample.
-/// VI: Command để cập nhật một Sample đã tồn tại.
-///
-/// EN: Sample ID to update / VI: ID sample cần cập nhật
-/// EN: New name / VI: Tên mới
-/// EN: New description / VI: Mô tả mới
-public record UpdateSampleCommand(
- Guid SampleId,
- string Name,
- string? Description
-) : IRequest;
diff --git a/services/booking-service-net/src/BookingService.API/Application/Commands/UpdateSampleCommandHandler.cs b/services/booking-service-net/src/BookingService.API/Application/Commands/UpdateSampleCommandHandler.cs
deleted file mode 100644
index ebca581c..00000000
--- a/services/booking-service-net/src/BookingService.API/Application/Commands/UpdateSampleCommandHandler.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using MediatR;
-using BookingService.Domain.AggregatesModel.SampleAggregate;
-
-namespace BookingService.API.Application.Commands;
-
-///
-/// EN: Handler for UpdateSampleCommand.
-/// VI: Handler cho UpdateSampleCommand.
-///
-public class UpdateSampleCommandHandler : IRequestHandler
-{
- private readonly ISampleRepository _sampleRepository;
- private readonly ILogger _logger;
-
- public UpdateSampleCommandHandler(
- ISampleRepository sampleRepository,
- ILogger logger)
- {
- _sampleRepository = sampleRepository ?? throw new ArgumentNullException(nameof(sampleRepository));
- _logger = logger ?? throw new ArgumentNullException(nameof(logger));
- }
-
- public async Task Handle(
- UpdateSampleCommand request,
- CancellationToken cancellationToken)
- {
- _logger.LogInformation(
- "Updating sample {SampleId} / Cập nhật sample {SampleId}",
- request.SampleId);
-
- // EN: Get existing sample / VI: Lấy sample đã tồn tại
- var sample = await _sampleRepository.GetAsync(request.SampleId);
-
- if (sample is null)
- {
- _logger.LogWarning(
- "Sample {SampleId} not found / Sample {SampleId} không tìm thấy",
- request.SampleId);
- return false;
- }
-
- // EN: Update sample using domain method / VI: Cập nhật sample sử dụng domain method
- sample.Update(request.Name, request.Description);
-
- // EN: Save changes / VI: Lưu thay đổi
- await _sampleRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);
-
- _logger.LogInformation(
- "Sample {SampleId} updated successfully / Sample {SampleId} đã cập nhật thành công",
- request.SampleId);
-
- return true;
- }
-}
diff --git a/services/booking-service-net/src/BookingService.API/Application/Queries/GetSampleQuery.cs b/services/booking-service-net/src/BookingService.API/Application/Queries/GetSampleQuery.cs
deleted file mode 100644
index 25f31497..00000000
--- a/services/booking-service-net/src/BookingService.API/Application/Queries/GetSampleQuery.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using MediatR;
-
-namespace BookingService.API.Application.Queries;
-
-///
-/// EN: Query to get a Sample by ID.
-/// VI: Query để lấy một Sample theo ID.
-///
-/// EN: Sample ID / VI: ID sample
-public record GetSampleQuery(Guid SampleId) : IRequest;
-
-///
-/// EN: Sample view model for API responses.
-/// VI: Sample view model cho API responses.
-///
-public record SampleViewModel(
- Guid Id,
- string Name,
- string? Description,
- string Status,
- DateTime CreatedAt,
- DateTime? UpdatedAt
-);
diff --git a/services/booking-service-net/src/BookingService.API/Application/Queries/GetSampleQueryHandler.cs b/services/booking-service-net/src/BookingService.API/Application/Queries/GetSampleQueryHandler.cs
deleted file mode 100644
index b1a17658..00000000
--- a/services/booking-service-net/src/BookingService.API/Application/Queries/GetSampleQueryHandler.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using MediatR;
-using BookingService.Domain.AggregatesModel.SampleAggregate;
-
-namespace BookingService.API.Application.Queries;
-
-///
-/// EN: Handler for GetSampleQuery.
-/// VI: Handler cho GetSampleQuery.
-///
-public class GetSampleQueryHandler : IRequestHandler
-{
- private readonly ISampleRepository _sampleRepository;
-
- public GetSampleQueryHandler(ISampleRepository sampleRepository)
- {
- _sampleRepository = sampleRepository ?? throw new ArgumentNullException(nameof(sampleRepository));
- }
-
- public async Task Handle(
- GetSampleQuery request,
- CancellationToken cancellationToken)
- {
- var sample = await _sampleRepository.GetAsync(request.SampleId);
-
- if (sample is null)
- {
- return null;
- }
-
- return new SampleViewModel(
- sample.Id,
- sample.Name,
- sample.Description,
- sample.Status.Name,
- sample.CreatedAt,
- sample.UpdatedAt
- );
- }
-}
diff --git a/services/booking-service-net/src/BookingService.API/Application/Queries/GetSamplesQuery.cs b/services/booking-service-net/src/BookingService.API/Application/Queries/GetSamplesQuery.cs
deleted file mode 100644
index ced4e6ac..00000000
--- a/services/booking-service-net/src/BookingService.API/Application/Queries/GetSamplesQuery.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using MediatR;
-
-namespace BookingService.API.Application.Queries;
-
-///
-/// EN: Query to get all Samples.
-/// VI: Query để lấy tất cả Samples.
-///
-public record GetSamplesQuery : IRequest>;
diff --git a/services/booking-service-net/src/BookingService.API/Application/Queries/GetSamplesQueryHandler.cs b/services/booking-service-net/src/BookingService.API/Application/Queries/GetSamplesQueryHandler.cs
deleted file mode 100644
index dc2515b0..00000000
--- a/services/booking-service-net/src/BookingService.API/Application/Queries/GetSamplesQueryHandler.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using MediatR;
-using BookingService.Domain.AggregatesModel.SampleAggregate;
-
-namespace BookingService.API.Application.Queries;
-
-///
-/// EN: Handler for GetSamplesQuery.
-/// VI: Handler cho GetSamplesQuery.
-///
-public class GetSamplesQueryHandler : IRequestHandler>
-{
- private readonly ISampleRepository _sampleRepository;
-
- public GetSamplesQueryHandler(ISampleRepository sampleRepository)
- {
- _sampleRepository = sampleRepository ?? throw new ArgumentNullException(nameof(sampleRepository));
- }
-
- public async Task> Handle(
- GetSamplesQuery request,
- CancellationToken cancellationToken)
- {
- var samples = await _sampleRepository.GetAllAsync();
-
- return samples.Select(sample => new SampleViewModel(
- sample.Id,
- sample.Name,
- sample.Description,
- sample.Status.Name,
- sample.CreatedAt,
- sample.UpdatedAt
- ));
- }
-}
diff --git a/services/booking-service-net/src/BookingService.API/Application/Validations/CreateSampleCommandValidator.cs b/services/booking-service-net/src/BookingService.API/Application/Validations/CreateSampleCommandValidator.cs
deleted file mode 100644
index a11274b4..00000000
--- a/services/booking-service-net/src/BookingService.API/Application/Validations/CreateSampleCommandValidator.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using FluentValidation;
-using BookingService.API.Application.Commands;
-
-namespace BookingService.API.Application.Validations;
-
-///
-/// EN: Validator for CreateSampleCommand.
-/// VI: Validator cho CreateSampleCommand.
-///
-public class CreateSampleCommandValidator : AbstractValidator
-{
- public CreateSampleCommandValidator()
- {
- RuleFor(x => x.Name)
- .NotEmpty()
- .WithMessage("Name is required / Tên là bắt buộc")
- .MaximumLength(200)
- .WithMessage("Name must be less than 200 characters / Tên phải ít hơn 200 ký tự");
-
- RuleFor(x => x.Description)
- .MaximumLength(1000)
- .WithMessage("Description must be less than 1000 characters / Mô tả phải ít hơn 1000 ký tự")
- .When(x => x.Description != null);
- }
-}
diff --git a/services/booking-service-net/src/BookingService.API/Application/Validations/UpdateSampleCommandValidator.cs b/services/booking-service-net/src/BookingService.API/Application/Validations/UpdateSampleCommandValidator.cs
deleted file mode 100644
index c5be27df..00000000
--- a/services/booking-service-net/src/BookingService.API/Application/Validations/UpdateSampleCommandValidator.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using FluentValidation;
-using BookingService.API.Application.Commands;
-
-namespace BookingService.API.Application.Validations;
-
-///
-/// EN: Validator for UpdateSampleCommand.
-/// VI: Validator cho UpdateSampleCommand.
-///
-public class UpdateSampleCommandValidator : AbstractValidator
-{
- public UpdateSampleCommandValidator()
- {
- RuleFor(x => x.SampleId)
- .NotEmpty()
- .WithMessage("Sample ID is required / ID sample là bắt buộc");
-
- RuleFor(x => x.Name)
- .NotEmpty()
- .WithMessage("Name is required / Tên là bắt buộc")
- .MaximumLength(200)
- .WithMessage("Name must be less than 200 characters / Tên phải ít hơn 200 ký tự");
-
- RuleFor(x => x.Description)
- .MaximumLength(1000)
- .WithMessage("Description must be less than 1000 characters / Mô tả phải ít hơn 1000 ký tự")
- .When(x => x.Description != null);
- }
-}
diff --git a/services/booking-service-net/src/BookingService.API/BookingService.API.csproj b/services/booking-service-net/src/BookingService.API/BookingService.API.csproj
index b5e0f768..4fa3b98c 100644
--- a/services/booking-service-net/src/BookingService.API/BookingService.API.csproj
+++ b/services/booking-service-net/src/BookingService.API/BookingService.API.csproj
@@ -14,6 +14,10 @@
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
diff --git a/services/booking-service-net/src/BookingService.API/Controllers/SamplesController.cs b/services/booking-service-net/src/BookingService.API/Controllers/SamplesController.cs
deleted file mode 100644
index a6c86169..00000000
--- a/services/booking-service-net/src/BookingService.API/Controllers/SamplesController.cs
+++ /dev/null
@@ -1,200 +0,0 @@
-using Asp.Versioning;
-using MediatR;
-using Microsoft.AspNetCore.Mvc;
-using BookingService.API.Application.Commands;
-using BookingService.API.Application.Queries;
-
-namespace BookingService.API.Controllers;
-
-///
-/// EN: Controller for Sample CRUD operations using CQRS pattern.
-/// VI: Controller cho các thao tác CRUD Sample sử dụng pattern CQRS.
-///
-[ApiController]
-[ApiVersion("1.0")]
-[Route("api/v{version:apiVersion}/[controller]")]
-[Produces("application/json")]
-public class SamplesController : ControllerBase
-{
- private readonly IMediator _mediator;
- private readonly ILogger _logger;
-
- public SamplesController(IMediator mediator, ILogger logger)
- {
- _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
- _logger = logger ?? throw new ArgumentNullException(nameof(logger));
- }
-
- ///
- /// EN: Get all samples.
- /// VI: Lấy tất cả samples.
- ///
- /// EN: List of samples / VI: Danh sách samples
- [HttpGet]
- [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)]
- public async Task GetSamples()
- {
- var samples = await _mediator.Send(new GetSamplesQuery());
- return Ok(new { success = true, data = samples });
- }
-
- ///
- /// EN: Get a sample by ID.
- /// VI: Lấy một sample theo ID.
- ///
- /// EN: Sample ID / VI: ID sample
- /// EN: Sample details / VI: Chi tiết sample
- [HttpGet("{id:guid}")]
- [ProducesResponseType(typeof(SampleViewModel), StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status404NotFound)]
- public async Task GetSample(Guid id)
- {
- var sample = await _mediator.Send(new GetSampleQuery(id));
-
- if (sample is null)
- {
- return NotFound(new
- {
- success = false,
- error = new
- {
- code = "SAMPLE_NOT_FOUND",
- message = $"Sample with ID {id} not found / Sample với ID {id} không tìm thấy"
- }
- });
- }
-
- return Ok(new { success = true, data = sample });
- }
-
- ///
- /// EN: Create a new sample.
- /// VI: Tạo một sample mới.
- ///
- /// EN: Create request / VI: Request tạo
- /// EN: Created sample ID / VI: ID sample đã tạo
- [HttpPost]
- [ProducesResponseType(typeof(CreateSampleCommandResult), StatusCodes.Status201Created)]
- [ProducesResponseType(StatusCodes.Status400BadRequest)]
- public async Task CreateSample([FromBody] CreateSampleRequest request)
- {
- var command = new CreateSampleCommand(request.Name, request.Description);
- var result = await _mediator.Send(command);
-
- return CreatedAtAction(
- nameof(GetSample),
- new { id = result.Id },
- new { success = true, data = result });
- }
-
- ///
- /// EN: Update an existing sample.
- /// VI: Cập nhật một sample đã tồn tại.
- ///
- /// EN: Sample ID / VI: ID sample
- /// EN: Update request / VI: Request cập nhật
- /// EN: Success status / VI: Trạng thái thành công
- [HttpPut("{id:guid}")]
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status404NotFound)]
- public async Task UpdateSample(Guid id, [FromBody] UpdateSampleRequest request)
- {
- var command = new UpdateSampleCommand(id, request.Name, request.Description);
- var result = await _mediator.Send(command);
-
- if (!result)
- {
- return NotFound(new
- {
- success = false,
- error = new
- {
- code = "SAMPLE_NOT_FOUND",
- message = $"Sample with ID {id} not found / Sample với ID {id} không tìm thấy"
- }
- });
- }
-
- return Ok(new { success = true, message = "Sample updated successfully / Sample đã cập nhật thành công" });
- }
-
- ///
- /// EN: Delete a sample.
- /// VI: Xóa một sample.
- ///
- /// EN: Sample ID / VI: ID sample
- /// EN: Success status / VI: Trạng thái thành công
- [HttpDelete("{id:guid}")]
- [ProducesResponseType(StatusCodes.Status204NoContent)]
- [ProducesResponseType(StatusCodes.Status404NotFound)]
- public async Task DeleteSample(Guid id)
- {
- var command = new DeleteSampleCommand(id);
- var result = await _mediator.Send(command);
-
- if (!result)
- {
- return NotFound(new
- {
- success = false,
- error = new
- {
- code = "SAMPLE_NOT_FOUND",
- message = $"Sample with ID {id} not found / Sample với ID {id} không tìm thấy"
- }
- });
- }
-
- return NoContent();
- }
-
- ///
- /// EN: Change sample status.
- /// VI: Thay đổi trạng thái sample.
- ///
- /// EN: Sample ID / VI: ID sample
- /// EN: Status change request / VI: Request thay đổi trạng thái
- /// EN: Success status / VI: Trạng thái thành công
- [HttpPatch("{id:guid}/status")]
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status400BadRequest)]
- [ProducesResponseType(StatusCodes.Status404NotFound)]
- public async Task ChangeSampleStatus(Guid id, [FromBody] ChangeStatusRequest request)
- {
- var command = new ChangeSampleStatusCommand(id, request.Status);
- var result = await _mediator.Send(command);
-
- if (!result)
- {
- return BadRequest(new
- {
- success = false,
- error = new
- {
- code = "STATUS_CHANGE_FAILED",
- message = "Failed to change sample status / Thay đổi trạng thái sample thất bại"
- }
- });
- }
-
- return Ok(new { success = true, message = "Sample status changed successfully / Trạng thái sample đã thay đổi thành công" });
- }
-}
-
-///
-/// EN: Request model for creating a sample.
-/// VI: Model request để tạo sample.
-///
-public record CreateSampleRequest(string Name, string? Description);
-
-///
-/// EN: Request model for updating a sample.
-/// VI: Model request để cập nhật sample.
-///
-public record UpdateSampleRequest(string Name, string? Description);
-
-///
-/// EN: Request model for changing sample status.
-/// VI: Model request để thay đổi trạng thái sample.
-///
-public record ChangeStatusRequest(string Status);
diff --git a/services/booking-service-net/src/BookingService.Domain/AggregatesModel/SampleAggregate/ISampleRepository.cs b/services/booking-service-net/src/BookingService.Domain/AggregatesModel/SampleAggregate/ISampleRepository.cs
deleted file mode 100644
index b9b72f64..00000000
--- a/services/booking-service-net/src/BookingService.Domain/AggregatesModel/SampleAggregate/ISampleRepository.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using BookingService.Domain.SeedWork;
-
-namespace BookingService.Domain.AggregatesModel.SampleAggregate;
-
-///
-/// EN: Repository interface for Sample aggregate.
-/// VI: Interface repository cho Sample aggregate.
-///
-///
-/// EN: Following repository pattern, this interface defines the contract
-/// for data access operations on Sample aggregate.
-/// VI: Theo pattern repository, interface này định nghĩa contract
-/// cho các thao tác truy cập dữ liệu trên Sample aggregate.
-///
-public interface ISampleRepository : IRepository
-{
- ///
- /// EN: Get a sample by its ID.
- /// VI: Lấy một sample theo ID.
- ///
- /// EN: The sample ID / VI: ID của sample
- /// EN: The sample or null if not found / VI: Sample hoặc null nếu không tìm thấy
- Task GetAsync(Guid sampleId);
-
- ///
- /// EN: Get all samples.
- /// VI: Lấy tất cả samples.
- ///
- /// EN: List of samples / VI: Danh sách samples
- Task> GetAllAsync();
-
- ///
- /// EN: Add a new sample.
- /// VI: Thêm một sample mới.
- ///
- /// EN: The sample to add / VI: Sample cần thêm
- /// EN: The added sample / VI: Sample đã thêm
- Sample Add(Sample sample);
-
- ///
- /// EN: Update an existing sample.
- /// VI: Cập nhật một sample đã tồn tại.
- ///
- /// EN: The sample to update / VI: Sample cần cập nhật
- void Update(Sample sample);
-
- ///
- /// EN: Delete a sample.
- /// VI: Xóa một sample.
- ///
- /// EN: The sample to delete / VI: Sample cần xóa
- void Delete(Sample sample);
-
- ///
- /// EN: Get samples by status.
- /// VI: Lấy samples theo trạng thái.
- ///
- /// EN: The status ID / VI: ID trạng thái
- /// EN: List of samples with given status / VI: Danh sách samples với trạng thái cho trước
- Task> GetByStatusAsync(int statusId);
-}
diff --git a/services/booking-service-net/src/BookingService.Domain/AggregatesModel/SampleAggregate/Sample.cs b/services/booking-service-net/src/BookingService.Domain/AggregatesModel/SampleAggregate/Sample.cs
deleted file mode 100644
index fe5e327f..00000000
--- a/services/booking-service-net/src/BookingService.Domain/AggregatesModel/SampleAggregate/Sample.cs
+++ /dev/null
@@ -1,158 +0,0 @@
-using BookingService.Domain.Events;
-using BookingService.Domain.Exceptions;
-using BookingService.Domain.SeedWork;
-
-namespace BookingService.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));
- }
-}
diff --git a/services/booking-service-net/src/BookingService.Domain/AggregatesModel/SampleAggregate/SampleStatus.cs b/services/booking-service-net/src/BookingService.Domain/AggregatesModel/SampleAggregate/SampleStatus.cs
deleted file mode 100644
index 03304826..00000000
--- a/services/booking-service-net/src/BookingService.Domain/AggregatesModel/SampleAggregate/SampleStatus.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using BookingService.Domain.SeedWork;
-
-namespace BookingService.Domain.AggregatesModel.SampleAggregate;
-
-///
-/// EN: Sample status enumeration following type-safe enum pattern.
-/// VI: Enumeration trạng thái Sample theo pattern enum an toàn kiểu.
-///
-public class SampleStatus : Enumeration
-{
- ///
- /// EN: Draft status - initial state
- /// VI: Trạng thái nháp - trạng thái ban đầu
- ///
- public static SampleStatus Draft = new(1, nameof(Draft));
-
- ///
- /// EN: Active status - ready for use
- /// VI: Trạng thái hoạt động - sẵn sàng sử dụng
- ///
- public static SampleStatus Active = new(2, nameof(Active));
-
- ///
- /// EN: Completed status - finished processing
- /// VI: Trạng thái hoàn thành - đã xử lý xong
- ///
- public static SampleStatus Completed = new(3, nameof(Completed));
-
- ///
- /// EN: Cancelled status - cancelled by user
- /// VI: Trạng thái đã hủy - bị hủy bởi người dùng
- ///
- public static SampleStatus Cancelled = new(4, nameof(Cancelled));
-
- public SampleStatus(int id, string name) : base(id, name)
- {
- }
-
- ///
- /// EN: Get all available statuses.
- /// VI: Lấy tất cả các trạng thái có sẵn.
- ///
- public static IEnumerable List() => GetAll();
-
- ///
- /// EN: Parse status from name.
- /// VI: Parse trạng thái từ tên.
- ///
- public static SampleStatus FromName(string name)
- {
- var status = List().SingleOrDefault(s =>
- string.Equals(s.Name, name, StringComparison.CurrentCultureIgnoreCase));
-
- if (status is null)
- {
- throw new ArgumentException($"Possible values for SampleStatus: {string.Join(",", List().Select(s => s.Name))}");
- }
-
- return status;
- }
-
- ///
- /// EN: Parse status from ID.
- /// VI: Parse trạng thái từ ID.
- ///
- public static SampleStatus From(int id)
- {
- var status = List().SingleOrDefault(s => s.Id == id);
-
- if (status is null)
- {
- throw new ArgumentException($"Possible values for SampleStatus: {string.Join(",", List().Select(s => s.Name))}");
- }
-
- return status;
- }
-}
diff --git a/services/booking-service-net/src/BookingService.Domain/Events/SampleCreatedDomainEvent.cs b/services/booking-service-net/src/BookingService.Domain/Events/SampleCreatedDomainEvent.cs
deleted file mode 100644
index 127044cf..00000000
--- a/services/booking-service-net/src/BookingService.Domain/Events/SampleCreatedDomainEvent.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using MediatR;
-using BookingService.Domain.AggregatesModel.SampleAggregate;
-
-namespace BookingService.Domain.Events;
-
-///
-/// EN: Domain event raised when a new Sample is created.
-/// VI: Domain event được phát ra khi một Sample mới được tạo.
-///
-public class SampleCreatedDomainEvent : INotification
-{
- ///
- /// EN: The newly created sample.
- /// VI: Sample mới được tạo.
- ///
- public Sample Sample { get; }
-
- public SampleCreatedDomainEvent(Sample sample)
- {
- Sample = sample;
- }
-}
diff --git a/services/booking-service-net/src/BookingService.Domain/Events/SampleStatusChangedDomainEvent.cs b/services/booking-service-net/src/BookingService.Domain/Events/SampleStatusChangedDomainEvent.cs
deleted file mode 100644
index a51f62f4..00000000
--- a/services/booking-service-net/src/BookingService.Domain/Events/SampleStatusChangedDomainEvent.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using MediatR;
-using BookingService.Domain.AggregatesModel.SampleAggregate;
-
-namespace BookingService.Domain.Events;
-
-///
-/// EN: Domain event raised when Sample status changes.
-/// VI: Domain event được phát ra khi trạng thái Sample thay đổi.
-///
-public class SampleStatusChangedDomainEvent : INotification
-{
- ///
- /// EN: The sample ID.
- /// VI: ID của sample.
- ///
- public Guid SampleId { get; }
-
- ///
- /// EN: Previous status before the change.
- /// VI: Trạng thái trước khi thay đổi.
- ///
- public SampleStatus PreviousStatus { get; }
-
- ///
- /// EN: New status after the change.
- /// VI: Trạng thái mới sau khi thay đổi.
- ///
- public SampleStatus NewStatus { get; }
-
- public SampleStatusChangedDomainEvent(
- Guid sampleId,
- SampleStatus previousStatus,
- SampleStatus newStatus)
- {
- SampleId = sampleId;
- PreviousStatus = previousStatus;
- NewStatus = newStatus;
- }
-}
diff --git a/services/booking-service-net/src/BookingService.Domain/Exceptions/SampleDomainException.cs b/services/booking-service-net/src/BookingService.Domain/Exceptions/SampleDomainException.cs
deleted file mode 100644
index 5397122d..00000000
--- a/services/booking-service-net/src/BookingService.Domain/Exceptions/SampleDomainException.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-namespace BookingService.Domain.Exceptions;
-
-///
-/// EN: Exception for Sample aggregate domain errors.
-/// VI: Exception cho các lỗi domain của Sample aggregate.
-///
-public class SampleDomainException : DomainException
-{
- public SampleDomainException()
- {
- }
-
- public SampleDomainException(string message) : base(message)
- {
- }
-
- public SampleDomainException(string message, Exception innerException)
- : base(message, innerException)
- {
- }
-}
diff --git a/services/booking-service-net/src/BookingService.Infrastructure/BookingContext.cs b/services/booking-service-net/src/BookingService.Infrastructure/BookingContext.cs
new file mode 100644
index 00000000..5cb2fb43
--- /dev/null
+++ b/services/booking-service-net/src/BookingService.Infrastructure/BookingContext.cs
@@ -0,0 +1,66 @@
+using MediatR;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Storage;
+using BookingService.Domain.AggregatesModel.AppointmentAggregate;
+using BookingService.Domain.SeedWork;
+using BookingService.Infrastructure.EntityConfigurations;
+
+namespace BookingService.Infrastructure;
+
+public class BookingContext : DbContext, IUnitOfWork
+{
+ private readonly IMediator _mediator;
+ private IDbContextTransaction? _currentTransaction;
+
+ public DbSet Appointments => Set();
+ public IDbContextTransaction? CurrentTransaction => _currentTransaction;
+ public bool HasActiveTransaction => _currentTransaction != null;
+
+ public BookingContext(DbContextOptions options, IMediator mediator) : base(options)
+ {
+ _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
+ }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ modelBuilder.ApplyConfiguration(new AppointmentEntityTypeConfiguration());
+ modelBuilder.ApplyConfiguration(new AppointmentStatusEntityTypeConfiguration());
+ }
+
+ public async Task SaveEntitiesAsync(CancellationToken cancellationToken = default)
+ {
+ await DispatchDomainEventsAsync();
+ await base.SaveChangesAsync(cancellationToken);
+ return true;
+ }
+
+ public async Task BeginTransactionAsync()
+ {
+ if (_currentTransaction != null) return null;
+ _currentTransaction = await Database.BeginTransactionAsync(System.Data.IsolationLevel.ReadCommitted);
+ return _currentTransaction;
+ }
+
+ public async Task CommitTransactionAsync(IDbContextTransaction transaction)
+ {
+ ArgumentNullException.ThrowIfNull(transaction);
+ if (transaction != _currentTransaction) throw new InvalidOperationException($"Transaction {transaction.TransactionId} is not current");
+ try { await SaveChangesAsync(); await transaction.CommitAsync(); }
+ catch { RollbackTransaction(); throw; }
+ finally { if (_currentTransaction != null) { _currentTransaction.Dispose(); _currentTransaction = null; } }
+ }
+
+ public void RollbackTransaction()
+ {
+ try { _currentTransaction?.Rollback(); }
+ finally { if (_currentTransaction != null) { _currentTransaction.Dispose(); _currentTransaction = null; } }
+ }
+
+ private async Task DispatchDomainEventsAsync()
+ {
+ var domainEntities = ChangeTracker.Entries().Where(x => x.Entity.DomainEvents.Any()).ToList();
+ var domainEvents = domainEntities.SelectMany(x => x.Entity.DomainEvents).ToList();
+ domainEntities.ForEach(entity => entity.Entity.ClearDomainEvents());
+ foreach (var domainEvent in domainEvents) await _mediator.Publish(domainEvent);
+ }
+}
diff --git a/services/booking-service-net/src/BookingService.Infrastructure/DependencyInjection.cs b/services/booking-service-net/src/BookingService.Infrastructure/DependencyInjection.cs
index 17c88958..2fcf7edb 100644
--- a/services/booking-service-net/src/BookingService.Infrastructure/DependencyInjection.cs
+++ b/services/booking-service-net/src/BookingService.Infrastructure/DependencyInjection.cs
@@ -1,7 +1,7 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
-using BookingService.Domain.AggregatesModel.SampleAggregate;
+using BookingService.Domain.AggregatesModel.AppointmentAggregate;
using BookingService.Infrastructure.Idempotency;
using BookingService.Infrastructure.Repositories;
diff --git a/services/booking-service-net/src/BookingService.Infrastructure/Entity Configurations/AppointmentEntityTypeConfiguration.cs b/services/booking-service-net/src/BookingService.Infrastructure/Entity Configurations/AppointmentEntityTypeConfiguration.cs
new file mode 100644
index 00000000..b4bf2c30
--- /dev/null
+++ b/services/booking-service-net/src/BookingService.Infrastructure/Entity Configurations/AppointmentEntityTypeConfiguration.cs
@@ -0,0 +1,38 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+using BookingService.Domain.AggregatesModel.AppointmentAggregate;
+
+namespace BookingService.Infrastructure.EntityConfigurations;
+
+public class AppointmentEntityTypeConfiguration : IEntityTypeConfiguration
+{
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.ToTable("appointments");
+ builder.HasKey(a => a.Id);
+ builder.Property(a => a.Id).HasColumnName("id").ValueGeneratedNever();
+ builder.Property("_shopId").HasColumnName("shop_id").IsRequired();
+ builder.Property("_customerId").HasColumnName("customer_id").IsRequired();
+ builder.Property("_serviceId").HasColumnName("service_id").IsRequired();
+ builder.Property(a => a.StatusId).HasColumnName("status_id").IsRequired();
+ builder.Property("_scheduledAt").HasColumnName("scheduled_at").IsRequired();
+ builder.Property("_durationMinutes").HasColumnName("duration_minutes").IsRequired();
+ builder.Property("_staffId").HasColumnName("staff_id");
+ builder.Property("_resourceId").HasColumnName("resource_id");
+ builder.Property("_notes").HasColumnName("notes").HasMaxLength(1000);
+
+ builder.HasIndex("_shopId").HasDatabaseName("ix_appointments_shop_id");
+ builder.HasIndex("_customerId").HasDatabaseName("ix_appointments_customer_id");
+ builder.HasIndex("_scheduledAt").HasDatabaseName("ix_appointments_scheduled_at");
+
+ builder.Ignore(a => a.ShopId);
+ builder.Ignore(a => a.CustomerId);
+ builder.Ignore(a => a.ServiceId);
+ builder.Ignore(a => a.Status);
+ builder.Ignore(a => a.ScheduledAt);
+ builder.Ignore(a => a.DurationMinutes);
+ builder.Ignore(a => a.StaffId);
+ builder.Ignore(a => a.ResourceId);
+ builder.Ignore(a => a.Notes);
+ }
+}
diff --git a/services/booking-service-net/src/BookingService.Infrastructure/EntityConfigurations/AppointmentStatusEntityTypeConfiguration.cs b/services/booking-service-net/src/BookingService.Infrastructure/EntityConfigurations/AppointmentStatusEntityTypeConfiguration.cs
new file mode 100644
index 00000000..2b4f661f
--- /dev/null
+++ b/services/booking-service-net/src/BookingService.Infrastructure/EntityConfigurations/AppointmentStatusEntityTypeConfiguration.cs
@@ -0,0 +1,24 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+using BookingService.Domain.AggregatesModel.AppointmentAggregate;
+
+namespace BookingService.Infrastructure.EntityConfigurations;
+
+public class AppointmentStatusEntityTypeConfiguration : IEntityTypeConfiguration
+{
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.ToTable("appointment_statuses");
+ builder.HasKey(s => s.Id);
+ builder.Property(s => s.Id).HasColumnName("id").ValueGeneratedNever();
+ builder.Property(s => s.Name).HasColumnName("name").HasMaxLength(50).IsRequired();
+ builder.HasData(
+ AppointmentStatus.Pending,
+ AppointmentStatus.Confirmed,
+ AppointmentStatus.InProgress,
+ AppointmentStatus.Completed,
+ AppointmentStatus.Cancelled,
+ AppointmentStatus.NoShow
+ );
+ }
+}
diff --git a/services/booking-service-net/src/BookingService.Infrastructure/EntityConfigurations/SampleEntityTypeConfiguration.cs b/services/booking-service-net/src/BookingService.Infrastructure/EntityConfigurations/SampleEntityTypeConfiguration.cs
deleted file mode 100644
index c0e0dae6..00000000
--- a/services/booking-service-net/src/BookingService.Infrastructure/EntityConfigurations/SampleEntityTypeConfiguration.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Metadata.Builders;
-using BookingService.Domain.AggregatesModel.SampleAggregate;
-
-namespace BookingService.Infrastructure.EntityConfigurations;
-
-///
-/// EN: EF Core configuration for Sample entity.
-/// VI: Cấu hình EF Core cho entity Sample.
-///
-public class SampleEntityTypeConfiguration : IEntityTypeConfiguration
-{
- public void Configure(EntityTypeBuilder builder)
- {
- // EN: Table name / VI: Tên bảng
- builder.ToTable("samples");
-
- // EN: Primary key / VI: Khóa chính
- builder.HasKey(s => s.Id);
-
- // EN: Ignore domain events (not persisted)
- // VI: Bỏ qua domain events (không lưu)
- builder.Ignore(s => s.DomainEvents);
-
- // EN: Properties / VI: Các thuộc tính
- builder.Property(s => s.Id)
- .HasColumnName("id")
- .IsRequired();
-
- builder.Property("_name")
- .HasColumnName("name")
- .HasMaxLength(200)
- .IsRequired();
-
- builder.Property("_description")
- .HasColumnName("description")
- .HasMaxLength(1000);
-
- builder.Property("_createdAt")
- .HasColumnName("created_at")
- .IsRequired();
-
- builder.Property("_updatedAt")
- .HasColumnName("updated_at");
-
- // EN: Status relationship / VI: Quan hệ với Status
- builder.Property(s => s.StatusId)
- .HasColumnName("status_id")
- .IsRequired();
-
- builder.HasOne(s => s.Status)
- .WithMany()
- .HasForeignKey(s => s.StatusId)
- .OnDelete(DeleteBehavior.Restrict);
-
- // EN: Indexes / VI: Các index
- builder.HasIndex("_name");
- builder.HasIndex(s => s.StatusId);
- builder.HasIndex("_createdAt");
- }
-}
diff --git a/services/booking-service-net/src/BookingService.Infrastructure/EntityConfigurations/SampleStatusEntityTypeConfiguration.cs b/services/booking-service-net/src/BookingService.Infrastructure/EntityConfigurations/SampleStatusEntityTypeConfiguration.cs
deleted file mode 100644
index 28ed123b..00000000
--- a/services/booking-service-net/src/BookingService.Infrastructure/EntityConfigurations/SampleStatusEntityTypeConfiguration.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Metadata.Builders;
-using BookingService.Domain.AggregatesModel.SampleAggregate;
-
-namespace BookingService.Infrastructure.EntityConfigurations;
-
-///
-/// EN: EF Core configuration for SampleStatus enumeration.
-/// VI: Cấu hình EF Core cho enumeration SampleStatus.
-///
-public class SampleStatusEntityTypeConfiguration : IEntityTypeConfiguration
-{
- public void Configure(EntityTypeBuilder builder)
- {
- // EN: Table name / VI: Tên bảng
- builder.ToTable("sample_statuses");
-
- // EN: Primary key / VI: Khóa chính
- builder.HasKey(s => s.Id);
-
- builder.Property(s => s.Id)
- .HasColumnName("id")
- .ValueGeneratedNever()
- .IsRequired();
-
- builder.Property(s => s.Name)
- .HasColumnName("name")
- .HasMaxLength(50)
- .IsRequired();
-
- // EN: Seed initial data / VI: Seed dữ liệu ban đầu
- builder.HasData(
- SampleStatus.Draft,
- SampleStatus.Active,
- SampleStatus.Completed,
- SampleStatus.Cancelled
- );
- }
-}
diff --git a/services/booking-service-net/src/BookingService.Infrastructure/MyServiceContext.cs b/services/booking-service-net/src/BookingService.Infrastructure/MyServiceContext.cs
deleted file mode 100644
index df42730a..00000000
--- a/services/booking-service-net/src/BookingService.Infrastructure/MyServiceContext.cs
+++ /dev/null
@@ -1,160 +0,0 @@
-using MediatR;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Storage;
-using BookingService.Domain.AggregatesModel.SampleAggregate;
-using BookingService.Domain.SeedWork;
-using BookingService.Infrastructure.EntityConfigurations;
-
-namespace BookingService.Infrastructure;
-
-///
-/// EN: EF Core DbContext for BookingService.
-/// VI: EF Core DbContext cho BookingService.
-///
-public class BookingServiceContext : DbContext, IUnitOfWork
-{
- private readonly IMediator _mediator;
- private IDbContextTransaction? _currentTransaction;
-
- ///
- /// EN: Samples table.
- /// VI: Bảng Samples.
- ///
- public DbSet Samples => Set();
-
- ///
- /// EN: Read-only access to current transaction.
- /// VI: Truy cập chỉ đọc đến transaction hiện tại.
- ///
- public IDbContextTransaction? CurrentTransaction => _currentTransaction;
-
- ///
- /// EN: Check if there is an active transaction.
- /// VI: Kiểm tra xem có transaction đang hoạt động không.
- ///
- public bool HasActiveTransaction => _currentTransaction != null;
-
- public BookingServiceContext(DbContextOptions options) : base(options)
- {
- _mediator = null!;
- }
-
- public BookingServiceContext(DbContextOptions options, IMediator mediator) : base(options)
- {
- _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
-
- System.Diagnostics.Debug.WriteLine("BookingServiceContext::ctor - " + GetHashCode());
- }
-
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- // EN: Apply entity configurations
- // VI: Áp dụng các cấu hình entity
- modelBuilder.ApplyConfiguration(new SampleEntityTypeConfiguration());
- modelBuilder.ApplyConfiguration(new SampleStatusEntityTypeConfiguration());
- }
-
- ///
- /// EN: Save entities and dispatch domain events.
- /// VI: Lưu entities và dispatch domain events.
- ///
- public async Task SaveEntitiesAsync(CancellationToken cancellationToken = default)
- {
- // EN: Dispatch domain events before saving (side effects)
- // VI: Dispatch domain events trước khi lưu (side effects)
- await DispatchDomainEventsAsync();
-
- // EN: Save changes to database
- // VI: Lưu thay đổi vào database
- await base.SaveChangesAsync(cancellationToken);
-
- return true;
- }
-
- ///
- /// EN: Begin a new transaction if none is active.
- /// VI: Bắt đầu một transaction mới nếu không có transaction nào đang hoạt động.
- ///
- public async Task BeginTransactionAsync()
- {
- if (_currentTransaction != null) return null;
-
- _currentTransaction = await Database.BeginTransactionAsync(System.Data.IsolationLevel.ReadCommitted);
-
- return _currentTransaction;
- }
-
- ///
- /// EN: Commit the current transaction.
- /// VI: Commit transaction hiện tại.
- ///
- public async Task CommitTransactionAsync(IDbContextTransaction transaction)
- {
- ArgumentNullException.ThrowIfNull(transaction);
-
- if (transaction != _currentTransaction)
- throw new InvalidOperationException($"Transaction {transaction.TransactionId} is not current");
-
- try
- {
- await SaveChangesAsync();
- await transaction.CommitAsync();
- }
- catch
- {
- RollbackTransaction();
- throw;
- }
- finally
- {
- if (_currentTransaction != null)
- {
- _currentTransaction.Dispose();
- _currentTransaction = null;
- }
- }
- }
-
- ///
- /// EN: Rollback the current transaction.
- /// VI: Rollback transaction hiện tại.
- ///
- public void RollbackTransaction()
- {
- try
- {
- _currentTransaction?.Rollback();
- }
- finally
- {
- if (_currentTransaction != null)
- {
- _currentTransaction.Dispose();
- _currentTransaction = null;
- }
- }
- }
-
- ///
- /// EN: Dispatch all domain events from tracked entities.
- /// VI: Dispatch tất cả domain events từ các entities đang được track.
- ///
- private async Task DispatchDomainEventsAsync()
- {
- var domainEntities = ChangeTracker
- .Entries()
- .Where(x => x.Entity.DomainEvents.Any())
- .ToList();
-
- var domainEvents = domainEntities
- .SelectMany(x => x.Entity.DomainEvents)
- .ToList();
-
- domainEntities.ForEach(entity => entity.Entity.ClearDomainEvents());
-
- foreach (var domainEvent in domainEvents)
- {
- await _mediator.Publish(domainEvent);
- }
- }
-}
diff --git a/services/booking-service-net/src/BookingService.Infrastructure/Repositories/SampleRepository.cs b/services/booking-service-net/src/BookingService.Infrastructure/Repositories/SampleRepository.cs
deleted file mode 100644
index f880bb59..00000000
--- a/services/booking-service-net/src/BookingService.Infrastructure/Repositories/SampleRepository.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-using Microsoft.EntityFrameworkCore;
-using BookingService.Domain.AggregatesModel.SampleAggregate;
-using BookingService.Domain.SeedWork;
-
-namespace BookingService.Infrastructure.Repositories;
-
-///
-/// EN: Repository implementation for Sample aggregate.
-/// VI: Triển khai repository cho Sample aggregate.
-///
-public class SampleRepository : ISampleRepository
-{
- private readonly BookingServiceContext _context;
-
- ///
- /// EN: Unit of work for transaction management.
- /// VI: Unit of work cho quản lý transaction.
- ///
- public IUnitOfWork UnitOfWork => _context;
-
- public SampleRepository(BookingServiceContext context)
- {
- _context = context ?? throw new ArgumentNullException(nameof(context));
- }
-
- ///
- public async Task GetAsync(Guid sampleId)
- {
- var sample = await _context.Samples
- .Include(s => s.Status)
- .FirstOrDefaultAsync(s => s.Id == sampleId);
-
- return sample;
- }
-
- ///
- public async Task> GetAllAsync()
- {
- return await _context.Samples
- .Include(s => s.Status)
- .OrderByDescending(s => s.CreatedAt)
- .ToListAsync();
- }
-
- ///
- public Sample Add(Sample sample)
- {
- return _context.Samples.Add(sample).Entity;
- }
-
- ///
- public void Update(Sample sample)
- {
- _context.Entry(sample).State = EntityState.Modified;
- }
-
- ///
- public void Delete(Sample sample)
- {
- _context.Samples.Remove(sample);
- }
-
- ///
- public async Task> GetByStatusAsync(int statusId)
- {
- return await _context.Samples
- .Include(s => s.Status)
- .Where(s => s.StatusId == statusId)
- .OrderByDescending(s => s.CreatedAt)
- .ToListAsync();
- }
-}
diff --git a/services/fnb-engine-net/src/FnbEngine.Domain/AggregatesModel/SampleAggregate/ISampleRepository.cs b/services/fnb-engine-net/src/FnbEngine.Domain/AggregatesModel/SampleAggregate/ISampleRepository.cs
deleted file mode 100644
index 10e7d359..00000000
--- a/services/fnb-engine-net/src/FnbEngine.Domain/AggregatesModel/SampleAggregate/ISampleRepository.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using FnbEngine.Domain.SeedWork;
-
-namespace FnbEngine.Domain.AggregatesModel.SampleAggregate;
-
-///
-/// EN: Repository interface for Sample aggregate.
-/// VI: Interface repository cho Sample aggregate.
-///
-///
-/// EN: Following repository pattern, this interface defines the contract
-/// for data access operations on Sample aggregate.
-/// VI: Theo pattern repository, interface này định nghĩa contract
-/// cho các thao tác truy cập dữ liệu trên Sample aggregate.
-///
-public interface ISampleRepository : IRepository
-{
- ///
- /// EN: Get a sample by its ID.
- /// VI: Lấy một sample theo ID.
- ///
- /// EN: The sample ID / VI: ID của sample
- /// EN: The sample or null if not found / VI: Sample hoặc null nếu không tìm thấy
- Task GetAsync(Guid sampleId);
-
- ///
- /// EN: Get all samples.
- /// VI: Lấy tất cả samples.
- ///
- /// EN: List of samples / VI: Danh sách samples
- Task> GetAllAsync();
-
- ///
- /// EN: Add a new sample.
- /// VI: Thêm một sample mới.
- ///
- /// EN: The sample to add / VI: Sample cần thêm
- /// EN: The added sample / VI: Sample đã thêm
- Sample Add(Sample sample);
-
- ///
- /// EN: Update an existing sample.
- /// VI: Cập nhật một sample đã tồn tại.
- ///
- /// EN: The sample to update / VI: Sample cần cập nhật
- void Update(Sample sample);
-
- ///
- /// EN: Delete a sample.
- /// VI: Xóa một sample.
- ///
- /// EN: The sample to delete / VI: Sample cần xóa
- void Delete(Sample sample);
-
- ///
- /// EN: Get samples by status.
- /// VI: Lấy samples theo trạng thái.
- ///
- /// EN: The status ID / VI: ID trạng thái
- /// EN: List of samples with given status / VI: Danh sách samples với trạng thái cho trước
- Task> GetByStatusAsync(int statusId);
-}
diff --git a/services/fnb-engine-net/src/FnbEngine.Domain/AggregatesModel/SampleAggregate/Sample.cs b/services/fnb-engine-net/src/FnbEngine.Domain/AggregatesModel/SampleAggregate/Sample.cs
deleted file mode 100644
index bbca3285..00000000
--- a/services/fnb-engine-net/src/FnbEngine.Domain/AggregatesModel/SampleAggregate/Sample.cs
+++ /dev/null
@@ -1,158 +0,0 @@
-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));
- }
-}
diff --git a/services/fnb-engine-net/src/FnbEngine.Domain/AggregatesModel/SampleAggregate/SampleStatus.cs b/services/fnb-engine-net/src/FnbEngine.Domain/AggregatesModel/SampleAggregate/SampleStatus.cs
deleted file mode 100644
index fcde41cf..00000000
--- a/services/fnb-engine-net/src/FnbEngine.Domain/AggregatesModel/SampleAggregate/SampleStatus.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using FnbEngine.Domain.SeedWork;
-
-namespace FnbEngine.Domain.AggregatesModel.SampleAggregate;
-
-///
-/// EN: Sample status enumeration following type-safe enum pattern.
-/// VI: Enumeration trạng thái Sample theo pattern enum an toàn kiểu.
-///
-public class SampleStatus : Enumeration
-{
- ///
- /// EN: Draft status - initial state
- /// VI: Trạng thái nháp - trạng thái ban đầu
- ///
- public static SampleStatus Draft = new(1, nameof(Draft));
-
- ///
- /// EN: Active status - ready for use
- /// VI: Trạng thái hoạt động - sẵn sàng sử dụng
- ///
- public static SampleStatus Active = new(2, nameof(Active));
-
- ///
- /// EN: Completed status - finished processing
- /// VI: Trạng thái hoàn thành - đã xử lý xong
- ///
- public static SampleStatus Completed = new(3, nameof(Completed));
-
- ///
- /// EN: Cancelled status - cancelled by user
- /// VI: Trạng thái đã hủy - bị hủy bởi người dùng
- ///
- public static SampleStatus Cancelled = new(4, nameof(Cancelled));
-
- public SampleStatus(int id, string name) : base(id, name)
- {
- }
-
- ///
- /// EN: Get all available statuses.
- /// VI: Lấy tất cả các trạng thái có sẵn.
- ///
- public static IEnumerable List() => GetAll();
-
- ///
- /// EN: Parse status from name.
- /// VI: Parse trạng thái từ tên.
- ///
- public static SampleStatus FromName(string name)
- {
- var status = List().SingleOrDefault(s =>
- string.Equals(s.Name, name, StringComparison.CurrentCultureIgnoreCase));
-
- if (status is null)
- {
- throw new ArgumentException($"Possible values for SampleStatus: {string.Join(",", List().Select(s => s.Name))}");
- }
-
- return status;
- }
-
- ///
- /// EN: Parse status from ID.
- /// VI: Parse trạng thái từ ID.
- ///
- public static SampleStatus From(int id)
- {
- var status = List().SingleOrDefault(s => s.Id == id);
-
- if (status is null)
- {
- throw new ArgumentException($"Possible values for SampleStatus: {string.Join(",", List().Select(s => s.Name))}");
- }
-
- return status;
- }
-}
diff --git a/services/fnb-engine-net/src/FnbEngine.Domain/Events/SampleCreatedDomainEvent.cs b/services/fnb-engine-net/src/FnbEngine.Domain/Events/SampleCreatedDomainEvent.cs
deleted file mode 100644
index 6502fafb..00000000
--- a/services/fnb-engine-net/src/FnbEngine.Domain/Events/SampleCreatedDomainEvent.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using MediatR;
-using FnbEngine.Domain.AggregatesModel.SampleAggregate;
-
-namespace FnbEngine.Domain.Events;
-
-///
-/// EN: Domain event raised when a new Sample is created.
-/// VI: Domain event được phát ra khi một Sample mới được tạo.
-///
-public class SampleCreatedDomainEvent : INotification
-{
- ///
- /// EN: The newly created sample.
- /// VI: Sample mới được tạo.
- ///
- public Sample Sample { get; }
-
- public SampleCreatedDomainEvent(Sample sample)
- {
- Sample = sample;
- }
-}
diff --git a/services/fnb-engine-net/src/FnbEngine.Domain/Events/SampleStatusChangedDomainEvent.cs b/services/fnb-engine-net/src/FnbEngine.Domain/Events/SampleStatusChangedDomainEvent.cs
deleted file mode 100644
index c84ea1b2..00000000
--- a/services/fnb-engine-net/src/FnbEngine.Domain/Events/SampleStatusChangedDomainEvent.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using MediatR;
-using FnbEngine.Domain.AggregatesModel.SampleAggregate;
-
-namespace FnbEngine.Domain.Events;
-
-///
-/// EN: Domain event raised when Sample status changes.
-/// VI: Domain event được phát ra khi trạng thái Sample thay đổi.
-///
-public class SampleStatusChangedDomainEvent : INotification
-{
- ///
- /// EN: The sample ID.
- /// VI: ID của sample.
- ///
- public Guid SampleId { get; }
-
- ///
- /// EN: Previous status before the change.
- /// VI: Trạng thái trước khi thay đổi.
- ///
- public SampleStatus PreviousStatus { get; }
-
- ///
- /// EN: New status after the change.
- /// VI: Trạng thái mới sau khi thay đổi.
- ///
- public SampleStatus NewStatus { get; }
-
- public SampleStatusChangedDomainEvent(
- Guid sampleId,
- SampleStatus previousStatus,
- SampleStatus newStatus)
- {
- SampleId = sampleId;
- PreviousStatus = previousStatus;
- NewStatus = newStatus;
- }
-}
diff --git a/services/fnb-engine-net/src/FnbEngine.Domain/Exceptions/SampleDomainException.cs b/services/fnb-engine-net/src/FnbEngine.Domain/Exceptions/SampleDomainException.cs
deleted file mode 100644
index b028afb7..00000000
--- a/services/fnb-engine-net/src/FnbEngine.Domain/Exceptions/SampleDomainException.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-namespace FnbEngine.Domain.Exceptions;
-
-///
-/// EN: Exception for Sample aggregate domain errors.
-/// VI: Exception cho các lỗi domain của Sample aggregate.
-///
-public class SampleDomainException : DomainException
-{
- public SampleDomainException()
- {
- }
-
- public SampleDomainException(string message) : base(message)
- {
- }
-
- public SampleDomainException(string message, Exception innerException)
- : base(message, innerException)
- {
- }
-}
diff --git a/services/inventory-service-net/src/InventoryService.Infrastructure/EntityConfigurations/InventoryItemEntityTypeConfiguration.cs b/services/inventory-service-net/src/InventoryService.Infrastructure/EntityConfigurations/InventoryItemEntityTypeConfiguration.cs
index cbd98533..d14fe365 100644
--- a/services/inventory-service-net/src/InventoryService.Infrastructure/EntityConfigurations/InventoryItemEntityTypeConfiguration.cs
+++ b/services/inventory-service-net/src/InventoryService.Infrastructure/EntityConfigurations/InventoryItemEntityTypeConfiguration.cs
@@ -18,10 +18,10 @@ public class InventoryItemEntityTypeConfiguration : IEntityTypeConfiguration("_productId").HasColumnName("product_id").IsRequired();
builder.Property("_shopId").HasColumnName("shop_id").IsRequired();
- builder.Property("_quantityOnHand").HasColumnName("quantity_on_hand").IsRequired();
+ builder.Property("_quantity").HasColumnName("quantity").IsRequired();
builder.Property("_reservedQuantity").HasColumnName("reserved_quantity").IsRequired();
builder.Property("_reorderLevel").HasColumnName("reorder_level").HasDefaultValue(10);
- builder.Property("_updatedAt").HasColumnName("updated_at").IsRequired();
+ builder.Property("_updatedAt").HasColumnName("updated_at");
// Owned InventoryTransaction collection
builder.OwnsMany(i => i.Transactions, txn =>
@@ -50,9 +50,9 @@ public class InventoryItemEntityTypeConfiguration : IEntityTypeConfiguration i.ProductId);
builder.Ignore(i => i.ShopId);
builder.Ignore(i => i.Quantity);
- builder.Ignore(i => i.Reserved);
- builder.Ignore(i => i.Available);
- builder.Ignore(i => i.ReorderPoint);
+ builder.Ignore(i => i.ReservedQuantity);
+ builder.Ignore(i => i.AvailableQuantity);
+ builder.Ignore(i => i.ReorderLevel);
builder.Ignore(i => i.UpdatedAt);
}
}