From a498c38d841fb059ecb53d6eaf3dd2086dc47b82 Mon Sep 17 00:00:00 2001 From: leandro Date: Thu, 19 Mar 2026 01:37:43 -0300 Subject: [PATCH] feat(sales): agregar servicio core de lectura para Delivery Note Closes #17 --- Core/Interfaces/IDeliveryNoteDom.cs | 36 +++++ Core/Services/DeliveryNoteService.cs | 35 +++++ PhLSM_Expedition_CheckStockItemConflicts.sql | 44 ------ PhLSM_StockItemIdList.sql | 5 - PhLSM_Stock_GetAvailabilityByStockItemIds.sql | 36 ----- Story 9 - Stock Reservation.sql | 135 ------------------ phronCare.sln | 24 ---- 7 files changed, 71 insertions(+), 244 deletions(-) create mode 100644 Core/Interfaces/IDeliveryNoteDom.cs create mode 100644 Core/Services/DeliveryNoteService.cs delete mode 100644 PhLSM_Expedition_CheckStockItemConflicts.sql delete mode 100644 PhLSM_StockItemIdList.sql delete mode 100644 PhLSM_Stock_GetAvailabilityByStockItemIds.sql delete mode 100644 Story 9 - Stock Reservation.sql diff --git a/Core/Interfaces/IDeliveryNoteDom.cs b/Core/Interfaces/IDeliveryNoteDom.cs new file mode 100644 index 0000000..be14f18 --- /dev/null +++ b/Core/Interfaces/IDeliveryNoteDom.cs @@ -0,0 +1,36 @@ +using Domain.Entities; + +/// +/// Servicio de dominio para la gestión de consultas de Delivery Note (Remito Ventas). +/// Encapsula el acceso a datos y expone operaciones de lectura para la capa superior. +/// +public interface IDeliveryNoteDom +{ + /// + /// Obtiene un Delivery Note por su identificador único. + /// + /// Identificador interno del Delivery Note. + /// + /// La entidad si existe; en caso contrario, null. + /// + Task GetByIdAsync(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. + /// + Task GetByDeliveryNoteNumberAsync(string deliveryNoteNumber); + + /// + /// Obtiene todos los Delivery Notes asociados a un presupuesto (Quote). + /// + /// Identificador del presupuesto relacionado. + /// + /// Colección de asociadas al presupuesto. + /// Puede estar vacía si no existen registros. + /// + Task> GetByQuoteIdAsync(int quoteId); +} \ No newline at end of file diff --git a/Core/Services/DeliveryNoteService.cs b/Core/Services/DeliveryNoteService.cs new file mode 100644 index 0000000..af74d6e --- /dev/null +++ b/Core/Services/DeliveryNoteService.cs @@ -0,0 +1,35 @@ +using Core.Interfaces; +using Domain.Entities; +using Models.Interfaces; + +namespace Core.Services +{ + public class DeliveryNoteService(IPhSDeliveryNoteRepository deliveryNoteRepository) : IDeliveryNoteDom + { + private readonly IPhSDeliveryNoteRepository _deliveryNoteRepository = deliveryNoteRepository; + + public Task GetByIdAsync(int id) + { + if (id <= 0) + throw new ArgumentOutOfRangeException(nameof(id), "El identificador del remito es inválido."); + + return _deliveryNoteRepository.GetByIdAsync(id); + } + + public Task GetByDeliveryNoteNumberAsync(string deliveryNoteNumber) + { + if (string.IsNullOrWhiteSpace(deliveryNoteNumber)) + throw new ArgumentException("El número de remito es obligatorio.", nameof(deliveryNoteNumber)); + + return _deliveryNoteRepository.GetByDeliveryNoteNumberAsync(deliveryNoteNumber.Trim()); + } + + public Task> GetByQuoteIdAsync(int quoteId) + { + if (quoteId <= 0) + throw new ArgumentOutOfRangeException(nameof(quoteId), "El identificador del presupuesto es inválido."); + + return _deliveryNoteRepository.GetByQuoteIdAsync(quoteId); + } + } +} diff --git a/PhLSM_Expedition_CheckStockItemConflicts.sql b/PhLSM_Expedition_CheckStockItemConflicts.sql deleted file mode 100644 index b265783..0000000 --- a/PhLSM_Expedition_CheckStockItemConflicts.sql +++ /dev/null @@ -1,44 +0,0 @@ -USE [phronCare_OperationsHub] -GO - -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO - --- ============================================= --- Procedure: PhLSM_Expedition_CheckStockItemConflicts --- Module: Logistics / Stock (PhLSM) --- Purpose: Detect serialized stock items already assigned --- to active expeditions. --- Author: Leandro Rojas --- Created: 2026-03-05 --- ============================================= - -ALTER PROCEDURE [dbo].[PhLSM_Expedition_CheckStockItemConflicts] -( - @StockItemIds dbo.PhLSM_StockItemIdList READONLY, - @IgnoreExpeditionId INT = NULL -) -AS -BEGIN - SET NOCOUNT ON; - - SELECT - d.stockitem_id AS StockitemId, - h.id AS ExpeditionId, - h.expeditionnumber AS Expeditionnumber, - h.status AS Status - FROM dbo.PhLSM_ExpeditionDetails d - INNER JOIN @StockItemIds ids - ON ids.stockitem_id = d.stockitem_id - INNER JOIN dbo.PhLSM_ExpeditionHeaders h - ON h.id = d.expedition_id - INNER JOIN dbo.PhLSM_StockItem si - ON si.id = d.stockitem_id - WHERE h.status NOT IN (5,6) -- 5=Cerrada, 6=Anulada - AND (@IgnoreExpeditionId IS NULL OR h.id <> @IgnoreExpeditionId) - AND si.serial IS NOT NULL - AND LTRIM(RTRIM(si.serial)) <> ''; -END -GO \ No newline at end of file diff --git a/PhLSM_StockItemIdList.sql b/PhLSM_StockItemIdList.sql deleted file mode 100644 index 66d899c..0000000 --- a/PhLSM_StockItemIdList.sql +++ /dev/null @@ -1,5 +0,0 @@ -CREATE TYPE dbo.PhLSM_StockItemIdList AS TABLE -( - stockitem_id INT NOT NULL -); -GO \ No newline at end of file diff --git a/PhLSM_Stock_GetAvailabilityByStockItemIds.sql b/PhLSM_Stock_GetAvailabilityByStockItemIds.sql deleted file mode 100644 index 0a36140..0000000 --- a/PhLSM_Stock_GetAvailabilityByStockItemIds.sql +++ /dev/null @@ -1,36 +0,0 @@ -USE [phronCare_OperationsHub] -GO - -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO - --- ============================================= --- Procedure: PhLSM_Stock_GetAvailabilityByStockItemIds --- Module: Logistics / Stock (PhLSM) --- Purpose: Returns quantity and availability data --- for the requested stock items. --- Author: Leandro Rojas --- Created: 2026-03-09 --- ============================================= - -CREATE OR ALTER PROCEDURE [dbo].[PhLSM_Stock_GetAvailabilityByStockItemIds] -( - @StockItemIds dbo.PhLSM_StockItemIdList READONLY -) -AS -BEGIN - SET NOCOUNT ON; - - SELECT - si.id AS StockitemId, - si.quantity AS Quantity, - ISNULL(si.reserved_quantity, 0) AS ReservedQuantity, - si.quantity - ISNULL(si.reserved_quantity, 0) AS AvailableQuantity, - si.serial AS Serial - FROM dbo.PhLSM_StockItem si - INNER JOIN @StockItemIds ids - ON ids.stockitem_id = si.id; -END -GO \ No newline at end of file diff --git a/Story 9 - Stock Reservation.sql b/Story 9 - Stock Reservation.sql deleted file mode 100644 index e89957a..0000000 --- a/Story 9 - Stock Reservation.sql +++ /dev/null @@ -1,135 +0,0 @@ -/* ========================================================= - VERIFICACIÓN STORY #9 - Expedición -> EnTransito + reservas de stock - ========================================================= */ - -SET NOCOUNT ON; - -DECLARE @ExpeditionNumber VARCHAR(50) = 'X-00000054'; -- cambiar - -DECLARE @ExpeditionId INT; - -SELECT @ExpeditionId = id -FROM dbo.PhLSM_ExpeditionHeaders -WHERE expeditionnumber = @ExpeditionNumber; - -IF @ExpeditionId IS NULL -BEGIN - RAISERROR('Expedición no encontrada',16,1); - RETURN; -END - -PRINT 'ExpeditionId: ' + CAST(@ExpeditionId AS VARCHAR); - -------------------------------------------------------------- --- 1. CABECERA -------------------------------------------------------------- -PRINT '===== CABECERA ====='; - -SELECT - id, - expeditionnumber, - issuedate, - status, - observations -FROM dbo.PhLSM_ExpeditionHeaders -WHERE id = @ExpeditionId; - - -------------------------------------------------------------- --- 2. DETALLES -------------------------------------------------------------- -PRINT '===== DETALLES ====='; - -SELECT - d.id, - d.expedition_id, - d.product_id, - d.stockitem_id, - d.quantity, - d.batch, - d.serial, - d.expiration -FROM dbo.PhLSM_ExpeditionDetails d -WHERE d.expedition_id = @ExpeditionId -ORDER BY d.id; - - -------------------------------------------------------------- --- 3. RESERVAS CREADAS -------------------------------------------------------------- -PRINT '===== RESERVAS ====='; - -SELECT - r.id, - r.source_type, - r.source_id, - r.stockitem_id, - r.reserved_quantity, - r.status, - r.createdat -FROM dbo.PhLSM_StockReservation r -WHERE r.source_type = 1 -AND r.source_id = @ExpeditionId -ORDER BY r.id; - - -------------------------------------------------------------- --- 4. STOCK ITEMS AFECTADOS -------------------------------------------------------------- -PRINT '===== STOCK ITEMS ====='; - -SELECT - si.id, - si.product_id, - si.location_id, - si.quantity, - si.reserved_quantity, - (si.quantity - si.reserved_quantity) AS available -FROM dbo.PhLSM_StockItem si -WHERE si.id IN -( - SELECT stockitem_id - FROM dbo.PhLSM_ExpeditionDetails - WHERE expedition_id = @ExpeditionId -); - - -------------------------------------------------------------- --- 5. VALIDACIÓN DETALLE VS RESERVA -------------------------------------------------------------- -PRINT '===== VALIDACION ====='; - -SELECT - d.id AS detail_id, - d.stockitem_id, - d.quantity AS requested, - r.reserved_quantity, - CASE - WHEN r.id IS NULL THEN 'FALTA RESERVA' - WHEN r.reserved_quantity <> d.quantity THEN 'CANTIDAD DISTINTA' - ELSE 'OK' - END AS resultado -FROM dbo.PhLSM_ExpeditionDetails d -LEFT JOIN dbo.PhLSM_StockReservation r - ON r.source_id = d.expedition_id - AND r.stockitem_id = d.stockitem_id - AND r.source_type = 1 - AND r.status = 1 -WHERE d.expedition_id = @ExpeditionId; - - -------------------------------------------------------------- --- 6. CHEQUEO DE DUPLICADOS -------------------------------------------------------------- -PRINT '===== DUPLICADOS ====='; - -SELECT - stockitem_id, - COUNT(*) AS cantidad -FROM dbo.PhLSM_StockReservation -WHERE source_type = 1 -AND source_id = @ExpeditionId -AND status = 1 -GROUP BY stockitem_id -HAVING COUNT(*) > 1; \ No newline at end of file diff --git a/phronCare.sln b/phronCare.sln index e837413..e07462f 100644 --- a/phronCare.sln +++ b/phronCare.sln @@ -43,26 +43,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1.5 Documents", "1.5 Docume EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Documents", "Documents\Documents.csproj", "{0EFF27D3-C585-49F3-BBB5-A5E99C52207B}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2.Database", "2.Database", "{E93C8350-6A6C-40F1-99C0-14CF7459EA8B}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Migrations", "Migrations", "{5826BD19-0018-4F9C-B405-9BAB997CC8C7}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Types", "Types", "{3C3276F6-7320-4AB8-9C1E-1893E4646FD4}" - ProjectSection(SolutionItems) = preProject - PhLSM_StockItemIdList.sql = PhLSM_StockItemIdList.sql - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Procedures", "Procedures", "{E4F7BA13-B838-42D5-AADD-481DD76DDD5E}" - ProjectSection(SolutionItems) = preProject - PhLSM_Expedition_CheckStockItemConflicts.sql = PhLSM_Expedition_CheckStockItemConflicts.sql - PhLSM_Stock_GetAvailabilityByStockItemIds.sql = PhLSM_Stock_GetAvailabilityByStockItemIds.sql - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Verifications", "Verifications", "{85918AF0-7D8E-41B6-9157-BD2ADF05BD64}" - ProjectSection(SolutionItems) = preProject - Story 9 - Stock Reservation.sql = Story 9 - Stock Reservation.sql - EndProjectSection -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -124,10 +104,6 @@ Global {34FC5538-4779-41F5-8355-7866B1395A4F} = {13328F60-28A6-446D-9935-23866F3F3D9D} {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {74280C0B-F2CC-4A3E-86D6-05530F9766D5} {0EFF27D3-C585-49F3-BBB5-A5E99C52207B} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} - {5826BD19-0018-4F9C-B405-9BAB997CC8C7} = {E93C8350-6A6C-40F1-99C0-14CF7459EA8B} - {3C3276F6-7320-4AB8-9C1E-1893E4646FD4} = {E93C8350-6A6C-40F1-99C0-14CF7459EA8B} - {E4F7BA13-B838-42D5-AADD-481DD76DDD5E} = {E93C8350-6A6C-40F1-99C0-14CF7459EA8B} - {85918AF0-7D8E-41B6-9157-BD2ADF05BD64} = {E93C8350-6A6C-40F1-99C0-14CF7459EA8B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {92DE3FEB-7D7E-4C78-BE8C-34931CA1DAED}