| | | 1 | | using MechanicsSoftware.Application.Abstractions; |
| | | 2 | | using MechanicsSoftware.Application.Exceptions; |
| | | 3 | | using MechanicsSoftware.Application.UseCases.ServiceOrders.Commands; |
| | | 4 | | using MechanicsSoftware.Domain.Entities; |
| | | 5 | | using MechanicsSoftware.Domain.Enums; |
| | | 6 | | |
| | | 7 | | namespace MechanicsSoftware.Application.UseCases.ServiceOrders.Handlers; |
| | | 8 | | |
| | 8 | 9 | | public sealed class AddPartItemHandler(IAppDbContext db) |
| | | 10 | | { |
| | | 11 | | public async Task<AddPartItemResponse> ExecuteAsync( |
| | | 12 | | Guid serviceOrderId, AddPartItemCommand command, CancellationToken cancellationToken = default) |
| | 8 | 13 | | { |
| | 8 | 14 | | var order = await db.ServiceOrders.FindFullAsync(serviceOrderId, cancellationToken); |
| | | 15 | | |
| | 6 | 16 | | var part = await db.Parts.FindAsync([command.PartId], cancellationToken) |
| | 6 | 17 | | ?? throw new NotFoundException(nameof(Part), command.PartId); |
| | | 18 | | |
| | | 19 | | PartAvailability availability; |
| | 4 | 20 | | string? warning = null; |
| | | 21 | | |
| | 4 | 22 | | if (part.AvailableQuantity >= command.Quantity) |
| | 2 | 23 | | { |
| | 2 | 24 | | part.Reserve(command.Quantity, serviceOrderId); |
| | 2 | 25 | | availability = PartAvailability.Available; |
| | 2 | 26 | | } |
| | | 27 | | else |
| | 2 | 28 | | { |
| | 2 | 29 | | availability = PartAvailability.Unavailable; |
| | 2 | 30 | | warning = $"Insufficient stock for part '{part.Name}'. " + |
| | 2 | 31 | | $"Available: {part.AvailableQuantity}, requested: {command.Quantity}. " + |
| | 2 | 32 | | $"Part added as UNAVAILABLE and excluded from budget."; |
| | 2 | 33 | | } |
| | | 34 | | |
| | 4 | 35 | | var item = order.AddPartItem( |
| | 4 | 36 | | part.Id, |
| | 4 | 37 | | part.Name, |
| | 4 | 38 | | part.UnitPrice, |
| | 4 | 39 | | command.Quantity, |
| | 4 | 40 | | availability); |
| | | 41 | | |
| | 4 | 42 | | await db.SaveChangesAsync(cancellationToken); |
| | | 43 | | |
| | 4 | 44 | | return new AddPartItemResponse( |
| | 4 | 45 | | item.Id, |
| | 4 | 46 | | item.PartId, |
| | 4 | 47 | | item.PartName, |
| | 4 | 48 | | item.UnitPrice.Cents, |
| | 4 | 49 | | item.Quantity, |
| | 4 | 50 | | availability == PartAvailability.Available ? "AVAILABLE" : "UNAVAILABLE", |
| | 4 | 51 | | item.Total.Cents, |
| | 4 | 52 | | warning); |
| | 4 | 53 | | } |
| | | 54 | | } |