From 33fe012b090dff2ff4b9763bc636fa2987021820 Mon Sep 17 00:00:00 2001 From: leandro Date: Thu, 19 Mar 2026 17:41:49 -0300 Subject: [PATCH] feat(sales): incorporar DTO de lectura para Delivery Note #23 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Se agregan DeliveryNoteDto y DeliveryNoteItemDto - Se implementa proyección a DTO en PhSDeliveryNoteRepository - Se extiende IPhSDeliveryNoteRepository con métodos DTO - Se ajusta DeliveryNoteService para trabajar con DTO - Se actualiza DeliveryNoteController para devolver DTO - Se elimina exposición directa de EDeliveryNote en la API Closes #23 --- Core/Interfaces/IDeliveryNoteDom.cs | 16 +++++------ Core/Services/DeliveryNoteService.cs | 14 +++++----- Domain/Domain.csproj | 4 +++ Domain/Dtos/Sales/DeliveryNoteDto.cs | 26 +++++++++++++++++ Domain/Dtos/Sales/DeliveryNoteItemDto.cs | 22 +++++++++++++++ .../Interfaces/IPhSDeliveryNoteRepository.cs | 9 +++--- .../Repositories/PhSDeliveryNoteRepository.cs | 28 +++++++++---------- .../Sales/DeliveryNoteController.cs | 14 +++++----- 8 files changed, 92 insertions(+), 41 deletions(-) create mode 100644 Domain/Dtos/Sales/DeliveryNoteDto.cs create mode 100644 Domain/Dtos/Sales/DeliveryNoteItemDto.cs diff --git a/Core/Interfaces/IDeliveryNoteDom.cs b/Core/Interfaces/IDeliveryNoteDom.cs index be14f18..ab69e37 100644 --- a/Core/Interfaces/IDeliveryNoteDom.cs +++ b/Core/Interfaces/IDeliveryNoteDom.cs @@ -1,4 +1,4 @@ -using Domain.Entities; +using Domain.Dtos.Sales; /// /// Servicio de dominio para la gestión de consultas de Delivery Note (Remito Ventas). @@ -11,26 +11,26 @@ public interface IDeliveryNoteDom /// /// Identificador interno del Delivery Note. /// - /// La entidad si existe; en caso contrario, null. + /// El DTO si existe; en caso contrario, null. /// - Task GetByIdAsync(int id); + Task GetDtoByIdAsync(int id); /// /// Obtiene un Delivery Note a partir de su número de documento. /// /// Número del Delivery Note (ej: DN-00000001). /// - /// La entidad si existe; en caso contrario, null. + /// El DTO si existe; en caso contrario, null. /// - Task GetByDeliveryNoteNumberAsync(string deliveryNoteNumber); + Task GetDtoByDeliveryNoteNumberAsync(string deliveryNoteNumber); /// /// Obtiene todos los Delivery Notes asociados a un presupuesto (Quote). /// /// Identificador del presupuesto relacionado. /// - /// Colección de asociadas al presupuesto. + /// Colección de asociadas al presupuesto. /// Puede estar vacía si no existen registros. /// - Task> GetByQuoteIdAsync(int quoteId); -} \ No newline at end of file + Task> GetDtosByQuoteIdAsync(int quoteId); +} diff --git a/Core/Services/DeliveryNoteService.cs b/Core/Services/DeliveryNoteService.cs index af74d6e..e338989 100644 --- a/Core/Services/DeliveryNoteService.cs +++ b/Core/Services/DeliveryNoteService.cs @@ -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 GetByIdAsync(int id) + public Task 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 GetByDeliveryNoteNumberAsync(string deliveryNoteNumber) + public Task 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> GetByQuoteIdAsync(int quoteId) + public Task> 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); } } } diff --git a/Domain/Domain.csproj b/Domain/Domain.csproj index fa71b7a..e49e055 100644 --- a/Domain/Domain.csproj +++ b/Domain/Domain.csproj @@ -6,4 +6,8 @@ enable + + + + diff --git a/Domain/Dtos/Sales/DeliveryNoteDto.cs b/Domain/Dtos/Sales/DeliveryNoteDto.cs new file mode 100644 index 0000000..67e76a9 --- /dev/null +++ b/Domain/Dtos/Sales/DeliveryNoteDto.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; + +namespace Domain.Dtos.Sales +{ + /// + /// DTO de lectura para Delivery Note. + /// Representa la cabecera del remito con su detalle de ítems. + /// + 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 Items { get; set; } = new(); + } +} diff --git a/Domain/Dtos/Sales/DeliveryNoteItemDto.cs b/Domain/Dtos/Sales/DeliveryNoteItemDto.cs new file mode 100644 index 0000000..354dffa --- /dev/null +++ b/Domain/Dtos/Sales/DeliveryNoteItemDto.cs @@ -0,0 +1,22 @@ +using System; + +namespace Domain.Dtos.Sales +{ + /// + /// DTO de lectura para el detalle de un Delivery Note. + /// + 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; } + } +} diff --git a/Models/Interfaces/IPhSDeliveryNoteRepository.cs b/Models/Interfaces/IPhSDeliveryNoteRepository.cs index 29888d4..fb1b342 100644 --- a/Models/Interfaces/IPhSDeliveryNoteRepository.cs +++ b/Models/Interfaces/IPhSDeliveryNoteRepository.cs @@ -1,12 +1,11 @@ -using Domain.Entities; +using Domain.Dtos.Sales; namespace Models.Interfaces { public interface IPhSDeliveryNoteRepository { - Task GetByIdAsync(int id); - Task GetByDeliveryNoteNumberAsync(string deliveryNoteNumber); - Task> GetByQuoteIdAsync(int quoteId); + Task GetDtoByIdAsync(int id); + Task GetDtoByDeliveryNoteNumberAsync(string deliveryNoteNumber); + Task> GetDtosByQuoteIdAsync(int quoteId); } } - diff --git a/Models/Repositories/PhSDeliveryNoteRepository.cs b/Models/Repositories/PhSDeliveryNoteRepository.cs index a60badb..ba1cd55 100644 --- a/Models/Repositories/PhSDeliveryNoteRepository.cs +++ b/Models/Repositories/PhSDeliveryNoteRepository.cs @@ -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 GetByIdAsync(int id) + public async Task 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 GetByDeliveryNoteNumberAsync(string deliveryNoteNumber) + public async Task 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> GetByQuoteIdAsync(int quoteId) + public async Task> 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, @@ -84,4 +84,4 @@ namespace Models.Repositories }; } } -} \ No newline at end of file +} diff --git a/phronCare.API/Controllers/Sales/DeliveryNoteController.cs b/phronCare.API/Controllers/Sales/DeliveryNoteController.cs index ca30f09..d63c5ea 100644 --- a/phronCare.API/Controllers/Sales/DeliveryNoteController.cs +++ b/phronCare.API/Controllers/Sales/DeliveryNoteController.cs @@ -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> GetById(int id) + public async Task> 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> GetByDeliveryNoteNumber(string deliveryNoteNumber) + public async Task> 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>> GetByQuoteId(int quoteId) + public async Task>> GetByQuoteId(int quoteId) { try { - var deliveryNotes = await _deliveryNoteService.GetByQuoteIdAsync(quoteId); + var deliveryNotes = await _deliveryNoteService.GetDtosByQuoteIdAsync(quoteId); return Ok(deliveryNotes); } catch (Exception ex)