diff --git a/Domain/Dtos/Stock/StockSnapshotItem.cs b/Domain/Dtos/Stock/StockSnapshotItem.cs
index ed52659..069f64a 100644
--- a/Domain/Dtos/Stock/StockSnapshotItem.cs
+++ b/Domain/Dtos/Stock/StockSnapshotItem.cs
@@ -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;
diff --git a/Domain/Entities/ELSExpeditionDetail.cs b/Domain/Entities/ELSExpeditionDetail.cs
index 5f0a530..4182716 100644
--- a/Domain/Entities/ELSExpeditionDetail.cs
+++ b/Domain/Entities/ELSExpeditionDetail.cs
@@ -17,6 +17,11 @@
///
public int ProductId { get; set; }
+ ///
+ /// Referencia a StockItem (PhLSM_StockItem)
+ ///
+ public int StockitemId { get; set; }
+
///
/// Cantidad solicitada del producto
///
diff --git a/Models/Models/PhLsmExpeditionDetail.cs b/Models/Models/PhLsmExpeditionDetail.cs
index eb5c16b..1eaa77d 100644
--- a/Models/Models/PhLsmExpeditionDetail.cs
+++ b/Models/Models/PhLsmExpeditionDetail.cs
@@ -20,6 +20,11 @@ public partial class PhLsmExpeditionDetail
///
public int ProductId { get; set; }
+ ///
+ /// Referencia a StockItem (PhLSM_StockItem)
+ ///
+ public int StockitemId { get; set; }
+
///
/// Cantidad solicitada del producto
///
@@ -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!;
}
diff --git a/Models/Models/PhLsmStockItem.cs b/Models/Models/PhLsmStockItem.cs
index bbc9f60..c8e9330 100644
--- a/Models/Models/PhLsmStockItem.cs
+++ b/Models/Models/PhLsmStockItem.cs
@@ -67,5 +67,9 @@ public partial class PhLsmStockItem
public virtual PhLsmStockLocation Location { get; set; } = null!;
+ public virtual ICollection PhLsmExpeditionDetails { get; set; } = new List();
+
+ public virtual ICollection PhLsmStockReservations { get; set; } = new List();
+
public virtual PhLsmProduct Product { get; set; } = null!;
}
diff --git a/Models/Models/PhLsmStockReservation.cs b/Models/Models/PhLsmStockReservation.cs
index 039f47a..fb86da2 100644
--- a/Models/Models/PhLsmStockReservation.cs
+++ b/Models/Models/PhLsmStockReservation.cs
@@ -1,4 +1,7 @@
-namespace Models.Models;
+using System;
+using System.Collections.Generic;
+
+namespace Models.Models;
///
/// 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.
diff --git a/Models/Models/PhronCareOperationsHubContext.cs b/Models/Models/PhronCareOperationsHubContext.cs
index d7a8df1..41c901a 100644
--- a/Models/Models/PhronCareOperationsHubContext.cs
+++ b/Models/Models/PhronCareOperationsHubContext.cs
@@ -6,10 +6,6 @@ namespace Models.Models;
public partial class PhronCareOperationsHubContext : DbContext
{
- public PhronCareOperationsHubContext()
- {
- }
-
public PhronCareOperationsHubContext(DbContextOptions options)
: base(options)
{
@@ -35,6 +31,8 @@ public partial class PhronCareOperationsHubContext : DbContext
public virtual DbSet PhLsmStockOuts { get; set; }
+ public virtual DbSet PhLsmStockReservations { get; set; }
+
public virtual DbSet PhLsmUnitOfMeasures { get; set; }
public virtual DbSet PhOhArcadocumentTypes { get; set; }
@@ -95,17 +93,6 @@ public partial class PhronCareOperationsHubContext : DbContext
public virtual DbSet 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(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(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(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__PhLSM_Un__3213E83FD70349B6");
diff --git a/phronCare.UIBlazor/Pages/Stock/Expeditions/ExpeditionCreate.razor b/phronCare.UIBlazor/Pages/Stock/Expeditions/ExpeditionCreate.razor
index 494ff91..d568f3b 100644
--- a/phronCare.UIBlazor/Pages/Stock/Expeditions/ExpeditionCreate.razor
+++ b/phronCare.UIBlazor/Pages/Stock/Expeditions/ExpeditionCreate.razor
@@ -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,
diff --git a/phronCare.UIBlazor/Pages/Stock/Shared/StockItemSelectorModal.razor b/phronCare.UIBlazor/Pages/Stock/Shared/StockItemSelectorModal.razor
index b918372..1f07d57 100644
--- a/phronCare.UIBlazor/Pages/Stock/Shared/StockItemSelectorModal.razor
+++ b/phronCare.UIBlazor/Pages/Stock/Shared/StockItemSelectorModal.razor
@@ -114,6 +114,7 @@
StockList = Snapshot.Select(s => new StockDisplayRow
{
ProductId = s.ProductId,
+ StockItemId = s.StockitemId,
ProductName = s.ProductName ?? "",
Batch = s.Batch,
Serial = s.Serial,