changed name from Apollinare to Zentral
This commit is contained in:
@@ -0,0 +1,288 @@
|
||||
using Zentral.API.Modules.Warehouse.Services;
|
||||
using Zentral.Domain.Entities.Warehouse;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Zentral.API.Modules.Warehouse.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Controller per la gestione delle partite/lotti
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("api/warehouse/batches")]
|
||||
public class BatchesController : ControllerBase
|
||||
{
|
||||
private readonly IWarehouseService _warehouseService;
|
||||
private readonly ILogger<BatchesController> _logger;
|
||||
|
||||
public BatchesController(
|
||||
IWarehouseService warehouseService,
|
||||
ILogger<BatchesController> logger)
|
||||
{
|
||||
_warehouseService = warehouseService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene la lista delle partite con filtri opzionali
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<List<BatchDto>>> GetBatches(
|
||||
[FromQuery] int? articleId = null,
|
||||
[FromQuery] BatchStatus? status = null)
|
||||
{
|
||||
var batches = await _warehouseService.GetBatchesAsync(articleId, status);
|
||||
return Ok(batches.Select(MapToDto));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene una partita per ID
|
||||
/// </summary>
|
||||
[HttpGet("{id}")]
|
||||
public async Task<ActionResult<BatchDto>> GetBatch(int id)
|
||||
{
|
||||
var batch = await _warehouseService.GetBatchByIdAsync(id);
|
||||
if (batch == null)
|
||||
return NotFound();
|
||||
|
||||
return Ok(MapToDto(batch));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene una partita per articolo e numero lotto
|
||||
/// </summary>
|
||||
[HttpGet("by-number/{articleId}/{batchNumber}")]
|
||||
public async Task<ActionResult<BatchDto>> GetBatchByNumber(int articleId, string batchNumber)
|
||||
{
|
||||
var batch = await _warehouseService.GetBatchByNumberAsync(articleId, batchNumber);
|
||||
if (batch == null)
|
||||
return NotFound();
|
||||
|
||||
return Ok(MapToDto(batch));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Crea una nuova partita
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<BatchDto>> CreateBatch([FromBody] CreateBatchDto dto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var batch = new ArticleBatch
|
||||
{
|
||||
ArticleId = dto.ArticleId,
|
||||
BatchNumber = dto.BatchNumber,
|
||||
ProductionDate = dto.ProductionDate,
|
||||
ExpiryDate = dto.ExpiryDate,
|
||||
SupplierBatch = dto.SupplierBatch,
|
||||
SupplierId = dto.SupplierId,
|
||||
UnitCost = dto.UnitCost,
|
||||
InitialQuantity = dto.InitialQuantity,
|
||||
CurrentQuantity = dto.InitialQuantity,
|
||||
Status = BatchStatus.Available,
|
||||
Certifications = dto.Certifications,
|
||||
Notes = dto.Notes
|
||||
};
|
||||
|
||||
var created = await _warehouseService.CreateBatchAsync(batch);
|
||||
return CreatedAtAction(nameof(GetBatch), new { id = created.Id }, MapToDto(created));
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return NotFound(new { error = ex.Message });
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return BadRequest(new { error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggiorna una partita esistente
|
||||
/// </summary>
|
||||
[HttpPut("{id}")]
|
||||
public async Task<ActionResult<BatchDto>> UpdateBatch(int id, [FromBody] UpdateBatchDto dto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existing = await _warehouseService.GetBatchByIdAsync(id);
|
||||
if (existing == null)
|
||||
return NotFound();
|
||||
|
||||
if (dto.ProductionDate.HasValue)
|
||||
existing.ProductionDate = dto.ProductionDate;
|
||||
if (dto.ExpiryDate.HasValue)
|
||||
existing.ExpiryDate = dto.ExpiryDate;
|
||||
if (dto.SupplierBatch != null)
|
||||
existing.SupplierBatch = dto.SupplierBatch;
|
||||
if (dto.UnitCost.HasValue)
|
||||
existing.UnitCost = dto.UnitCost;
|
||||
if (dto.Certifications != null)
|
||||
existing.Certifications = dto.Certifications;
|
||||
if (dto.Notes != null)
|
||||
existing.Notes = dto.Notes;
|
||||
|
||||
var updated = await _warehouseService.UpdateBatchAsync(existing);
|
||||
return Ok(MapToDto(updated));
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return BadRequest(new { error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggiorna lo stato di una partita
|
||||
/// </summary>
|
||||
[HttpPut("{id}/status")]
|
||||
public async Task<ActionResult> UpdateBatchStatus(int id, [FromBody] UpdateBatchStatusDto dto)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _warehouseService.UpdateBatchStatusAsync(id, dto.Status);
|
||||
return Ok();
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return NotFound(new { error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene le partite in scadenza
|
||||
/// </summary>
|
||||
[HttpGet("expiring")]
|
||||
public async Task<ActionResult<List<BatchDto>>> GetExpiringBatches([FromQuery] int daysThreshold = 30)
|
||||
{
|
||||
var batches = await _warehouseService.GetExpiringBatchesAsync(daysThreshold);
|
||||
return Ok(batches.Select(MapToDto));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registra un controllo qualità sulla partita
|
||||
/// </summary>
|
||||
[HttpPost("{id}/quality-check")]
|
||||
public async Task<ActionResult<BatchDto>> RecordQualityCheck(int id, [FromBody] QualityCheckDto dto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var batch = await _warehouseService.GetBatchByIdAsync(id);
|
||||
if (batch == null)
|
||||
return NotFound();
|
||||
|
||||
batch.QualityStatus = dto.QualityStatus;
|
||||
batch.LastQualityCheckDate = DateTime.UtcNow;
|
||||
|
||||
// Aggiorna lo stato del lotto in base al risultato
|
||||
if (dto.QualityStatus == QualityStatus.Rejected)
|
||||
{
|
||||
batch.Status = BatchStatus.Blocked;
|
||||
}
|
||||
else if (dto.QualityStatus == QualityStatus.Approved && batch.Status == BatchStatus.Quarantine)
|
||||
{
|
||||
batch.Status = BatchStatus.Available;
|
||||
}
|
||||
|
||||
var updated = await _warehouseService.UpdateBatchAsync(batch);
|
||||
return Ok(MapToDto(updated));
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return NotFound(new { error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
#region DTOs
|
||||
|
||||
public record BatchDto(
|
||||
int Id,
|
||||
int ArticleId,
|
||||
string? ArticleCode,
|
||||
string? ArticleDescription,
|
||||
string BatchNumber,
|
||||
DateTime? ProductionDate,
|
||||
DateTime? ExpiryDate,
|
||||
string? SupplierBatch,
|
||||
int? SupplierId,
|
||||
decimal? UnitCost,
|
||||
decimal InitialQuantity,
|
||||
decimal CurrentQuantity,
|
||||
decimal ReservedQuantity,
|
||||
decimal AvailableQuantity,
|
||||
BatchStatus Status,
|
||||
QualityStatus? QualityStatus,
|
||||
DateTime? LastQualityCheckDate,
|
||||
string? Certifications,
|
||||
string? Notes,
|
||||
bool IsExpired,
|
||||
int? DaysToExpiry,
|
||||
DateTime? CreatedAt,
|
||||
DateTime? UpdatedAt
|
||||
);
|
||||
|
||||
public record CreateBatchDto(
|
||||
int ArticleId,
|
||||
string BatchNumber,
|
||||
DateTime? ProductionDate,
|
||||
DateTime? ExpiryDate,
|
||||
string? SupplierBatch,
|
||||
int? SupplierId,
|
||||
decimal? UnitCost,
|
||||
decimal InitialQuantity,
|
||||
string? Certifications,
|
||||
string? Notes
|
||||
);
|
||||
|
||||
public record UpdateBatchDto(
|
||||
DateTime? ProductionDate,
|
||||
DateTime? ExpiryDate,
|
||||
string? SupplierBatch,
|
||||
decimal? UnitCost,
|
||||
string? Certifications,
|
||||
string? Notes
|
||||
);
|
||||
|
||||
public record UpdateBatchStatusDto(BatchStatus Status);
|
||||
|
||||
public record QualityCheckDto(QualityStatus QualityStatus, string? Notes);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Mapping
|
||||
|
||||
private static BatchDto MapToDto(ArticleBatch batch)
|
||||
{
|
||||
var isExpired = batch.ExpiryDate.HasValue && batch.ExpiryDate.Value < DateTime.UtcNow;
|
||||
var daysToExpiry = batch.ExpiryDate.HasValue
|
||||
? (int?)Math.Max(0, (batch.ExpiryDate.Value - DateTime.UtcNow).Days)
|
||||
: null;
|
||||
|
||||
return new BatchDto(
|
||||
batch.Id,
|
||||
batch.ArticleId,
|
||||
batch.Article?.Code,
|
||||
batch.Article?.Description,
|
||||
batch.BatchNumber,
|
||||
batch.ProductionDate,
|
||||
batch.ExpiryDate,
|
||||
batch.SupplierBatch,
|
||||
batch.SupplierId,
|
||||
batch.UnitCost,
|
||||
batch.InitialQuantity,
|
||||
batch.CurrentQuantity,
|
||||
batch.ReservedQuantity,
|
||||
batch.CurrentQuantity - batch.ReservedQuantity,
|
||||
batch.Status,
|
||||
batch.QualityStatus,
|
||||
batch.LastQualityCheckDate,
|
||||
batch.Certifications,
|
||||
batch.Notes,
|
||||
isExpired,
|
||||
daysToExpiry,
|
||||
batch.CreatedAt,
|
||||
batch.UpdatedAt
|
||||
);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user