Files
vigilcare-clinical/VigilCareClinicalAPI/Services/OrderService.cs
T

121 lines
4.2 KiB
C#

using Microsoft.EntityFrameworkCore;
public class OrderService : IOrderService
{
private static readonly Dictionary<OrderStatus, HashSet<OrderStatus>> _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;
private readonly IServiceProvider _serviceProvider;
public OrderService(AppDbContext db, IServiceProvider serviceProvider)
{
_db = db;
_serviceProvider = serviceProvider;
}
public async Task<Order> 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<PagedResult<Order>> 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<Order>(orders, page, pageSize, total);
}
public async Task<Order> 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<Order> 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<Order> 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();
var bundleService = _serviceProvider.GetRequiredService<ISepsisBundleService>();
await bundleService.OnOrderResultedAsync(order.Id);
return order;
}
}