Merge pull request 'feat(sales): scaffold EF para Delivery Notes' (#12) from feature/leandro/11-deliverynote-scaffold into master
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 2m17s

Reviewed-on: http://saludlab.com.ar:3000/leandro/phronCare/pulls/12
This commit is contained in:
Leandro Hernan Rojas 2026-03-16 22:45:04 +00:00
commit ada3c04b9b
8 changed files with 313 additions and 0 deletions

View File

@ -29,6 +29,8 @@ public partial class PhSCustomer
public virtual ICollection<PhSCustomerDocument> PhSCustomerDocuments { get; set; } = new List<PhSCustomerDocument>();
public virtual ICollection<PhSDeliveryNote> PhSDeliveryNotes { get; set; } = new List<PhSDeliveryNote>();
public virtual ICollection<PhSPatient> PhSPatients { get; set; } = new List<PhSPatient>();
public virtual PhOhTaxCondition? TaxCondition { get; set; }

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
namespace Models.Models;
public partial class PhSDeliveryNote
{
public int Id { get; set; }
public string Deliverynotenumber { get; set; } = null!;
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; } = null!;
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 virtual PhSCustomer Customer { get; set; } = null!;
public virtual ICollection<PhSDeliveryNoteDetail> PhSDeliveryNoteDetails { get; set; } = new List<PhSDeliveryNoteDetail>();
public virtual PhSQuoteHeader? Quote { get; set; }
}

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
namespace Models.Models;
public partial class PhSDeliveryNoteDetail
{
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; } = null!;
public decimal Quantity { get; set; }
public string Notes { get; set; } = null!;
public DateTime Createdat { get; set; }
public DateTime? Modifiedat { get; set; }
public virtual PhSDeliveryNote Deliverynote { get; set; } = null!;
public virtual PhSQuoteDetail? QuoteDetail { get; set; }
}

View File

@ -68,6 +68,8 @@ public partial class PhSQuoteDetail
/// </summary>
public DateTime? Modifiedat { get; set; }
public virtual ICollection<PhSDeliveryNoteDetail> PhSDeliveryNoteDetails { get; set; } = new List<PhSDeliveryNoteDetail>();
public virtual PhSProduct Product { get; set; } = null!;
public virtual PhSQuoteHeader Quoteheader { get; set; } = null!;

View File

@ -130,6 +130,8 @@ public partial class PhSQuoteHeader
public virtual PhSPaymentTerm? Paymentterm { get; set; }
public virtual ICollection<PhSDeliveryNote> PhSDeliveryNotes { get; set; } = new List<PhSDeliveryNote>();
public virtual ICollection<PhSQuoteAdjustment> PhSQuoteAdjustments { get; set; } = new List<PhSQuoteAdjustment>();
public virtual ICollection<PhSQuoteDetail> PhSQuoteDetails { get; set; } = new List<PhSQuoteDetail>();

View File

@ -57,6 +57,10 @@ public partial class PhronCareOperationsHubContext : DbContext
public virtual DbSet<PhSCustomerDocument> PhSCustomerDocuments { get; set; }
public virtual DbSet<PhSDeliveryNote> PhSDeliveryNotes { get; set; }
public virtual DbSet<PhSDeliveryNoteDetail> PhSDeliveryNoteDetails { get; set; }
public virtual DbSet<PhSDocumentType> PhSDocumentTypes { get; set; }
public virtual DbSet<PhSFormSeries> PhSFormSeries { get; set; }
@ -1033,6 +1037,98 @@ public partial class PhronCareOperationsHubContext : DbContext
.HasConstraintName("FK_PhS_CustomerDocuments_PhS_DocumentTypes");
});
modelBuilder.Entity<PhSDeliveryNote>(entity =>
{
entity.ToTable("PhS_DeliveryNotes");
entity.HasIndex(e => e.CustomerId, "IX_PhS_DeliveryNotes_customer_id");
entity.HasIndex(e => e.Issuedate, "IX_PhS_DeliveryNotes_issuedate");
entity.HasIndex(e => e.QuoteId, "IX_PhS_DeliveryNotes_quote_id");
entity.HasIndex(e => e.Status, "IX_PhS_DeliveryNotes_status");
entity.HasIndex(e => e.Deliverynotenumber, "UQ_PhS_DeliveryNotes_deliverynotenumber").IsUnique();
entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.Createdat)
.HasDefaultValueSql("(getdate())")
.HasColumnType("datetime")
.HasColumnName("createdat");
entity.Property(e => e.CustomerId).HasColumnName("customer_id");
entity.Property(e => e.Deliverynotenumber)
.HasMaxLength(20)
.IsUnicode(false)
.HasColumnName("deliverynotenumber");
entity.Property(e => e.ExtrainfoJson).HasColumnName("extrainfo_json");
entity.Property(e => e.Issuedate)
.HasColumnType("datetime")
.HasColumnName("issuedate");
entity.Property(e => e.Modifiedat)
.HasColumnType("datetime")
.HasColumnName("modifiedat");
entity.Property(e => e.Observations)
.HasMaxLength(1000)
.HasColumnName("observations");
entity.Property(e => e.Printcount).HasColumnName("printcount");
entity.Property(e => e.QuoteId).HasColumnName("quote_id");
entity.Property(e => e.SalesinvoiceId).HasColumnName("salesinvoice_id");
entity.Property(e => e.Status)
.HasMaxLength(20)
.IsUnicode(false)
.HasColumnName("status");
entity.HasOne(d => d.Customer).WithMany(p => p.PhSDeliveryNotes)
.HasForeignKey(d => d.CustomerId)
.OnDelete(DeleteBehavior.ClientSetNull);
entity.HasOne(d => d.Quote).WithMany(p => p.PhSDeliveryNotes).HasForeignKey(d => d.QuoteId);
});
modelBuilder.Entity<PhSDeliveryNoteDetail>(entity =>
{
entity.ToTable("PhS_DeliveryNoteDetails");
entity.HasIndex(e => e.DeliverynoteId, "IX_PhS_DeliveryNoteDetails_deliverynote_id");
entity.HasIndex(e => new { e.DeliverynoteId, e.LineNumber }, "IX_PhS_DeliveryNoteDetails_deliverynote_id_line_number");
entity.HasIndex(e => new { e.OriginType, e.OriginId }, "IX_PhS_DeliveryNoteDetails_origin_type_origin_id");
entity.HasIndex(e => e.QuoteDetailId, "IX_PhS_DeliveryNoteDetails_quote_detail_id");
entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.Createdat)
.HasDefaultValueSql("(getdate())")
.HasColumnType("datetime")
.HasColumnName("createdat");
entity.Property(e => e.DeliverynoteId).HasColumnName("deliverynote_id");
entity.Property(e => e.Description)
.HasMaxLength(500)
.HasColumnName("description");
entity.Property(e => e.LineNumber).HasColumnName("line_number");
entity.Property(e => e.Modifiedat)
.HasColumnType("datetime")
.HasColumnName("modifiedat");
entity.Property(e => e.Notes)
.HasMaxLength(1000)
.HasDefaultValue("")
.HasColumnName("notes");
entity.Property(e => e.OriginId).HasColumnName("origin_id");
entity.Property(e => e.OriginType).HasColumnName("origin_type");
entity.Property(e => e.Quantity)
.HasColumnType("decimal(18, 2)")
.HasColumnName("quantity");
entity.Property(e => e.QuoteDetailId).HasColumnName("quote_detail_id");
entity.HasOne(d => d.Deliverynote).WithMany(p => p.PhSDeliveryNoteDetails)
.HasForeignKey(d => d.DeliverynoteId)
.OnDelete(DeleteBehavior.ClientSetNull);
entity.HasOne(d => d.QuoteDetail).WithMany(p => p.PhSDeliveryNoteDetails).HasForeignKey(d => d.QuoteDetailId);
});
modelBuilder.Entity<PhSDocumentType>(entity =>
{
entity.ToTable("PhS_DocumentTypes");

View File

@ -0,0 +1,135 @@
/* =========================================================
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;

View File

@ -58,6 +58,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Procedures", "Procedures",
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
@ -122,6 +127,7 @@ Global
{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}