feat(sales): incorporar DTO de lectura para Delivery Note #23 #24

Merged
leandro merged 1 commits from feature/leandro/23-deliverynote-dto-read into master 2026-03-19 20:44:56 +00:00
8 changed files with 92 additions and 41 deletions

View File

@ -1,4 +1,4 @@
using Domain.Entities; using Domain.Dtos.Sales;
/// <summary> /// <summary>
/// Servicio de dominio para la gestión de consultas de Delivery Note (Remito Ventas). /// Servicio de dominio para la gestión de consultas de Delivery Note (Remito Ventas).
@ -11,26 +11,26 @@ public interface IDeliveryNoteDom
/// </summary> /// </summary>
/// <param name="id">Identificador interno del Delivery Note.</param> /// <param name="id">Identificador interno del Delivery Note.</param>
/// <returns> /// <returns>
/// La entidad <see cref="EDeliveryNote"/> si existe; en caso contrario, null. /// El DTO <see cref="DeliveryNoteDto"/> si existe; en caso contrario, null.
/// </returns> /// </returns>
Task<EDeliveryNote?> GetByIdAsync(int id); Task<DeliveryNoteDto?> GetDtoByIdAsync(int id);
/// <summary> /// <summary>
/// Obtiene un Delivery Note a partir de su número de documento. /// Obtiene un Delivery Note a partir de su número de documento.
/// </summary> /// </summary>
/// <param name="deliveryNoteNumber">Número del Delivery Note (ej: DN-00000001).</param> /// <param name="deliveryNoteNumber">Número del Delivery Note (ej: DN-00000001).</param>
/// <returns> /// <returns>
/// La entidad <see cref="EDeliveryNote"/> si existe; en caso contrario, null. /// El DTO <see cref="DeliveryNoteDto"/> si existe; en caso contrario, null.
/// </returns> /// </returns>
Task<EDeliveryNote?> GetByDeliveryNoteNumberAsync(string deliveryNoteNumber); Task<DeliveryNoteDto?> GetDtoByDeliveryNoteNumberAsync(string deliveryNoteNumber);
/// <summary> /// <summary>
/// Obtiene todos los Delivery Notes asociados a un presupuesto (Quote). /// Obtiene todos los Delivery Notes asociados a un presupuesto (Quote).
/// </summary> /// </summary>
/// <param name="quoteId">Identificador del presupuesto relacionado.</param> /// <param name="quoteId">Identificador del presupuesto relacionado.</param>
/// <returns> /// <returns>
/// Colección de <see cref="EDeliveryNote"/> asociadas al presupuesto. /// Colección de <see cref="DeliveryNoteDto"/> asociadas al presupuesto.
/// Puede estar vacía si no existen registros. /// Puede estar vacía si no existen registros.
/// </returns> /// </returns>
Task<IEnumerable<EDeliveryNote>> GetByQuoteIdAsync(int quoteId); Task<IEnumerable<DeliveryNoteDto>> GetDtosByQuoteIdAsync(int quoteId);
} }

View File

@ -1,5 +1,5 @@
using Core.Interfaces; using Core.Interfaces;
using Domain.Entities; using Domain.Dtos.Sales;
using Models.Interfaces; using Models.Interfaces;
namespace Core.Services namespace Core.Services
@ -8,28 +8,28 @@ namespace Core.Services
{ {
private readonly IPhSDeliveryNoteRepository _deliveryNoteRepository = deliveryNoteRepository; private readonly IPhSDeliveryNoteRepository _deliveryNoteRepository = deliveryNoteRepository;
public Task<EDeliveryNote?> GetByIdAsync(int id) public Task<DeliveryNoteDto?> GetDtoByIdAsync(int id)
{ {
if (id <= 0) if (id <= 0)
throw new ArgumentOutOfRangeException(nameof(id), "El identificador del remito es inválido."); throw new ArgumentOutOfRangeException(nameof(id), "El identificador del remito es inválido.");
return _deliveryNoteRepository.GetByIdAsync(id); return _deliveryNoteRepository.GetDtoByIdAsync(id);
} }
public Task<EDeliveryNote?> GetByDeliveryNoteNumberAsync(string deliveryNoteNumber) public Task<DeliveryNoteDto?> GetDtoByDeliveryNoteNumberAsync(string deliveryNoteNumber)
{ {
if (string.IsNullOrWhiteSpace(deliveryNoteNumber)) if (string.IsNullOrWhiteSpace(deliveryNoteNumber))
throw new ArgumentException("El número de remito es obligatorio.", nameof(deliveryNoteNumber)); throw new ArgumentException("El número de remito es obligatorio.", nameof(deliveryNoteNumber));
return _deliveryNoteRepository.GetByDeliveryNoteNumberAsync(deliveryNoteNumber.Trim()); return _deliveryNoteRepository.GetDtoByDeliveryNoteNumberAsync(deliveryNoteNumber.Trim());
} }
public Task<IEnumerable<EDeliveryNote>> GetByQuoteIdAsync(int quoteId) public Task<IEnumerable<DeliveryNoteDto>> GetDtosByQuoteIdAsync(int quoteId)
{ {
if (quoteId <= 0) if (quoteId <= 0)
throw new ArgumentOutOfRangeException(nameof(quoteId), "El identificador del presupuesto es inválido."); throw new ArgumentOutOfRangeException(nameof(quoteId), "El identificador del presupuesto es inválido.");
return _deliveryNoteRepository.GetByQuoteIdAsync(quoteId); return _deliveryNoteRepository.GetDtosByQuoteIdAsync(quoteId);
} }
} }
} }

View File

@ -6,4 +6,8 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Folder Include="Dtos\Sales\" />
</ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
namespace Domain.Dtos.Sales
{
/// <summary>
/// DTO de lectura para Delivery Note.
/// Representa la cabecera del remito con su detalle de ítems.
/// </summary>
public class DeliveryNoteDto
{
public int Id { get; set; }
public string DeliveryNoteNumber { get; set; } = string.Empty;
public int? QuoteId { get; set; }
public int? SalesInvoiceId { get; set; }
public DateTime IssueDate { get; set; }
public int CustomerId { get; set; }
public string Status { get; set; } = string.Empty;
public string? Observations { get; set; }
public string? ExtraInfoJson { get; set; }
public int PrintCount { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? ModifiedAt { get; set; }
public List<DeliveryNoteItemDto> Items { get; set; } = new();
}
}

View File

@ -0,0 +1,22 @@
using System;
namespace Domain.Dtos.Sales
{
/// <summary>
/// DTO de lectura para el detalle de un Delivery Note.
/// </summary>
public class DeliveryNoteItemDto
{
public int Id { get; set; }
public int DeliverynoteId { get; set; }
public int LineNumber { get; set; }
public byte OriginType { get; set; }
public int? OriginId { get; set; }
public int? QuoteDetailId { get; set; }
public string Description { get; set; } = string.Empty;
public decimal Quantity { get; set; }
public string Notes { get; set; } = string.Empty;
public DateTime Createdat { get; set; }
public DateTime? Modifiedat { get; set; }
}
}

View File

@ -1,12 +1,11 @@
using Domain.Entities; using Domain.Dtos.Sales;
namespace Models.Interfaces namespace Models.Interfaces
{ {
public interface IPhSDeliveryNoteRepository public interface IPhSDeliveryNoteRepository
{ {
Task<EDeliveryNote?> GetByIdAsync(int id); Task<DeliveryNoteDto?> GetDtoByIdAsync(int id);
Task<EDeliveryNote?> GetByDeliveryNoteNumberAsync(string deliveryNoteNumber); Task<DeliveryNoteDto?> GetDtoByDeliveryNoteNumberAsync(string deliveryNoteNumber);
Task<IEnumerable<EDeliveryNote>> GetByQuoteIdAsync(int quoteId); Task<IEnumerable<DeliveryNoteDto>> GetDtosByQuoteIdAsync(int quoteId);
} }
} }

View File

@ -1,6 +1,6 @@
using Domain.Dtos.Sales;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Models.Interfaces; using Models.Interfaces;
using Domain.Entities;
using Models.Models; using Models.Models;
namespace Models.Repositories namespace Models.Repositories
@ -9,27 +9,27 @@ namespace Models.Repositories
{ {
private readonly PhronCareOperationsHubContext _context = context; private readonly PhronCareOperationsHubContext _context = context;
public async Task<EDeliveryNote?> GetByIdAsync(int id) public async Task<DeliveryNoteDto?> GetDtoByIdAsync(int id)
{ {
var entity = await _context.PhSDeliveryNotes var entity = await _context.PhSDeliveryNotes
.Include(x => x.PhSDeliveryNoteDetails) .Include(x => x.PhSDeliveryNoteDetails)
.AsNoTracking() .AsNoTracking()
.FirstOrDefaultAsync(x => x.Id == id); .FirstOrDefaultAsync(x => x.Id == id);
return entity == null ? null : MapDeliveryNote(entity); return entity == null ? null : MapDeliveryNoteDto(entity);
} }
public async Task<EDeliveryNote?> GetByDeliveryNoteNumberAsync(string deliveryNoteNumber) public async Task<DeliveryNoteDto?> GetDtoByDeliveryNoteNumberAsync(string deliveryNoteNumber)
{ {
var entity = await _context.PhSDeliveryNotes var entity = await _context.PhSDeliveryNotes
.Include(x => x.PhSDeliveryNoteDetails) .Include(x => x.PhSDeliveryNoteDetails)
.AsNoTracking() .AsNoTracking()
.FirstOrDefaultAsync(x => x.Deliverynotenumber == deliveryNoteNumber); .FirstOrDefaultAsync(x => x.Deliverynotenumber == deliveryNoteNumber);
return entity == null ? null : MapDeliveryNote(entity); return entity == null ? null : MapDeliveryNoteDto(entity);
} }
public async Task<IEnumerable<EDeliveryNote>> GetByQuoteIdAsync(int quoteId) public async Task<IEnumerable<DeliveryNoteDto>> GetDtosByQuoteIdAsync(int quoteId)
{ {
var entities = await _context.PhSDeliveryNotes var entities = await _context.PhSDeliveryNotes
.Include(x => x.PhSDeliveryNoteDetails) .Include(x => x.PhSDeliveryNoteDetails)
@ -39,12 +39,12 @@ namespace Models.Repositories
.ThenByDescending(x => x.Id) .ThenByDescending(x => x.Id)
.ToListAsync(); .ToListAsync();
return entities.Select(MapDeliveryNote); return entities.Select(MapDeliveryNoteDto);
} }
private static EDeliveryNote MapDeliveryNote(PhSDeliveryNote source) private static DeliveryNoteDto MapDeliveryNoteDto(PhSDeliveryNote source)
{ {
return new EDeliveryNote return new DeliveryNoteDto
{ {
Id = source.Id, Id = source.Id,
DeliveryNoteNumber = source.Deliverynotenumber, DeliveryNoteNumber = source.Deliverynotenumber,
@ -58,17 +58,17 @@ namespace Models.Repositories
PrintCount = source.Printcount, PrintCount = source.Printcount,
CreatedAt = source.Createdat, CreatedAt = source.Createdat,
ModifiedAt = source.Modifiedat, ModifiedAt = source.Modifiedat,
PhSDeliveryNoteDetails = source.PhSDeliveryNoteDetails Items = source.PhSDeliveryNoteDetails
.OrderBy(d => d.LineNumber) .OrderBy(d => d.LineNumber)
.ThenBy(d => d.Id) .ThenBy(d => d.Id)
.Select(MapDeliveryNoteDetail) .Select(MapDeliveryNoteItemDto)
.ToList() .ToList()
}; };
} }
private static EDeliveryNoteDetail MapDeliveryNoteDetail(PhSDeliveryNoteDetail source) private static DeliveryNoteItemDto MapDeliveryNoteItemDto(PhSDeliveryNoteDetail source)
{ {
return new EDeliveryNoteDetail return new DeliveryNoteItemDto
{ {
Id = source.Id, Id = source.Id,
DeliverynoteId = source.DeliverynoteId, DeliverynoteId = source.DeliverynoteId,

View File

@ -1,4 +1,4 @@
using Domain.Entities; using Domain.Dtos.Sales;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Reflection; using System.Reflection;
@ -16,11 +16,11 @@ namespace phronCare.API.Controllers.Sales
} }
[HttpGet("{id:int}")] [HttpGet("{id:int}")]
public async Task<ActionResult<EDeliveryNote>> GetById(int id) public async Task<ActionResult<DeliveryNoteDto>> GetById(int id)
{ {
try try
{ {
var deliveryNote = await _deliveryNoteService.GetByIdAsync(id); var deliveryNote = await _deliveryNoteService.GetDtoByIdAsync(id);
if (deliveryNote == null) if (deliveryNote == null)
return NotFound($"Remito con ID {id} no encontrado."); return NotFound($"Remito con ID {id} no encontrado.");
@ -34,11 +34,11 @@ namespace phronCare.API.Controllers.Sales
} }
[HttpGet("number/{deliveryNoteNumber}")] [HttpGet("number/{deliveryNoteNumber}")]
public async Task<ActionResult<EDeliveryNote>> GetByDeliveryNoteNumber(string deliveryNoteNumber) public async Task<ActionResult<DeliveryNoteDto>> GetByDeliveryNoteNumber(string deliveryNoteNumber)
{ {
try try
{ {
var deliveryNote = await _deliveryNoteService.GetByDeliveryNoteNumberAsync(deliveryNoteNumber); var deliveryNote = await _deliveryNoteService.GetDtoByDeliveryNoteNumberAsync(deliveryNoteNumber);
if (deliveryNote == null) if (deliveryNote == null)
return NotFound($"Remito con número {deliveryNoteNumber} no encontrado."); return NotFound($"Remito con número {deliveryNoteNumber} no encontrado.");
@ -52,11 +52,11 @@ namespace phronCare.API.Controllers.Sales
} }
[HttpGet("by-quote/{quoteId:int}")] [HttpGet("by-quote/{quoteId:int}")]
public async Task<ActionResult<IEnumerable<EDeliveryNote>>> GetByQuoteId(int quoteId) public async Task<ActionResult<IEnumerable<DeliveryNoteDto>>> GetByQuoteId(int quoteId)
{ {
try try
{ {
var deliveryNotes = await _deliveryNoteService.GetByQuoteIdAsync(quoteId); var deliveryNotes = await _deliveryNoteService.GetDtosByQuoteIdAsync(quoteId);
return Ok(deliveryNotes); return Ok(deliveryNotes);
} }
catch (Exception ex) catch (Exception ex)