This commit is contained in:
2025-11-29 16:06:13 +01:00
parent c7dbcde5dd
commit cedcc503fa
34 changed files with 9097 additions and 191 deletions

View File

@@ -239,6 +239,7 @@ public class WarehouseArticlesController : ControllerBase
public record ArticleDto(
int Id,
string Code,
string? AlternativeCode,
string Description,
string? ShortDescription,
string? Barcode,
@@ -273,36 +274,36 @@ public class WarehouseArticlesController : ControllerBase
);
public record CreateArticleDto(
string Code,
string Description,
string? ShortDescription,
string? Barcode,
string? ManufacturerCode,
int? CategoryId,
string UnitOfMeasure,
string? SecondaryUnitOfMeasure,
decimal? UnitConversionFactor,
StockManagementType StockManagement,
bool IsBatchManaged,
bool IsSerialManaged,
bool HasExpiry,
int? ExpiryWarningDays,
decimal? MinimumStock,
decimal? MaximumStock,
decimal? ReorderPoint,
decimal? ReorderQuantity,
int? LeadTimeDays,
ValuationMethod? ValuationMethod,
decimal? StandardCost,
decimal? BaseSellingPrice,
decimal? Weight,
decimal? Volume,
string? Notes
string? AlternativeCode = null,
string? ShortDescription = null,
string? Barcode = null,
string? ManufacturerCode = null,
int? CategoryId = null,
string? SecondaryUnitOfMeasure = null,
decimal? UnitConversionFactor = null,
StockManagementType StockManagement = StockManagementType.Standard,
bool IsBatchManaged = false,
bool IsSerialManaged = false,
bool HasExpiry = false,
int? ExpiryWarningDays = null,
decimal? MinimumStock = null,
decimal? MaximumStock = null,
decimal? ReorderPoint = null,
decimal? ReorderQuantity = null,
int? LeadTimeDays = null,
ValuationMethod? ValuationMethod = null,
decimal? StandardCost = null,
decimal? BaseSellingPrice = null,
decimal? Weight = null,
decimal? Volume = null,
string? Notes = null
);
public record UpdateArticleDto(
string Code,
string Description,
string? AlternativeCode,
string? ShortDescription,
string? Barcode,
string? ManufacturerCode,
@@ -363,6 +364,7 @@ public class WarehouseArticlesController : ControllerBase
private static ArticleDto MapToDto(WarehouseArticle article) => new(
article.Id,
article.Code,
article.AlternativeCode,
article.Description,
article.ShortDescription,
article.Barcode,
@@ -398,7 +400,8 @@ public class WarehouseArticlesController : ControllerBase
private static WarehouseArticle MapFromDto(CreateArticleDto dto) => new()
{
Code = dto.Code,
// Code viene generato automaticamente da WarehouseService.CreateArticleAsync
AlternativeCode = dto.AlternativeCode,
Description = dto.Description,
ShortDescription = dto.ShortDescription,
Barcode = dto.Barcode,
@@ -428,7 +431,8 @@ public class WarehouseArticlesController : ControllerBase
private static void UpdateFromDto(WarehouseArticle article, UpdateArticleDto dto)
{
article.Code = dto.Code;
// Code non viene aggiornato - è generato automaticamente e immutabile
article.AlternativeCode = dto.AlternativeCode;
article.Description = dto.Description;
article.ShortDescription = dto.ShortDescription;
article.Barcode = dto.Barcode;

View File

@@ -1,3 +1,4 @@
using Apollinare.API.Services;
using Apollinare.Domain.Entities.Warehouse;
using Apollinare.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
@@ -13,6 +14,7 @@ public class WarehouseService : IWarehouseService
private readonly AppollinareDbContext _context;
private readonly IMemoryCache _cache;
private readonly ILogger<WarehouseService> _logger;
private readonly AutoCodeService _autoCodeService;
private const string WAREHOUSES_CACHE_KEY = "warehouse_locations";
private const string CATEGORIES_CACHE_KEY = "warehouse_categories";
@@ -22,11 +24,13 @@ public class WarehouseService : IWarehouseService
public WarehouseService(
AppollinareDbContext context,
IMemoryCache cache,
ILogger<WarehouseService> logger)
ILogger<WarehouseService> logger,
AutoCodeService autoCodeService)
{
_context = context;
_cache = cache;
_logger = logger;
_autoCodeService = autoCodeService;
}
#region Articoli
@@ -118,6 +122,16 @@ public class WarehouseService : IWarehouseService
public async Task<WarehouseArticle> CreateArticleAsync(WarehouseArticle article)
{
// Genera codice automaticamente se non specificato
if (string.IsNullOrWhiteSpace(article.Code))
{
var generatedCode = await _autoCodeService.GenerateNextCodeAsync("warehouse_article");
if (generatedCode != null)
article.Code = generatedCode;
else
throw new InvalidOperationException("Impossibile generare codice automatico per l'articolo");
}
// Verifica unicità codice
if (await _context.WarehouseArticles.AnyAsync(a => a.Code == article.Code))
throw new InvalidOperationException($"Esiste già un articolo con codice '{article.Code}'");
@@ -230,6 +244,16 @@ public class WarehouseService : IWarehouseService
public async Task<WarehouseArticleCategory> CreateCategoryAsync(WarehouseArticleCategory category)
{
// Genera codice automaticamente se non specificato
if (string.IsNullOrWhiteSpace(category.Code))
{
var generatedCode = await _autoCodeService.GenerateNextCodeAsync("warehouse_category");
if (generatedCode != null)
category.Code = generatedCode;
else
throw new InvalidOperationException("Impossibile generare codice automatico per la categoria");
}
if (await _context.WarehouseArticleCategories.AnyAsync(c => c.Code == category.Code))
throw new InvalidOperationException($"Esiste già una categoria con codice '{category.Code}'");
@@ -336,6 +360,16 @@ public class WarehouseService : IWarehouseService
public async Task<WarehouseLocation> CreateWarehouseAsync(WarehouseLocation warehouse)
{
// Genera codice automaticamente se non specificato
if (string.IsNullOrWhiteSpace(warehouse.Code))
{
var generatedCode = await _autoCodeService.GenerateNextCodeAsync("warehouse_location");
if (generatedCode != null)
warehouse.Code = generatedCode;
else
throw new InvalidOperationException("Impossibile generare codice automatico per il magazzino");
}
if (await _context.WarehouseLocations.AnyAsync(w => w.Code == warehouse.Code))
throw new InvalidOperationException($"Esiste già un magazzino con codice '{warehouse.Code}'");
@@ -464,6 +498,16 @@ public class WarehouseService : IWarehouseService
if (!article.IsBatchManaged)
throw new InvalidOperationException("L'articolo non è gestito a lotti");
// Genera numero lotto automaticamente se non specificato
if (string.IsNullOrWhiteSpace(batch.BatchNumber))
{
var generatedCode = await _autoCodeService.GenerateNextCodeAsync("article_batch");
if (generatedCode != null)
batch.BatchNumber = generatedCode;
else
throw new InvalidOperationException("Impossibile generare numero lotto automatico");
}
// Verifica unicità batch number per articolo
if (await _context.ArticleBatches.AnyAsync(b => b.ArticleId == batch.ArticleId && b.BatchNumber == batch.BatchNumber))
throw new InvalidOperationException($"Esiste già un lotto '{batch.BatchNumber}' per questo articolo");
@@ -809,9 +853,15 @@ public class WarehouseService : IWarehouseService
public async Task<StockMovement> CreateMovementAsync(StockMovement movement)
{
// Genera numero documento se non specificato
// Genera numero documento automaticamente se non specificato
if (string.IsNullOrEmpty(movement.DocumentNumber))
movement.DocumentNumber = await GenerateDocumentNumberAsync(movement.Type);
{
var generatedCode = await _autoCodeService.GenerateNextCodeAsync("stock_movement");
if (generatedCode != null)
movement.DocumentNumber = generatedCode;
else
movement.DocumentNumber = await GenerateDocumentNumberAsync(movement.Type); // Fallback
}
// Verifica unicità documento
if (await _context.StockMovements.AnyAsync(m => m.DocumentNumber == movement.DocumentNumber))
@@ -1428,8 +1478,15 @@ public class WarehouseService : IWarehouseService
public async Task<InventoryCount> CreateInventoryCountAsync(InventoryCount inventory)
{
// Genera codice automaticamente se non specificato
if (string.IsNullOrEmpty(inventory.Code))
inventory.Code = $"INV/{DateTime.UtcNow:yyyyMMdd}/{await GenerateInventorySequenceAsync()}";
{
var generatedCode = await _autoCodeService.GenerateNextCodeAsync("inventory_count");
if (generatedCode != null)
inventory.Code = generatedCode;
else
inventory.Code = $"INV/{DateTime.UtcNow:yyyyMMdd}/{await GenerateInventorySequenceAsync()}"; // Fallback
}
inventory.CreatedAt = DateTime.UtcNow;
_context.InventoryCounts.Add(inventory);