Some checks failed
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Failing after 3m17s
101 lines
3.8 KiB
C#
101 lines
3.8 KiB
C#
using System.Net.Http.Json;
|
|
using Domain.Dtos.Stock;
|
|
using Domain.Generics;
|
|
using Transversal.Services;
|
|
|
|
|
|
public class StockScanService : IStockScanService
|
|
{
|
|
private readonly HttpClient _http;
|
|
|
|
public StockScanService(HttpClient http)
|
|
{
|
|
_http = http;
|
|
}
|
|
|
|
public async Task<StockItemSelectionDto?> ParseAndMatchAsync(string rawInput, int locationId)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(rawInput))
|
|
return null;
|
|
|
|
try
|
|
{
|
|
var parsed = Gs1CodeParser.Parse(rawInput);
|
|
var raw = rawInput.Trim();
|
|
|
|
bool hasParsedAis = !string.IsNullOrWhiteSpace(parsed.Lot)
|
|
|| parsed.ExpirationDate.HasValue
|
|
|| !string.IsNullOrWhiteSpace(parsed.Serial)
|
|
|| !string.IsNullOrWhiteSpace(parsed.Variant); // incluir (22)
|
|
|
|
string? gtinToSend = parsed.Gtin ?? parsed.Variant; // (22) como fallback
|
|
if (gtinToSend is null && !hasParsedAis && IsPlainCode(raw))
|
|
gtinToSend = raw; // código plano tipeado (factory/regulatory)
|
|
|
|
|
|
// 3. Armar parámetros de búsqueda
|
|
var sp = new StockItemParsedSearchParams
|
|
{
|
|
Gtin = gtinToSend,
|
|
Batch = string.IsNullOrWhiteSpace(parsed.Lot) ? null : parsed.Lot,
|
|
Expiration = parsed.ExpirationDate.HasValue
|
|
? DateOnly.FromDateTime(parsed.ExpirationDate.Value)
|
|
: null,
|
|
Serial = string.IsNullOrWhiteSpace(parsed.Serial) ? null : parsed.Serial,
|
|
LocationId = locationId,
|
|
Page = 1,
|
|
PageSize = 10
|
|
};
|
|
|
|
// 4. Log para depuración (quitar en producción)
|
|
Console.WriteLine($"[ParseAndMatchAsync] Gtin={sp.Gtin}, Batch={sp.Batch}, Exp={sp.Expiration}, Serial={sp.Serial}, Loc={sp.LocationId}");
|
|
|
|
// 5. Llamar a la API
|
|
var resp = await _http.PostAsJsonAsync("/api/lsstockscan/search-parsed", sp);
|
|
if (!resp.IsSuccessStatusCode)
|
|
{
|
|
var err = await resp.Content.ReadAsStringAsync();
|
|
Console.WriteLine($"[ParseAndMatchAsync] API devolvió error {resp.StatusCode}: {err}");
|
|
return null;
|
|
}
|
|
|
|
// 6. Leer resultado
|
|
var pr = await resp.Content.ReadFromJsonAsync<PagedResult<StockItemScanResultDto>>();
|
|
var first = pr?.Items?.FirstOrDefault();
|
|
if (first == null)
|
|
{
|
|
Console.WriteLine("[ParseAndMatchAsync] No se encontró ningún ítem que coincida.");
|
|
return null;
|
|
}
|
|
|
|
// 7. Mapear a DTO de selección
|
|
return new StockItemSelectionDto
|
|
{
|
|
StockItemId = first.StockItemId,
|
|
ProductId = first.ProductId,
|
|
ProductName = first.ProductName,
|
|
Batch = first.Batch ?? string.Empty,
|
|
Expiration = first.Expiration?.ToDateTime(TimeOnly.MinValue),
|
|
Quantity = first.AvailableQty,
|
|
LocationId = first.LocationId ?? 0
|
|
};
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"[ParseAndMatchAsync] Error inesperado: {ex}");
|
|
throw;
|
|
}
|
|
|
|
}
|
|
private static bool IsPlainCode(string s)
|
|
{
|
|
// sin FNC1 ($), sin espacios y sin prefijos AI típicos
|
|
if (s.Contains('$') || s.Contains((char)29) || s.Contains(' ')) return false;
|
|
// evita raws que empiezan como AIs "01","10","17","21","22"
|
|
var prefix = s.Length >= 2 ? s[..2] : s;
|
|
if (prefix is "01" or "10" or "11" or "17" or "21" or "22") return false;
|
|
// permite letras/dígitos y algunos separadores comunes
|
|
return s.All(c => char.IsLetterOrDigit(c) || c is '-' or '/' or '_');
|
|
}
|
|
}
|