Merge pull request 'feat(expeditions): persist stockitem_id in ExpeditionDetails (traceability base)' (#4) from feature/leandro/3-persist-stockitemid-expeditiondetail into master
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 4m26s
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 4m26s
Reviewed-on: http://saludlab.com.ar:3000/leandro/phronCare/pulls/4
This commit is contained in:
commit
55924ca07a
@ -7,6 +7,7 @@
|
||||
public class StockSnapshotItem
|
||||
{
|
||||
public int ProductId { get; set; }
|
||||
public int StockitemId { get; set; }
|
||||
public string? ProductName { get; set; } = string.Empty;
|
||||
public int LocationId { get; set; }
|
||||
public string Batch { get; set; } = string.Empty;
|
||||
|
||||
@ -17,6 +17,11 @@
|
||||
/// </summary>
|
||||
public int ProductId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Referencia a StockItem (PhLSM_StockItem)
|
||||
/// </summary>
|
||||
public int StockitemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cantidad solicitada del producto
|
||||
/// </summary>
|
||||
|
||||
@ -20,6 +20,11 @@ public partial class PhLsmExpeditionDetail
|
||||
/// </summary>
|
||||
public int ProductId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Referencia a StockItem (PhLSM_StockItem)
|
||||
/// </summary>
|
||||
public int StockitemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cantidad solicitada del producto
|
||||
/// </summary>
|
||||
@ -68,4 +73,6 @@ public partial class PhLsmExpeditionDetail
|
||||
public virtual PhLsmExpeditionHeader Expedition { get; set; } = null!;
|
||||
|
||||
public virtual PhLsmProduct Product { get; set; } = null!;
|
||||
|
||||
public virtual PhLsmStockItem Stockitem { get; set; } = null!;
|
||||
}
|
||||
|
||||
@ -67,5 +67,9 @@ public partial class PhLsmStockItem
|
||||
|
||||
public virtual PhLsmStockLocation Location { get; set; } = null!;
|
||||
|
||||
public virtual ICollection<PhLsmExpeditionDetail> PhLsmExpeditionDetails { get; set; } = new List<PhLsmExpeditionDetail>();
|
||||
|
||||
public virtual ICollection<PhLsmStockReservation> PhLsmStockReservations { get; set; } = new List<PhLsmStockReservation>();
|
||||
|
||||
public virtual PhLsmProduct Product { get; set; } = null!;
|
||||
}
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
namespace Models.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Models.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Reservas de stock por origen genérico (source_type/source_id). Cada fila bloquea cantidad sobre un StockItem. No duplica lote/serie/vencimiento; se resuelve por JOIN a PhLSM_StockItem.
|
||||
|
||||
@ -6,10 +6,6 @@ namespace Models.Models;
|
||||
|
||||
public partial class PhronCareOperationsHubContext : DbContext
|
||||
{
|
||||
public PhronCareOperationsHubContext()
|
||||
{
|
||||
}
|
||||
|
||||
public PhronCareOperationsHubContext(DbContextOptions<PhronCareOperationsHubContext> options)
|
||||
: base(options)
|
||||
{
|
||||
@ -35,6 +31,8 @@ public partial class PhronCareOperationsHubContext : DbContext
|
||||
|
||||
public virtual DbSet<PhLsmStockOut> PhLsmStockOuts { get; set; }
|
||||
|
||||
public virtual DbSet<PhLsmStockReservation> PhLsmStockReservations { get; set; }
|
||||
|
||||
public virtual DbSet<PhLsmUnitOfMeasure> PhLsmUnitOfMeasures { get; set; }
|
||||
|
||||
public virtual DbSet<PhOhArcadocumentType> PhOhArcadocumentTypes { get; set; }
|
||||
@ -95,17 +93,6 @@ public partial class PhronCareOperationsHubContext : DbContext
|
||||
|
||||
public virtual DbSet<PhSQuoteTaxis> PhSQuoteTaxes { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
#region VERSION DOCKER
|
||||
{
|
||||
if (!optionsBuilder.IsConfigured)
|
||||
{
|
||||
// Dejarlo vacío para usar la configuración externa desde Program.cs o Startup.cs
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
//=> optionsBuilder.UseSqlServer("data source=srv01.saludlab.com.ar,39458;initial catalog=phronCare_OperationsHub;User ID=sa;Password=HS|s[~xxQzTo/n>9jO;encrypt=False;trustServerCertificate=True;MultipleActiveResultSets=True");
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.UseCollation("Modern_Spanish_CI_AS");
|
||||
@ -116,6 +103,14 @@ public partial class PhronCareOperationsHubContext : DbContext
|
||||
|
||||
entity.ToTable("PhLSM_ExpeditionDetails");
|
||||
|
||||
entity.HasIndex(e => e.ExpeditionId, "IX_PhLSM_ExpeditionDetails_Expedition");
|
||||
|
||||
entity.HasIndex(e => new { e.ExpeditionId, e.StockitemId }, "IX_PhLSM_ExpeditionDetails_Expedition_StockItem");
|
||||
|
||||
entity.HasIndex(e => e.ProductId, "IX_PhLSM_ExpeditionDetails_Product");
|
||||
|
||||
entity.HasIndex(e => e.StockitemId, "IX_PhLSM_ExpeditionDetails_StockItem");
|
||||
|
||||
entity.Property(e => e.Id)
|
||||
.HasComment("Identificador interno del ítem de expedición")
|
||||
.HasColumnName("id");
|
||||
@ -162,6 +157,9 @@ public partial class PhronCareOperationsHubContext : DbContext
|
||||
.HasMaxLength(100)
|
||||
.HasComment("Número de serie de la unidad individual, según etiqueta de trazabilidad del fabricante.")
|
||||
.HasColumnName("serial");
|
||||
entity.Property(e => e.StockitemId)
|
||||
.HasComment("Referencia a StockItem (PhLSM_StockItem)")
|
||||
.HasColumnName("stockitem_id");
|
||||
|
||||
entity.HasOne(d => d.Expedition).WithMany(p => p.PhLsmExpeditionDetails)
|
||||
.HasForeignKey(d => d.ExpeditionId)
|
||||
@ -172,6 +170,11 @@ public partial class PhronCareOperationsHubContext : DbContext
|
||||
.HasForeignKey(d => d.ProductId)
|
||||
.OnDelete(DeleteBehavior.ClientSetNull)
|
||||
.HasConstraintName("FK_PhLSM_ExpeditionDetails_PhLSM_Product");
|
||||
|
||||
entity.HasOne(d => d.Stockitem).WithMany(p => p.PhLsmExpeditionDetails)
|
||||
.HasForeignKey(d => d.StockitemId)
|
||||
.OnDelete(DeleteBehavior.ClientSetNull)
|
||||
.HasConstraintName("FK_PhLSM_ExpeditionDetails_PhLSM_StockItem");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<PhLsmExpeditionHeader>(entity =>
|
||||
@ -180,6 +183,8 @@ public partial class PhronCareOperationsHubContext : DbContext
|
||||
|
||||
entity.ToTable("PhLSM_ExpeditionHeaders");
|
||||
|
||||
entity.HasIndex(e => e.Expeditionnumber, "UX_PhLSM_ExpeditionHeaders_Number").IsUnique();
|
||||
|
||||
entity.Property(e => e.Id)
|
||||
.HasComment("Identificador interno de la expedición")
|
||||
.HasColumnName("id");
|
||||
@ -641,6 +646,64 @@ public partial class PhronCareOperationsHubContext : DbContext
|
||||
.HasConstraintName("FK_PhLSM_StockOut_PhLSM_Product");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<PhLsmStockReservation>(entity =>
|
||||
{
|
||||
entity.ToTable("PhLSM_StockReservation", tb => tb.HasComment("Reservas de stock por origen genérico (source_type/source_id). Cada fila bloquea cantidad sobre un StockItem. No duplica lote/serie/vencimiento; se resuelve por JOIN a PhLSM_StockItem."));
|
||||
|
||||
entity.HasIndex(e => new { e.SourceType, e.SourceId, e.Status }, "IX_PhLSM_StockReservation_Source_Status");
|
||||
|
||||
entity.HasIndex(e => e.StockitemId, "IX_PhLSM_StockReservation_StockItem_Reserved").HasFilter("([status]=(1))");
|
||||
|
||||
entity.HasIndex(e => new { e.SourceType, e.SourceId, e.StockitemId }, "UX_PhLSM_StockReservation_Source_StockItem_Consumed")
|
||||
.IsUnique()
|
||||
.HasFilter("([status]=(3))");
|
||||
|
||||
entity.HasIndex(e => new { e.SourceType, e.SourceId, e.StockitemId }, "UX_PhLSM_StockReservation_Source_StockItem_Reserved")
|
||||
.IsUnique()
|
||||
.HasFilter("([status]=(1))");
|
||||
|
||||
entity.Property(e => e.Id)
|
||||
.HasComment("Identificador autoincremental de la reserva.")
|
||||
.HasColumnName("id");
|
||||
entity.Property(e => e.Createdat)
|
||||
.HasPrecision(0)
|
||||
.HasDefaultValueSql("(sysutcdatetime())")
|
||||
.HasComment("Fecha/hora de creación (UTC).")
|
||||
.HasColumnName("createdat");
|
||||
entity.Property(e => e.Modifiedat)
|
||||
.HasPrecision(0)
|
||||
.HasComment("Última modificación (UTC). Puede ser NULL si nunca se actualizó.")
|
||||
.HasColumnName("modifiedat");
|
||||
entity.Property(e => e.ReservedQuantity)
|
||||
.HasComment("Cantidad reservada (bloqueada). No disponible mientras status=1 (Reserved).")
|
||||
.HasColumnType("decimal(18, 2)")
|
||||
.HasColumnName("reserved_quantity");
|
||||
entity.Property(e => e.Rowversion)
|
||||
.IsRowVersion()
|
||||
.IsConcurrencyToken()
|
||||
.HasComment("Token de concurrencia optimista (ROWVERSION) para actualizaciones seguras.")
|
||||
.HasColumnName("rowversion");
|
||||
entity.Property(e => e.SourceId)
|
||||
.HasComment("Identificador del origen. Ej.: expedition_id cuando source_type=1.")
|
||||
.HasColumnName("source_id");
|
||||
entity.Property(e => e.SourceType)
|
||||
.HasDefaultValue((byte)1)
|
||||
.HasComment("Tipo de origen de la reserva. 1=Expedition (extensible a futuros orígenes).")
|
||||
.HasColumnName("source_type");
|
||||
entity.Property(e => e.Status)
|
||||
.HasDefaultValue(1)
|
||||
.HasComment("Estado de la reserva: 1=Reserved, 2=Released, 3=Consumed.")
|
||||
.HasColumnName("status");
|
||||
entity.Property(e => e.StockitemId)
|
||||
.HasComment("Referencia al StockItem exacto bloqueado (FK a PhLSM_StockItem). Define producto/ubicación/trazabilidad por JOIN.")
|
||||
.HasColumnName("stockitem_id");
|
||||
|
||||
entity.HasOne(d => d.Stockitem).WithMany(p => p.PhLsmStockReservations)
|
||||
.HasForeignKey(d => d.StockitemId)
|
||||
.OnDelete(DeleteBehavior.ClientSetNull)
|
||||
.HasConstraintName("FK_PhLSM_StockReservation_StockItem");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<PhLsmUnitOfMeasure>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("PK__PhLSM_Un__3213E83FD70349B6");
|
||||
|
||||
@ -360,6 +360,12 @@
|
||||
existing.Expiration = exp;
|
||||
existing.LocationId = s.LocationId;
|
||||
existing.TraceabilityType = s.TraceabilityType; // UI only
|
||||
|
||||
// 🆕 AGREGAR ESTO
|
||||
if (s.StockItemId != 0 && existing.StockitemId != s.StockItemId)
|
||||
{
|
||||
existing.StockitemId = s.StockItemId;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -374,7 +380,8 @@
|
||||
Expiration = exp,
|
||||
TraceabilityType = s.TraceabilityType, // UI only (no DB)
|
||||
Serial = s.Serial,
|
||||
LocationId = s.LocationId
|
||||
LocationId = s.LocationId,
|
||||
StockitemId = s.StockItemId
|
||||
});
|
||||
}
|
||||
// si newQty == 0 y no existía, no hacemos nada
|
||||
@ -397,6 +404,7 @@
|
||||
return new StockSnapshotItem
|
||||
{
|
||||
ProductId = d.ProductId,
|
||||
StockitemId = d.StockitemId, // 🆕 incluir StockitemId en el snapshot
|
||||
ProductName = d.ProductName,
|
||||
LocationId = d.LocationId,
|
||||
Batch = d.Batch ?? string.Empty,
|
||||
|
||||
@ -114,6 +114,7 @@
|
||||
StockList = Snapshot.Select(s => new StockDisplayRow
|
||||
{
|
||||
ProductId = s.ProductId,
|
||||
StockItemId = s.StockitemId,
|
||||
ProductName = s.ProductName ?? "<Producto sin descripción>",
|
||||
Batch = s.Batch,
|
||||
Serial = s.Serial,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user