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>
/// Servicio de dominio para la gestión de consultas de Delivery Note (Remito Ventas).
@ -11,26 +11,26 @@ public interface IDeliveryNoteDom
/// </summary>
/// <param name="id">Identificador interno del Delivery Note.</param>
/// <returns>
/// La entidad <see cref="EDeliveryNote"/> si existe; en caso contrario, null.
/// El DTO <see cref="DeliveryNoteDto"/> si existe; en caso contrario, null.
/// </returns>
Task<EDeliveryNote?> GetByIdAsync(int id);
Task<DeliveryNoteDto?> GetDtoByIdAsync(int id);
/// <summary>
/// Obtiene un Delivery Note a partir de su número de documento.
/// </summary>
/// <param name="deliveryNoteNumber">Número del Delivery Note (ej: DN-00000001).</param>
/// <returns>
/// La entidad <see cref="EDeliveryNote"/> si existe; en caso contrario, null.
/// El DTO <see cref="DeliveryNoteDto"/> si existe; en caso contrario, null.
/// </returns>
Task<EDeliveryNote?> GetByDeliveryNoteNumberAsync(string deliveryNoteNumber);
Task<DeliveryNoteDto?> GetDtoByDeliveryNoteNumberAsync(string deliveryNoteNumber);
/// <summary>
/// Obtiene todos los Delivery Notes asociados a un presupuesto (Quote).
/// </summary>
/// <param name="quoteId">Identificador del presupuesto relacionado.</param>
/// <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.
/// </returns>
Task<IEnumerable<EDeliveryNote>> GetByQuoteIdAsync(int quoteId);
Task<IEnumerable<DeliveryNoteDto>> GetDtosByQuoteIdAsync(int quoteId);
}

View File

@ -1,5 +1,5 @@
using Core.Interfaces;
using Domain.Entities;
using Domain.Dtos.Sales;
using Models.Interfaces;
namespace Core.Services
@ -8,28 +8,28 @@ namespace Core.Services
{
private readonly IPhSDeliveryNoteRepository _deliveryNoteRepository = deliveryNoteRepository;
public Task<EDeliveryNote?> GetByIdAsync(int id)
public Task<DeliveryNoteDto?> GetDtoByIdAsync(int id)
{
if (id <= 0)
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))
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)
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>
</PropertyGroup>
<ItemGroup>
<Folder Include="Dtos\Sales\" />
</ItemGroup>
</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
{
public interface IPhSDeliveryNoteRepository
{
Task<EDeliveryNote?> GetByIdAsync(int id);
Task<EDeliveryNote?> GetByDeliveryNoteNumberAsync(string deliveryNoteNumber);
Task<IEnumerable<EDeliveryNote>> GetByQuoteIdAsync(int quoteId);
Task<DeliveryNoteDto?> GetDtoByIdAsync(int id);
Task<DeliveryNoteDto?> GetDtoByDeliveryNoteNumberAsync(string deliveryNoteNumber);
Task<IEnumerable<DeliveryNoteDto>> GetDtosByQuoteIdAsync(int quoteId);
}
}

View File

@ -1,6 +1,6 @@
using Domain.Dtos.Sales;
using Microsoft.EntityFrameworkCore;
using Models.Interfaces;
using Domain.Entities;
using Models.Models;
namespace Models.Repositories
@ -9,27 +9,27 @@ namespace Models.Repositories
{
private readonly PhronCareOperationsHubContext _context = context;
public async Task<EDeliveryNote?> GetByIdAsync(int id)
public async Task<DeliveryNoteDto?> GetDtoByIdAsync(int id)
{
var entity = await _context.PhSDeliveryNotes
.Include(x => x.PhSDeliveryNoteDetails)
.AsNoTracking()
.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
.Include(x => x.PhSDeliveryNoteDetails)
.AsNoTracking()
.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
.Include(x => x.PhSDeliveryNoteDetails)
@ -39,12 +39,12 @@ namespace Models.Repositories
.ThenByDescending(x => x.Id)
.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,
DeliveryNoteNumber = source.Deliverynotenumber,
@ -58,17 +58,17 @@ namespace Models.Repositories
PrintCount = source.Printcount,
CreatedAt = source.Createdat,
ModifiedAt = source.Modifiedat,
PhSDeliveryNoteDetails = source.PhSDeliveryNoteDetails
Items = source.PhSDeliveryNoteDetails
.OrderBy(d => d.LineNumber)
.ThenBy(d => d.Id)
.Select(MapDeliveryNoteDetail)
.Select(MapDeliveryNoteItemDto)
.ToList()
};
}
private static EDeliveryNoteDetail MapDeliveryNoteDetail(PhSDeliveryNoteDetail source)
private static DeliveryNoteItemDto MapDeliveryNoteItemDto(PhSDeliveryNoteDetail source)
{
return new EDeliveryNoteDetail
return new DeliveryNoteItemDto
{
Id = source.Id,
DeliverynoteId = source.DeliverynoteId,

View File

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