Files

102 lines
3.6 KiB
C#

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
public class MedicationService : IMedicationService
{
private readonly AppDbContext _db;
private readonly MedicationCorrelationOptions _correlationOptions;
public MedicationService(
AppDbContext db,
IOptions<MedicationCorrelationOptions> correlationOptions)
{
_db = db;
_correlationOptions = correlationOptions.Value;
}
public async Task<MedicationAdministration> CreateAsync(
Guid encounterId, CreateMedicationAdministrationRequest 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 record medications for a non-active encounter.",
"ENCOUNTER_NOT_ACTIVE");
var med = new MedicationAdministration
{
Id = Guid.NewGuid(),
EncounterId = encounterId,
DrugName = req.DrugName.Trim(),
Dose = req.Dose,
DoseUnit = req.DoseUnit.Trim(),
Route = req.Route.Trim(),
AdministeredAt = req.AdministeredAt ?? DateTimeOffset.UtcNow,
AdministeredBy = req.AdministeredBy.Trim()
};
_db.MedicationAdministrations.Add(med);
await _db.SaveChangesAsync();
return med;
}
public async Task<MedicationAdministration> GetByIdAsync(Guid id)
{
var med = await _db.MedicationAdministrations
.AsNoTracking()
.Include(m => m.Encounter)
.FirstOrDefaultAsync(m => m.Id == id);
if (med is null)
throw new NotFoundException("Medication administration not found.", "MEDICATION_NOT_FOUND");
return med;
}
public async Task<IReadOnlyList<MedicationAdministration>> GetRecentForEncounterAsync(
Guid encounterId, string observationCode, int windowMinutes)
{
var cutoff = DateTimeOffset.UtcNow.AddMinutes(-windowMinutes);
var mappings = _correlationOptions.DrugVitalMappings;
// Find drugs that affect this observation code
var relevantDrugs = mappings
.Where(kv => kv.Value.Contains(observationCode, StringComparer.OrdinalIgnoreCase))
.Select(kv => kv.Key)
.ToHashSet(StringComparer.OrdinalIgnoreCase);
if (relevantDrugs.Count == 0)
return Array.Empty<MedicationAdministration>();
return await _db.MedicationAdministrations
.AsNoTracking()
.Where(m => m.EncounterId == encounterId
&& m.AdministeredAt >= cutoff
&& relevantDrugs.Contains(m.DrugName.ToLower()))
.OrderByDescending(m => m.AdministeredAt)
.ToListAsync();
}
public async Task<PagedResult<MedicationAdministration>> ListByEncounterAsync(
Guid encounterId, DateTimeOffset? since, int page, int pageSize)
{
var query = _db.MedicationAdministrations
.AsNoTracking()
.Where(m => m.EncounterId == encounterId);
if (since.HasValue)
query = query.Where(m => m.AdministeredAt >= since.Value);
var total = await query.CountAsync();
var items = await query
.OrderByDescending(m => m.AdministeredAt)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
return new PagedResult<MedicationAdministration>(items, page, pageSize, total);
}
}