Add Fix Scanner GS1, Factory Code
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 9m18s
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 9m18s
This commit is contained in:
parent
914702e4da
commit
2719bd4d9e
@ -30,7 +30,7 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Número de serie de la unidad individual, según etiqueta de trazabilidad del fabricante.
|
/// Número de serie de la unidad individual, según etiqueta de trazabilidad del fabricante.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? Serial { get; set; }
|
public string Serial { get; set; } = string.Empty ;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fecha de vencimiento (si aplica)
|
/// Fecha de vencimiento (si aplica)
|
||||||
|
|||||||
@ -109,7 +109,7 @@ namespace Models.Repositories.Stock
|
|||||||
int page,
|
int page,
|
||||||
int take)
|
int take)
|
||||||
{
|
{
|
||||||
// 0) Si no hay NINGÚN dato parseado, no traigas todo
|
// 0) Sin ningún dato parseado -> vacío (evitar traer todo)
|
||||||
if (string.IsNullOrWhiteSpace(gtin) &&
|
if (string.IsNullOrWhiteSpace(gtin) &&
|
||||||
string.IsNullOrWhiteSpace(batch) &&
|
string.IsNullOrWhiteSpace(batch) &&
|
||||||
!expiration.HasValue &&
|
!expiration.HasValue &&
|
||||||
@ -128,7 +128,6 @@ namespace Models.Repositories.Stock
|
|||||||
.Where(p => p.ExternalCode == g || p.FactoryCode == g || p.RegulatoryCode == g)
|
.Where(p => p.ExternalCode == g || p.FactoryCode == g || p.RegulatoryCode == g)
|
||||||
.Select(p => p.Id).ToListAsync();
|
.Select(p => p.Id).ToListAsync();
|
||||||
|
|
||||||
// Si se pidió GTIN y no matchea ningún producto, devolvé vacío
|
|
||||||
if (productIds.Count == 0)
|
if (productIds.Count == 0)
|
||||||
{
|
{
|
||||||
return new PagedResult<StockItemScanResultDto>
|
return new PagedResult<StockItemScanResultDto>
|
||||||
@ -151,29 +150,145 @@ namespace Models.Repositories.Stock
|
|||||||
if (locationId.HasValue)
|
if (locationId.HasValue)
|
||||||
baseQuery = baseQuery.Where(x => x.si.LocationId == locationId.Value);
|
baseQuery = baseQuery.Where(x => x.si.LocationId == locationId.Value);
|
||||||
|
|
||||||
// 3) Reglas por tipo de trazabilidad (sin fuzzy)
|
// 3) Reglas por tipo de trazabilidad — PRIORIDAD: tipo REAL del producto si hay productIds
|
||||||
|
if (productIds.Count > 0)
|
||||||
|
{
|
||||||
|
var traces = await _context.PhLsmProducts.AsNoTracking()
|
||||||
|
.Where(p => productIds.Contains(p.Id))
|
||||||
|
.Select(p => p.TraceabilityType)
|
||||||
|
.Distinct()
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// Nota: normalmente habrá un solo tipo; si hubiera mezcla, estas ramas las contemplan.
|
||||||
|
|
||||||
|
if (traces.Contains(4) || traces.Contains(5))
|
||||||
|
{
|
||||||
|
// T4/T5: requieren serial. T5 además requiere expiration exacta.
|
||||||
|
if (string.IsNullOrWhiteSpace(serial))
|
||||||
|
return new PagedResult<StockItemScanResultDto>
|
||||||
|
{ Items = [], TotalItems = 0, Page = page <= 0 ? 1 : page, PageSize = take <= 0 ? 20 : take };
|
||||||
|
|
||||||
|
var s = serial.Trim();
|
||||||
|
|
||||||
|
if (traces.Contains(5) && expiration.HasValue)
|
||||||
|
{
|
||||||
|
var e = expiration.Value;
|
||||||
baseQuery = baseQuery.Where(x =>
|
baseQuery = baseQuery.Where(x =>
|
||||||
// None: solo producto + ubicación
|
(x.p.TraceabilityType == 5 &&
|
||||||
(x.p.TraceabilityType == 1)
|
x.si.Serial != null && x.si.Serial == s &&
|
||||||
// BatchOnly: requiere batch exacto
|
x.si.Expiration.HasValue && x.si.Expiration.Value == e)
|
||||||
|| (x.p.TraceabilityType == 2
|
||
|
||||||
&& !string.IsNullOrWhiteSpace(batch)
|
// si el conjunto tuviera también productos T4, permitimos T4 por serial
|
||||||
&& x.si.Batch == batch!.Trim())
|
(x.p.TraceabilityType == 4 &&
|
||||||
// Batch+Exp: requiere batch + expiration exactos
|
x.si.Serial != null && x.si.Serial == s)
|
||||||
|| (x.p.TraceabilityType == 3
|
|
||||||
&& !string.IsNullOrWhiteSpace(batch) && expiration.HasValue
|
|
||||||
&& x.si.Batch == batch!.Trim()
|
|
||||||
&& x.si.Expiration.HasValue && x.si.Expiration.Value == expiration.Value)
|
|
||||||
// SerialUnit: requiere serial exacto (ignora expiration)
|
|
||||||
|| (x.p.TraceabilityType == 4
|
|
||||||
&& !string.IsNullOrWhiteSpace(serial)
|
|
||||||
&& x.si.Serial != null && x.si.Serial == serial!.Trim())
|
|
||||||
// Serial+Exp: requiere serial + expiration exactos
|
|
||||||
|| (x.p.TraceabilityType == 5
|
|
||||||
&& !string.IsNullOrWhiteSpace(serial) && expiration.HasValue
|
|
||||||
&& x.si.Serial != null && x.si.Serial == serial!.Trim()
|
|
||||||
&& x.si.Expiration.HasValue && x.si.Expiration.Value == expiration.Value)
|
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
baseQuery = baseQuery.Where(x =>
|
||||||
|
x.p.TraceabilityType == 4 &&
|
||||||
|
x.si.Serial != null && x.si.Serial == s
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (traces.Contains(3))
|
||||||
|
{
|
||||||
|
// T3: exige batch + expiration exactos
|
||||||
|
if (string.IsNullOrWhiteSpace(batch) || !expiration.HasValue)
|
||||||
|
return new PagedResult<StockItemScanResultDto>
|
||||||
|
{ Items = [], TotalItems = 0, Page = page <= 0 ? 1 : page, PageSize = take <= 0 ? 20 : take };
|
||||||
|
|
||||||
|
var b = batch.Trim();
|
||||||
|
var e = expiration.Value;
|
||||||
|
|
||||||
|
baseQuery = baseQuery.Where(x =>
|
||||||
|
x.p.TraceabilityType == 3 &&
|
||||||
|
x.si.Batch == b &&
|
||||||
|
x.si.Expiration.HasValue && x.si.Expiration.Value == e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (traces.Contains(2))
|
||||||
|
{
|
||||||
|
// T2: exige batch exacto (ignorar serial/expiration si vinieran)
|
||||||
|
if (string.IsNullOrWhiteSpace(batch))
|
||||||
|
return new PagedResult<StockItemScanResultDto>
|
||||||
|
{ Items = [], TotalItems = 0, Page = page <= 0 ? 1 : page, PageSize = take <= 0 ? 20 : take };
|
||||||
|
|
||||||
|
var b = batch.Trim();
|
||||||
|
|
||||||
|
baseQuery = baseQuery.Where(x =>
|
||||||
|
x.p.TraceabilityType == 2 &&
|
||||||
|
x.si.Batch == b
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (traces.Contains(1))
|
||||||
|
{
|
||||||
|
// T1: sin traza (solo producto + ubicación)
|
||||||
|
baseQuery = baseQuery.Where(x => x.p.TraceabilityType == 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new PagedResult<StockItemScanResultDto>
|
||||||
|
{ Items = [], TotalItems = 0, Page = page <= 0 ? 1 : page, PageSize = take <= 0 ? 20 : take };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Fallback: sin productIds -> decidir por presencia de datos (tu heurística original)
|
||||||
|
if (!string.IsNullOrWhiteSpace(serial))
|
||||||
|
{
|
||||||
|
var s = serial.Trim();
|
||||||
|
|
||||||
|
if (expiration.HasValue)
|
||||||
|
{
|
||||||
|
var e = expiration.Value;
|
||||||
|
baseQuery = baseQuery.Where(x =>
|
||||||
|
(x.p.TraceabilityType == 5 &&
|
||||||
|
x.si.Serial != null && x.si.Serial == s &&
|
||||||
|
x.si.Expiration.HasValue && x.si.Expiration.Value == e)
|
||||||
|
||
|
||||||
|
(x.p.TraceabilityType == 4 &&
|
||||||
|
x.si.Serial != null && x.si.Serial == s)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
baseQuery = baseQuery.Where(x =>
|
||||||
|
x.p.TraceabilityType == 4 &&
|
||||||
|
x.si.Serial != null && x.si.Serial == s
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrWhiteSpace(batch))
|
||||||
|
{
|
||||||
|
var b = batch.Trim();
|
||||||
|
|
||||||
|
if (expiration.HasValue)
|
||||||
|
{
|
||||||
|
var e = expiration.Value;
|
||||||
|
baseQuery = baseQuery.Where(x =>
|
||||||
|
(x.p.TraceabilityType == 3 &&
|
||||||
|
x.si.Batch == b &&
|
||||||
|
x.si.Expiration.HasValue && x.si.Expiration.Value == e)
|
||||||
|
||
|
||||||
|
(x.p.TraceabilityType == 2 &&
|
||||||
|
x.si.Batch == b)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
baseQuery = baseQuery.Where(x =>
|
||||||
|
x.p.TraceabilityType == 2 &&
|
||||||
|
x.si.Batch == b
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Solo aceptar T1 cuando no hay otra evidencia
|
||||||
|
baseQuery = baseQuery.Where(x => x.p.TraceabilityType == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 4) Orden y proyección
|
// 4) Orden y proyección
|
||||||
baseQuery = baseQuery.OrderBy(x => x.si.Expiration).ThenBy(x => x.p.Name);
|
baseQuery = baseQuery.OrderBy(x => x.si.Expiration).ThenBy(x => x.p.Name);
|
||||||
@ -189,8 +304,8 @@ namespace Models.Repositories.Stock
|
|||||||
LocationId = x.si.LocationId,
|
LocationId = x.si.LocationId,
|
||||||
LocationName = x.loc != null ? x.loc.Descripcion : null,
|
LocationName = x.loc != null ? x.loc.Descripcion : null,
|
||||||
Batch = x.si.Batch,
|
Batch = x.si.Batch,
|
||||||
Expiration = x.si.Expiration, // DateOnly?
|
Expiration = x.si.Expiration,
|
||||||
Serial = x.si.Serial, // si aplica
|
Serial = x.si.Serial,
|
||||||
TraceabilityType = x.p.TraceabilityType,
|
TraceabilityType = x.p.TraceabilityType,
|
||||||
AvailableQty = x.si.Quantity,
|
AvailableQty = x.si.Quantity,
|
||||||
PlusProcess = x.p.PlusProcess
|
PlusProcess = x.p.PlusProcess
|
||||||
|
|||||||
@ -49,6 +49,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>Producto</th>
|
<th>Producto</th>
|
||||||
<th>Lote</th>
|
<th>Lote</th>
|
||||||
|
<th>Serial</th>
|
||||||
<th>Vencimiento</th>
|
<th>Vencimiento</th>
|
||||||
<th>Disponible</th>
|
<th>Disponible</th>
|
||||||
<th>Cantidad a usar</th>
|
<th>Cantidad a usar</th>
|
||||||
@ -60,6 +61,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>@item.ProductName</td>
|
<td>@item.ProductName</td>
|
||||||
<td>@item.Batch</td>
|
<td>@item.Batch</td>
|
||||||
|
<td>@item.Serial</td>
|
||||||
<td>@item.Expiration?.ToShortDateString()</td>
|
<td>@item.Expiration?.ToShortDateString()</td>
|
||||||
<td>@item.Available</td>
|
<td>@item.Available</td>
|
||||||
<td>
|
<td>
|
||||||
@ -145,6 +147,7 @@
|
|||||||
ProductId = matchedItem.ProductId,
|
ProductId = matchedItem.ProductId,
|
||||||
ProductName = matchedItem.ProductName,
|
ProductName = matchedItem.ProductName,
|
||||||
Batch = matchedItem.Batch,
|
Batch = matchedItem.Batch,
|
||||||
|
Serial = matchedItem.Serial,
|
||||||
Expiration = matchedItem.Expiration,
|
Expiration = matchedItem.Expiration,
|
||||||
Available = matchedItem.Quantity,
|
Available = matchedItem.Quantity,
|
||||||
Selected = 1,
|
Selected = 1,
|
||||||
@ -181,6 +184,7 @@
|
|||||||
ProductId = x.ProductId,
|
ProductId = x.ProductId,
|
||||||
ProductName = x.ProductName,
|
ProductName = x.ProductName,
|
||||||
Batch = x.Batch,
|
Batch = x.Batch,
|
||||||
|
Serial= x.Serial,
|
||||||
Expiration = x.Expiration,
|
Expiration = x.Expiration,
|
||||||
Quantity = x.Selected,
|
Quantity = x.Selected,
|
||||||
LocationId = x.LocationId
|
LocationId = x.LocationId
|
||||||
@ -213,6 +217,7 @@
|
|||||||
public int ProductId { get; set; }
|
public int ProductId { get; set; }
|
||||||
public string ProductName { get; set; } = string.Empty;
|
public string ProductName { get; set; } = string.Empty;
|
||||||
public string Batch { get; set; } = string.Empty;
|
public string Batch { get; set; } = string.Empty;
|
||||||
|
public string Serial { get; set; } = string.Empty;
|
||||||
public DateTime? Expiration { get; set; }
|
public DateTime? Expiration { get; set; }
|
||||||
public decimal Available { get; set; }
|
public decimal Available { get; set; }
|
||||||
public decimal Selected { get; set; }
|
public decimal Selected { get; set; }
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user