diff --git a/src/Core/Logistics.Application.Tenant/Commands/Invoice/CreateInvoice/CreateInvoiceCommand.cs b/src/Core/Logistics.Application.Tenant/Commands/Invoice/CreateInvoice/CreateInvoiceCommand.cs index d14bf3e3f..f0edefc33 100644 --- a/src/Core/Logistics.Application.Tenant/Commands/Invoice/CreateInvoice/CreateInvoiceCommand.cs +++ b/src/Core/Logistics.Application.Tenant/Commands/Invoice/CreateInvoice/CreateInvoiceCommand.cs @@ -5,8 +5,6 @@ namespace Logistics.Application.Tenant.Commands; public class CreateInvoiceCommand : IRequest { - public string? CompanyName { get; set; } - public string? CompanyAddress { get; set; } public string CustomerId { get; set; } = default!; public string LoadId { get; set; } = default!; public PaymentMethod PaymentMethod { get; set; } diff --git a/src/Core/Logistics.Application.Tenant/Commands/Invoice/UpdateInvoice/UpdateInvoiceCommand.cs b/src/Core/Logistics.Application.Tenant/Commands/Invoice/UpdateInvoice/UpdateInvoiceCommand.cs index dbe53c6be..b641885f7 100644 --- a/src/Core/Logistics.Application.Tenant/Commands/Invoice/UpdateInvoice/UpdateInvoiceCommand.cs +++ b/src/Core/Logistics.Application.Tenant/Commands/Invoice/UpdateInvoice/UpdateInvoiceCommand.cs @@ -6,16 +6,6 @@ namespace Logistics.Application.Tenant.Commands; public class UpdateInvoiceCommand : IRequest { public string Id { get; set; } = default!; - public string? CompanyName { get; set; } - public string? CompanyAddress { get; set; } - public string CustomerId { get; set; } = default!; - public string LoadId { get; set; } = default!; - public PaymentMethod PaymentMethod { get; set; } - public decimal PaymentAmount { get; set; } - - public PaymentMethod? Method { get; set; } - public decimal? Amount { get; set; } - public PaymentStatus? Status { get; set; } - public PaymentFor? PaymentFor { get; set; } - public string? Comment { get; set; } + public PaymentMethod? PaymentMethod { get; set; } + public decimal? PaymentAmount { get; set; } } diff --git a/src/Core/Logistics.Application.Tenant/Commands/Invoice/UpdateInvoice/UpdateInvoiceHandler.cs b/src/Core/Logistics.Application.Tenant/Commands/Invoice/UpdateInvoice/UpdateInvoiceHandler.cs index 2f7303682..2aa4fc7ca 100644 --- a/src/Core/Logistics.Application.Tenant/Commands/Invoice/UpdateInvoice/UpdateInvoiceHandler.cs +++ b/src/Core/Logistics.Application.Tenant/Commands/Invoice/UpdateInvoice/UpdateInvoiceHandler.cs @@ -1,6 +1,6 @@ namespace Logistics.Application.Tenant.Commands; -internal sealed class UpdateInvoiceHandler : RequestHandler +internal sealed class UpdateInvoiceHandler : RequestHandler { private readonly ITenantRepository _tenantRepository; @@ -10,35 +10,23 @@ public UpdateInvoiceHandler(ITenantRepository tenantRepository) } protected override async Task HandleValidated( - UpdatePaymentCommand req, CancellationToken cancellationToken) + UpdateInvoiceCommand req, CancellationToken cancellationToken) { - var payment = await _tenantRepository.GetAsync(req.Id); + var invoice = await _tenantRepository.GetAsync(req.Id); - if (payment is null) - return ResponseResult.CreateError($"Could not find a payment with ID '{req.Id}'"); - - if (req.PaymentFor.HasValue && payment.PaymentFor != req.PaymentFor) - { - payment.PaymentFor = req.PaymentFor.Value; - } - if (req.Method.HasValue && payment.Method != req.Method) - { - payment.Method = req.Method.Value; - } - if (req.Status.HasValue && payment.Status != req.Status) - { - payment.SetStatus(req.Status.Value); - } - if (req.Amount.HasValue && payment.Amount != req.Amount) + if (invoice is null) + return ResponseResult.CreateError($"Could not find an invoice with ID '{req.Id}'"); + + if (req.PaymentMethod.HasValue && invoice.Payment.Method != req.PaymentMethod) { - payment.Amount = req.Amount.Value; + invoice.Payment.Method = req.PaymentMethod.Value; } - if (!string.IsNullOrEmpty(req.Comment) && payment.Comment != req.Comment) + if (req.PaymentAmount.HasValue && invoice.Payment.Amount != req.PaymentAmount) { - payment.Comment = req.Comment; + invoice.Payment.Amount = req.PaymentAmount.Value; } - _tenantRepository.Update(payment); + _tenantRepository.Update(invoice); await _tenantRepository.UnitOfWork.CommitAsync(); return ResponseResult.CreateSuccess(); } diff --git a/src/Core/Logistics.Application.Tenant/Mappers/InvoiceMapper.cs b/src/Core/Logistics.Application.Tenant/Mappers/InvoiceMapper.cs index fda25b6ac..2574836e6 100644 --- a/src/Core/Logistics.Application.Tenant/Mappers/InvoiceMapper.cs +++ b/src/Core/Logistics.Application.Tenant/Mappers/InvoiceMapper.cs @@ -8,7 +8,7 @@ public static InvoiceDto ToDto(this Invoice entity) { return new InvoiceDto { - CustomerId = entity.CustomerId, + Customer = entity.Customer.ToDto(), LoadId = entity.LoadId, Payment = entity.Payment.ToDto() }; diff --git a/src/Core/Logistics.Application.Tenant/Queries/Invoice/GetInvoiceById/GetInvoiceByIdHandler.cs b/src/Core/Logistics.Application.Tenant/Queries/Invoice/GetInvoiceById/GetInvoiceByIdHandler.cs new file mode 100644 index 000000000..0ecdf53b3 --- /dev/null +++ b/src/Core/Logistics.Application.Tenant/Queries/Invoice/GetInvoiceById/GetInvoiceByIdHandler.cs @@ -0,0 +1,26 @@ +using Logistics.Application.Tenant.Mappers; +using Logistics.Shared.Models; + +namespace Logistics.Application.Tenant.Queries; + +internal sealed class GetInvoiceByIdHandler : RequestHandler> +{ + private readonly ITenantRepository _tenantRepository; + + public GetInvoiceByIdHandler(ITenantRepository tenantRepository) + { + _tenantRepository = tenantRepository; + } + + protected override async Task> HandleValidated( + GetInvoiceByIdQuery req, CancellationToken cancellationToken) + { + var invoiceEntity = await _tenantRepository.GetAsync(req.Id); + + if (invoiceEntity is null) + return ResponseResult.CreateError($"Could not find an invoice with ID {req.Id}"); + + var invoiceDto = invoiceEntity.ToDto(); + return ResponseResult.CreateSuccess(invoiceDto); + } +} diff --git a/src/Core/Logistics.Application.Tenant/Queries/Invoice/GetInvoiceById/GetInvoiceByIdQuery.cs b/src/Core/Logistics.Application.Tenant/Queries/Invoice/GetInvoiceById/GetInvoiceByIdQuery.cs new file mode 100644 index 000000000..670d42468 --- /dev/null +++ b/src/Core/Logistics.Application.Tenant/Queries/Invoice/GetInvoiceById/GetInvoiceByIdQuery.cs @@ -0,0 +1,9 @@ +using Logistics.Shared.Models; +using MediatR; + +namespace Logistics.Application.Tenant.Queries; + +public class GetInvoiceByIdQuery : IRequest> +{ + public string? Id { get; set; } +} diff --git a/src/Core/Logistics.Application.Tenant/Queries/Invoice/GetInvoiceById/GetInvoiceByIdValidator.cs b/src/Core/Logistics.Application.Tenant/Queries/Invoice/GetInvoiceById/GetInvoiceByIdValidator.cs new file mode 100644 index 000000000..d9d85e1df --- /dev/null +++ b/src/Core/Logistics.Application.Tenant/Queries/Invoice/GetInvoiceById/GetInvoiceByIdValidator.cs @@ -0,0 +1,11 @@ +using FluentValidation; + +namespace Logistics.Application.Tenant.Queries; + +internal sealed class GetInvoiceByIdValidator : AbstractValidator +{ + public GetInvoiceByIdValidator() + { + RuleFor(i => i.Id).NotEmpty(); + } +} diff --git a/src/Core/Logistics.Application.Tenant/Queries/Invoice/GetInvoices/GetInvoicesHandler.cs b/src/Core/Logistics.Application.Tenant/Queries/Invoice/GetInvoices/GetInvoicesHandler.cs new file mode 100644 index 000000000..ad206e73f --- /dev/null +++ b/src/Core/Logistics.Application.Tenant/Queries/Invoice/GetInvoices/GetInvoicesHandler.cs @@ -0,0 +1,31 @@ +using Logistics.Application.Tenant.Mappers; +using Logistics.Shared.Models; + +namespace Logistics.Application.Tenant.Queries; + +internal sealed class GetInvoicesHandler : RequestHandler> +{ + private readonly ITenantRepository _tenantRepository; + + public GetInvoicesHandler(ITenantRepository tenantRepository) + { + _tenantRepository = tenantRepository; + } + + protected override Task> HandleValidated( + GetInvoicesQuery req, + CancellationToken cancellationToken) + { + var totalItems = _tenantRepository.Query().Count(); + var specification = new FilterInvoicesByInterval(req.OrderBy, req.StartDate, req.EndDate, req.Descending); + + var invoicesDto = _tenantRepository.ApplySpecification(specification) + .Skip((req.Page - 1) * req.PageSize) + .Take(req.PageSize) + .Select(i => i.ToDto()) + .ToArray(); + + var totalPages = (int)Math.Ceiling(totalItems / (double)req.PageSize); + return Task.FromResult(PagedResponseResult.Create(invoicesDto, totalItems, totalPages)); + } +} diff --git a/src/Core/Logistics.Application.Tenant/Queries/Invoice/GetInvoices/GetInvoicesQuery.cs b/src/Core/Logistics.Application.Tenant/Queries/Invoice/GetInvoices/GetInvoicesQuery.cs new file mode 100644 index 000000000..7dc4ed507 --- /dev/null +++ b/src/Core/Logistics.Application.Tenant/Queries/Invoice/GetInvoices/GetInvoicesQuery.cs @@ -0,0 +1,8 @@ +using Logistics.Shared.Models; +using MediatR; + +namespace Logistics.Application.Tenant.Queries; + +public class GetInvoicesQuery : PagedIntervalQuery, IRequest> +{ +} diff --git a/src/Core/Logistics.Application.Tenant/Queries/Invoice/GetInvoices/GetInvoicesValidator.cs b/src/Core/Logistics.Application.Tenant/Queries/Invoice/GetInvoices/GetInvoicesValidator.cs new file mode 100644 index 000000000..c0a01d6b9 --- /dev/null +++ b/src/Core/Logistics.Application.Tenant/Queries/Invoice/GetInvoices/GetInvoicesValidator.cs @@ -0,0 +1,16 @@ +using FluentValidation; + +namespace Logistics.Application.Tenant.Queries; + +internal sealed class GetInvoicesValidator : AbstractValidator +{ + public GetInvoicesValidator() + { + RuleFor(i => i.StartDate).LessThan(i => i.EndDate); + RuleFor(i => i.Page) + .GreaterThanOrEqualTo(0); + + RuleFor(i => i.PageSize) + .GreaterThanOrEqualTo(1); + } +} diff --git a/src/Core/Logistics.Domain/Specifications/FilterInvoicesByInterval.cs b/src/Core/Logistics.Domain/Specifications/FilterInvoicesByInterval.cs new file mode 100644 index 000000000..c10f6b984 --- /dev/null +++ b/src/Core/Logistics.Domain/Specifications/FilterInvoicesByInterval.cs @@ -0,0 +1,26 @@ +using System.Linq.Expressions; +using Logistics.Domain.Entities; + +namespace Logistics.Domain.Specifications; + +public class FilterInvoicesByInterval : BaseSpecification +{ + public FilterInvoicesByInterval(string? orderProperty, DateTime? startPeriod, DateTime endPeriod, bool descending) + { + Descending = descending; + OrderBy = InitOrderBy(orderProperty); + + Criteria = i => + i.Created >= startPeriod && i.Created <= endPeriod; + } + + private static Expression> InitOrderBy(string? propertyName) + { + propertyName = propertyName?.ToLower(); + return propertyName switch + { + "paymentamount" => i => i.Payment.Amount, + _ => i => i.Created + }; + } +} diff --git a/src/Server/Logistics.API/Controllers/InvoiceController.cs b/src/Server/Logistics.API/Controllers/InvoiceController.cs index 277557c4b..9b4437649 100644 --- a/src/Server/Logistics.API/Controllers/InvoiceController.cs +++ b/src/Server/Logistics.API/Controllers/InvoiceController.cs @@ -14,12 +14,12 @@ public InvoicesController(IMediator mediator) } [HttpGet("{id}")] - [ProducesResponseType(typeof(ResponseResult), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ResponseResult), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ResponseResult), StatusCodes.Status400BadRequest)] [Authorize(Policy = Permissions.Invoices.View)] public async Task GetById(string id) { - var result = await _mediator.Send(new GetPaymentByIdQuery {Id = id}); + var result = await _mediator.Send(new GetInvoiceByIdQuery {Id = id}); if (result.IsSuccess) return Ok(result); @@ -28,10 +28,10 @@ public async Task GetById(string id) } [HttpGet] - [ProducesResponseType(typeof(PagedResponseResult), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(PagedResponseResult), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ResponseResult), StatusCodes.Status400BadRequest)] [Authorize(Policy = Permissions.Invoices.View)] - public async Task GetList([FromQuery] GetPaymentsQuery query) + public async Task GetList([FromQuery] GetInvoicesQuery query) { var result = await _mediator.Send(query); diff --git a/src/Shared/Logistics.Shared.Models/InvoiceDto.cs b/src/Shared/Logistics.Shared.Models/InvoiceDto.cs index 2e6bc44b7..21755a157 100644 --- a/src/Shared/Logistics.Shared.Models/InvoiceDto.cs +++ b/src/Shared/Logistics.Shared.Models/InvoiceDto.cs @@ -5,6 +5,6 @@ public class InvoiceDto public string? CompanyName { get; set; } public string? CompanyAddress { get; set; } public string LoadId { get; set; } = default!; - public string CustomerId { get; set; } = default!; + public CustomerDto Customer { get; set; } = default!; public PaymentDto Payment { get; set; } = default!; }