feature: FHIR R4 Inbound Facade
This commit is contained in:
@@ -15,11 +15,16 @@ public class EncounterService : IEncounterService
|
||||
|
||||
private readonly AppDbContext _db;
|
||||
private readonly IQsofaService _qsofa;
|
||||
private readonly IExternalIdentifierService _identifiers;
|
||||
|
||||
public EncounterService(AppDbContext db, IQsofaService qsofa)
|
||||
public EncounterService(
|
||||
AppDbContext db,
|
||||
IQsofaService qsofa,
|
||||
IExternalIdentifierService identifiers)
|
||||
{
|
||||
_db = db;
|
||||
_qsofa = qsofa;
|
||||
_identifiers = identifiers;
|
||||
}
|
||||
|
||||
public async Task<Encounter> GetByIdAsync(Guid id)
|
||||
@@ -194,4 +199,89 @@ public class EncounterService : IEncounterService
|
||||
|
||||
return new { encounterId, events = timeline };
|
||||
}
|
||||
|
||||
public async Task<Encounter> OpenOrUpdateByIdentifierAsync(FhirEncounterUpsertRequest req)
|
||||
{
|
||||
var existingId = await _identifiers.ResolveInternalIdAsync(
|
||||
ExternalResourceType.Encounter, req.IdentifierSystem, req.IdentifierValue);
|
||||
|
||||
if (existingId.HasValue)
|
||||
{
|
||||
var existingEncounter = await _db.Encounters
|
||||
.Include(e => e.Patient)
|
||||
.FirstOrDefaultAsync(e => e.Id == existingId.Value)
|
||||
?? throw new NotFoundException("Encounter not found.", "ENCOUNTER_NOT_FOUND");
|
||||
|
||||
existingEncounter.Department = req.Department;
|
||||
existingEncounter.AttendingPhysician = req.AttendingPhysician;
|
||||
existingEncounter.RoomBed = req.RoomBed;
|
||||
existingEncounter.AdmissionReason = req.AdmissionReason;
|
||||
|
||||
if (existingEncounter.Status != req.TargetStatus)
|
||||
{
|
||||
await TransitionStatusAsync(
|
||||
existingEncounter.Id, req.TargetStatus, req.DischargeDiagnosis);
|
||||
await _db.Entry(existingEncounter).ReloadAsync();
|
||||
}
|
||||
|
||||
return existingEncounter;
|
||||
}
|
||||
|
||||
// Create new encounter — mirrors PatientService.OpenEncounterAsync
|
||||
var patient = await _db.Patients.FindAsync(req.PatientId);
|
||||
if (patient is null)
|
||||
throw new NotFoundException("Patient not found.", "PATIENT_NOT_FOUND");
|
||||
|
||||
var encounter = new Encounter
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
PatientId = req.PatientId,
|
||||
EncounterType = req.EncounterType,
|
||||
Status = EncounterStatus.Active,
|
||||
Department = req.Department,
|
||||
AttendingPhysician = req.AttendingPhysician,
|
||||
RoomBed = req.RoomBed,
|
||||
AdmissionReason = req.AdmissionReason,
|
||||
AdmittedAt = req.AdmittedAt ?? DateTimeOffset.UtcNow,
|
||||
CreatedAt = DateTimeOffset.UtcNow
|
||||
};
|
||||
|
||||
_db.Encounters.Add(encounter);
|
||||
|
||||
_db.OutboxEvents.Add(new OutboxEvent
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Topic = "encounter.status.changed",
|
||||
Payload = JsonSerializer.Serialize(new
|
||||
{
|
||||
encounterId = encounter.Id,
|
||||
patientId = patient.Id,
|
||||
mrn = patient.Mrn,
|
||||
patientName = $"{patient.FirstName} {patient.LastName}",
|
||||
previousStatus = (string?)null,
|
||||
newStatus = encounter.Status.ToDbString(),
|
||||
department = encounter.Department.ToDbString(),
|
||||
attendingPhysician = encounter.AttendingPhysician,
|
||||
roomBed = encounter.RoomBed,
|
||||
admissionReason = encounter.AdmissionReason,
|
||||
admittedAt = encounter.AdmittedAt,
|
||||
changedAt = DateTimeOffset.UtcNow
|
||||
}),
|
||||
PartitionKey = encounter.Id.ToString(),
|
||||
CreatedAt = DateTimeOffset.UtcNow
|
||||
});
|
||||
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
await _identifiers.LinkAsync(
|
||||
ExternalResourceType.Encounter,
|
||||
encounter.Id,
|
||||
req.IdentifierSystem,
|
||||
req.IdentifierValue);
|
||||
|
||||
if (req.TargetStatus == EncounterStatus.Discharged)
|
||||
await TransitionStatusAsync(encounter.Id, EncounterStatus.Discharged, req.DischargeDiagnosis);
|
||||
|
||||
return encounter;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user