feat(api): expose sales document application endpoints
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (pull_request) Successful in 6m9s
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (pull_request) Successful in 6m9s
close #64
This commit is contained in:
parent
36c3e26231
commit
adb8eb5c5c
@ -1,9 +1,21 @@
|
|||||||
using Domain.Dtos.Sales;
|
using Domain.Dtos.Sales;
|
||||||
|
using Domain.Generics;
|
||||||
|
|
||||||
namespace Core.Interfaces
|
namespace Core.Interfaces
|
||||||
{
|
{
|
||||||
public interface ISalesDocumentDom
|
public interface ISalesDocumentDom
|
||||||
{
|
{
|
||||||
|
Task<PagedResult<SalesDocumentSummaryDto>> SearchAsync(
|
||||||
|
int? customerId,
|
||||||
|
string? customerText,
|
||||||
|
int? quoteId,
|
||||||
|
int? documentType,
|
||||||
|
int? status,
|
||||||
|
DateTime? issueDateFrom,
|
||||||
|
DateTime? issueDateTo,
|
||||||
|
int page = 1,
|
||||||
|
int pageSize = 50);
|
||||||
|
|
||||||
Task<SalesDocumentCreateResponse> CreateAsync(SalesDocumentCreateRequest request);
|
Task<SalesDocumentCreateResponse> CreateAsync(SalesDocumentCreateRequest request);
|
||||||
Task<SalesDocumentDto?> GetDtoByIdAsync(int id);
|
Task<SalesDocumentDto?> GetDtoByIdAsync(int id);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ using Core.Interfaces;
|
|||||||
using Domain.Constants;
|
using Domain.Constants;
|
||||||
using Domain.Dtos.Sales;
|
using Domain.Dtos.Sales;
|
||||||
using Domain.Entities;
|
using Domain.Entities;
|
||||||
|
using Domain.Generics;
|
||||||
using Models.Interfaces;
|
using Models.Interfaces;
|
||||||
|
|
||||||
namespace Core.Services
|
namespace Core.Services
|
||||||
@ -10,6 +11,29 @@ namespace Core.Services
|
|||||||
{
|
{
|
||||||
private readonly IPhSSalesDocumentRepository _salesDocumentRepository = salesDocumentRepository;
|
private readonly IPhSSalesDocumentRepository _salesDocumentRepository = salesDocumentRepository;
|
||||||
|
|
||||||
|
public Task<PagedResult<SalesDocumentSummaryDto>> SearchAsync(
|
||||||
|
int? customerId,
|
||||||
|
string? customerText,
|
||||||
|
int? quoteId,
|
||||||
|
int? documentType,
|
||||||
|
int? status,
|
||||||
|
DateTime? issueDateFrom,
|
||||||
|
DateTime? issueDateTo,
|
||||||
|
int page = 1,
|
||||||
|
int pageSize = 50)
|
||||||
|
{
|
||||||
|
return _salesDocumentRepository.SearchAsync(
|
||||||
|
customerId,
|
||||||
|
customerText,
|
||||||
|
quoteId,
|
||||||
|
documentType,
|
||||||
|
status,
|
||||||
|
issueDateFrom,
|
||||||
|
issueDateTo,
|
||||||
|
page,
|
||||||
|
pageSize);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<SalesDocumentCreateResponse> CreateAsync(SalesDocumentCreateRequest request)
|
public async Task<SalesDocumentCreateResponse> CreateAsync(SalesDocumentCreateRequest request)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(request);
|
ArgumentNullException.ThrowIfNull(request);
|
||||||
|
|||||||
@ -1,10 +1,22 @@
|
|||||||
using Domain.Dtos.Sales;
|
using Domain.Dtos.Sales;
|
||||||
using Domain.Entities;
|
using Domain.Entities;
|
||||||
|
using Domain.Generics;
|
||||||
|
|
||||||
namespace Models.Interfaces
|
namespace Models.Interfaces
|
||||||
{
|
{
|
||||||
public interface IPhSSalesDocumentRepository
|
public interface IPhSSalesDocumentRepository
|
||||||
{
|
{
|
||||||
|
Task<PagedResult<SalesDocumentSummaryDto>> SearchAsync(
|
||||||
|
int? customerId,
|
||||||
|
string? customerText,
|
||||||
|
int? quoteId,
|
||||||
|
int? documentType,
|
||||||
|
int? status,
|
||||||
|
DateTime? issueDateFrom,
|
||||||
|
DateTime? issueDateTo,
|
||||||
|
int page = 1,
|
||||||
|
int pageSize = 50);
|
||||||
|
|
||||||
Task<ESalesDocument> CreateAsync(ESalesDocument entity);
|
Task<ESalesDocument> CreateAsync(ESalesDocument entity);
|
||||||
Task<SalesDocumentDto?> GetDtoByIdAsync(int id);
|
Task<SalesDocumentDto?> GetDtoByIdAsync(int id);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using Domain.Dtos.Sales;
|
using Domain.Dtos.Sales;
|
||||||
using Domain.Entities;
|
using Domain.Entities;
|
||||||
|
using Domain.Generics;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Models.Helpers;
|
using Models.Helpers;
|
||||||
using Models.Interfaces;
|
using Models.Interfaces;
|
||||||
@ -11,6 +12,103 @@ namespace Models.Repositories
|
|||||||
{
|
{
|
||||||
private readonly PhronCareOperationsHubContext _context = context;
|
private readonly PhronCareOperationsHubContext _context = context;
|
||||||
|
|
||||||
|
public async Task<PagedResult<SalesDocumentSummaryDto>> SearchAsync(
|
||||||
|
int? customerId,
|
||||||
|
string? customerText,
|
||||||
|
int? quoteId,
|
||||||
|
int? documentType,
|
||||||
|
int? status,
|
||||||
|
DateTime? issueDateFrom,
|
||||||
|
DateTime? issueDateTo,
|
||||||
|
int page = 1,
|
||||||
|
int pageSize = 50)
|
||||||
|
{
|
||||||
|
page = page <= 0 ? 1 : page;
|
||||||
|
pageSize = pageSize <= 0 ? 50 : pageSize;
|
||||||
|
|
||||||
|
var query = _context.PhSSalesDocuments
|
||||||
|
.Include(x => x.Customer)
|
||||||
|
.Include(x => x.BillToCustomer)
|
||||||
|
.AsNoTracking()
|
||||||
|
.AsQueryable();
|
||||||
|
|
||||||
|
if (customerId.HasValue && customerId.Value > 0)
|
||||||
|
{
|
||||||
|
query = query.Where(x => x.CustomerId == customerId.Value || x.BillToCustomerId == customerId.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(customerText))
|
||||||
|
{
|
||||||
|
var normalizedCustomerText = customerText.Trim();
|
||||||
|
query = query.Where(x =>
|
||||||
|
(x.Customer.Name ?? string.Empty).Contains(normalizedCustomerText) ||
|
||||||
|
(x.BillToCustomer.Name ?? string.Empty).Contains(normalizedCustomerText));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quoteId.HasValue && quoteId.Value > 0)
|
||||||
|
{
|
||||||
|
query = query.Where(x => x.QuoteId == quoteId.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (documentType.HasValue && documentType.Value > 0)
|
||||||
|
{
|
||||||
|
query = query.Where(x => x.DocumentType == documentType.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status.HasValue && status.Value > 0)
|
||||||
|
{
|
||||||
|
query = query.Where(x => x.Status == status.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (issueDateFrom.HasValue)
|
||||||
|
{
|
||||||
|
query = query.Where(x => x.IssueDate >= issueDateFrom.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (issueDateTo.HasValue)
|
||||||
|
{
|
||||||
|
query = query.Where(x => x.IssueDate <= issueDateTo.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalItems = await query.CountAsync();
|
||||||
|
|
||||||
|
var items = await query
|
||||||
|
.OrderByDescending(x => x.IssueDate)
|
||||||
|
.ThenByDescending(x => x.Id)
|
||||||
|
.Skip((page - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
|
.Select(x => new SalesDocumentSummaryDto
|
||||||
|
{
|
||||||
|
Id = x.Id,
|
||||||
|
InternalDocumentNumber = x.InternalDocumentNumber,
|
||||||
|
DocumentType = x.DocumentType,
|
||||||
|
Status = x.Status,
|
||||||
|
QuoteId = x.QuoteId,
|
||||||
|
CustomerId = x.CustomerId,
|
||||||
|
CustomerName = x.Customer.Name ?? string.Empty,
|
||||||
|
BillToCustomerId = x.BillToCustomerId,
|
||||||
|
BillToCustomerName = x.BillToCustomer.Name ?? string.Empty,
|
||||||
|
IssueDate = x.IssueDate,
|
||||||
|
Currency = x.Currency,
|
||||||
|
NetAmount = x.NetAmount,
|
||||||
|
TaxAmount = x.TaxAmount,
|
||||||
|
TotalAmount = x.TotalAmount,
|
||||||
|
PeriodFrom = x.PeriodFrom,
|
||||||
|
PeriodTo = x.PeriodTo,
|
||||||
|
Createdat = x.Createdat,
|
||||||
|
Modifiedat = x.Modifiedat
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
return new PagedResult<SalesDocumentSummaryDto>
|
||||||
|
{
|
||||||
|
Items = items,
|
||||||
|
TotalItems = totalItems,
|
||||||
|
Page = page,
|
||||||
|
PageSize = pageSize
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<ESalesDocument> CreateAsync(ESalesDocument entity)
|
public async Task<ESalesDocument> CreateAsync(ESalesDocument entity)
|
||||||
{
|
{
|
||||||
var mapped = EntityMapper.MapEntity<ESalesDocument, PhSSalesDocument>(entity);
|
var mapped = EntityMapper.MapEntity<ESalesDocument, PhSSalesDocument>(entity);
|
||||||
|
|||||||
103
phronCare.API/Controllers/Sales/SalesDocumentController.cs
Normal file
103
phronCare.API/Controllers/Sales/SalesDocumentController.cs
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
using Core.Interfaces;
|
||||||
|
using Domain.Dtos.Sales;
|
||||||
|
using Domain.Generics;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace phronCare.API.Controllers.Sales
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class SalesDocumentController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly ISalesDocumentDom _salesDocumentService;
|
||||||
|
|
||||||
|
public SalesDocumentController(ISalesDocumentDom salesDocumentService)
|
||||||
|
{
|
||||||
|
_salesDocumentService = salesDocumentService ?? throw new ArgumentNullException(nameof(salesDocumentService));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("search")]
|
||||||
|
public async Task<ActionResult<PagedResult<SalesDocumentSummaryDto>>> Search(
|
||||||
|
[FromQuery] int? customerId,
|
||||||
|
[FromQuery] string? customerText,
|
||||||
|
[FromQuery] int? quoteId,
|
||||||
|
[FromQuery] int? documentType,
|
||||||
|
[FromQuery] int? status,
|
||||||
|
[FromQuery] DateTime? issueDateFrom,
|
||||||
|
[FromQuery] DateTime? issueDateTo,
|
||||||
|
[FromQuery] int page = 1,
|
||||||
|
[FromQuery] int pageSize = 50)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _salesDocumentService.SearchAsync(
|
||||||
|
customerId,
|
||||||
|
customerText,
|
||||||
|
quoteId,
|
||||||
|
documentType,
|
||||||
|
status,
|
||||||
|
issueDateFrom,
|
||||||
|
issueDateTo,
|
||||||
|
page,
|
||||||
|
pageSize);
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
||||||
|
return StatusCode(500, $"{methodName} Message: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id:int}")]
|
||||||
|
public async Task<ActionResult<SalesDocumentDto>> GetById(int id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var salesDocument = await _salesDocumentService.GetDtoByIdAsync(id);
|
||||||
|
if (salesDocument == null)
|
||||||
|
return NotFound($"Sales Document con ID {id} no encontrado.");
|
||||||
|
|
||||||
|
return Ok(salesDocument);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
||||||
|
return StatusCode(500, $"{methodName} Message: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<ActionResult<SalesDocumentDto>> Create([FromBody] SalesDocumentCreateRequest request)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (request == null)
|
||||||
|
return BadRequest("El payload no puede ser nulo.");
|
||||||
|
|
||||||
|
var created = await _salesDocumentService.CreateAsync(request);
|
||||||
|
var salesDocument = await _salesDocumentService.GetDtoByIdAsync(created.Id);
|
||||||
|
|
||||||
|
if (salesDocument == null)
|
||||||
|
return StatusCode(500, $"No se pudo recuperar el Sales Document creado con ID {created.Id}.");
|
||||||
|
|
||||||
|
return CreatedAtAction(nameof(GetById), new { id = salesDocument.Id }, salesDocument);
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(ex.Message);
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(ex.Message);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
||||||
|
return StatusCode(500, $"{methodName} Message: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -242,6 +242,9 @@ static void RepositorysAndServices(WebApplicationBuilder builder)
|
|||||||
builder.Services.AddScoped<IDeliveryNoteDom, DeliveryNoteService>();
|
builder.Services.AddScoped<IDeliveryNoteDom, DeliveryNoteService>();
|
||||||
builder.Services.AddScoped<IPhSDeliveryNoteRepository, PhSDeliveryNoteRepository>();
|
builder.Services.AddScoped<IPhSDeliveryNoteRepository, PhSDeliveryNoteRepository>();
|
||||||
|
|
||||||
|
builder.Services.AddScoped<ISalesDocumentDom, SalesDocumentService>();
|
||||||
|
builder.Services.AddScoped<IPhSSalesDocumentRepository, PhSSalesDocumentRepository>();
|
||||||
|
|
||||||
builder.Services.AddScoped<ITaxTypeDom, TaxTypeService>();
|
builder.Services.AddScoped<ITaxTypeDom, TaxTypeService>();
|
||||||
builder.Services.AddScoped<IPhOhArcataxTypeRepository, PhOhArcataxTypeRepository>();
|
builder.Services.AddScoped<IPhOhArcataxTypeRepository, PhOhArcataxTypeRepository>();
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user