using Microsoft.EntityFrameworkCore; public class OrderService : IOrderService { private static readonly Dictionary> _allowedTransitions = new() { [OrderStatus.Pending] = new() { OrderStatus.InProgress, OrderStatus.Cancelled }, [OrderStatus.InProgress] = new() { OrderStatus.Resulted, OrderStatus.Cancelled }, [OrderStatus.Resulted] = new(), [OrderStatus.Cancelled] = new(), }; private readonly AppDbContext _db; public OrderService(AppDbContext db) => _db = db; public async Task CreateAsync(Guid encounterId, CreateOrderRequest req) { var encounter = await _db.Encounters.FindAsync(encounterId); if (encounter is null) throw new NotFoundException("Encounter not found.", "ENCOUNTER_NOT_FOUND"); if (encounter.Status != EncounterStatus.Active) throw new ConflictException( "Cannot create orders for a non-active encounter.", "ENCOUNTER_NOT_ACTIVE"); var order = new Order { Id = Guid.NewGuid(), EncounterId = encounterId, OrderType = req.OrderType, Description = req.Description, OrderedBy = req.OrderedBy, Status = OrderStatus.Pending, OrderedAt = DateTimeOffset.UtcNow }; _db.Orders.Add(order); await _db.SaveChangesAsync(); return order; } public async Task> ListByEncounterAsync( Guid encounterId, OrderStatus? status, int page, int pageSize) { var query = _db.Orders .AsNoTracking() .Where(o => o.EncounterId == encounterId); if (status.HasValue) query = query.Where(o => o.Status == status.Value); var total = await query.CountAsync(); var orders = await query .OrderByDescending(o => o.OrderedAt) .Skip((page - 1) * pageSize) .Take(pageSize) .ToListAsync(); return new PagedResult(orders, page, pageSize, total); } public async Task GetByIdAsync(Guid id) { var order = await _db.Orders .AsNoTracking() .Include(o => o.Encounter) .FirstOrDefaultAsync(o => o.Id == id); if (order is null) throw new NotFoundException("Order not found.", "ORDER_NOT_FOUND"); return order; } public async Task TransitionStatusAsync(Guid id, OrderStatus targetStatus) { var order = await _db.Orders.FindAsync(id); if (order is null) throw new NotFoundException("Order not found.", "ORDER_NOT_FOUND"); if (!_allowedTransitions[order.Status].Contains(targetStatus)) throw new ConflictException( $"Transition to '{targetStatus}' is not permitted from status '{order.Status}'.", "ILLEGAL_ORDER_STATUS_TRANSITION"); order.Status = targetStatus; if (targetStatus == OrderStatus.Resulted) order.ResultedAt = DateTimeOffset.UtcNow; await _db.SaveChangesAsync(); return order; } public async Task RecordResultAsync(Guid id, RecordOrderResultRequest req) { var order = await _db.Orders.FindAsync(id); if (order is null) throw new NotFoundException("Order not found.", "ORDER_NOT_FOUND"); if (order.Status == OrderStatus.Resulted) throw new ConflictException("Order already resulted.", "ORDER_ALREADY_RESULTED"); if (order.Status == OrderStatus.Cancelled) throw new ConflictException("Cannot result a cancelled order.", "ORDER_CANCELLED"); order.Status = OrderStatus.Resulted; order.ResultedAt = DateTimeOffset.UtcNow; order.ResultSummary = req.ResultSummary; await _db.SaveChangesAsync(); return order; } }