123 lines
4.5 KiB
C#
123 lines
4.5 KiB
C#
using Hl7.Fhir.Model;
|
|
|
|
public class FhirBundleProcessor
|
|
{
|
|
private readonly IPatientService _patients;
|
|
private readonly IEncounterService _encounters;
|
|
private readonly IObservationService _observations;
|
|
private readonly IMedicationService _medications;
|
|
private readonly PatientFhirMapper _patientMapper;
|
|
private readonly EncounterFhirMapper _encounterMapper;
|
|
private readonly ObservationFhirMapper _observationMapper;
|
|
private readonly MedicationAdministrationFhirMapper _medMapper;
|
|
|
|
public FhirBundleProcessor(
|
|
IPatientService patients,
|
|
IEncounterService encounters,
|
|
IObservationService observations,
|
|
IMedicationService medications,
|
|
PatientFhirMapper patientMapper,
|
|
EncounterFhirMapper encounterMapper,
|
|
ObservationFhirMapper observationMapper,
|
|
MedicationAdministrationFhirMapper medMapper)
|
|
{
|
|
_patients = patients;
|
|
_encounters = encounters;
|
|
_observations = observations;
|
|
_medications = medications;
|
|
_patientMapper = patientMapper;
|
|
_encounterMapper = encounterMapper;
|
|
_observationMapper = observationMapper;
|
|
_medMapper = medMapper;
|
|
}
|
|
|
|
public async Task<Bundle> ProcessTransactionAsync(Bundle transaction)
|
|
{
|
|
var response = new Bundle { Type = Bundle.BundleType.TransactionResponse };
|
|
|
|
// Process in dependency order: Patient → Encounter → Observation/MedAdmin
|
|
var entries = transaction.Entry
|
|
.OrderBy(e => Priority(e.Resource))
|
|
.ToList();
|
|
|
|
foreach (var entry in entries)
|
|
{
|
|
var resource = entry.Resource;
|
|
try
|
|
{
|
|
var location = resource switch
|
|
{
|
|
Hl7.Fhir.Model.Patient p => await ProcessPatientAsync(p),
|
|
Hl7.Fhir.Model.Encounter e => await ProcessEncounterAsync(e),
|
|
Hl7.Fhir.Model.Observation o => await ProcessObservationAsync(o),
|
|
Hl7.Fhir.Model.MedicationAdministration m => await ProcessMedAsync(m),
|
|
_ => throw new FhirMappingException(
|
|
$"Unsupported resource type in bundle: {resource.TypeName}", "not-supported")
|
|
};
|
|
|
|
response.Entry.Add(new Bundle.EntryComponent
|
|
{
|
|
Response = new Bundle.ResponseComponent
|
|
{
|
|
Status = "201 Created",
|
|
Location = location
|
|
}
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
response.Entry.Add(new Bundle.EntryComponent
|
|
{
|
|
Response = new Bundle.ResponseComponent
|
|
{
|
|
Status = "422 Unprocessable Entity",
|
|
Outcome = FhirOperationOutcomeBuilder.FromException(ex)
|
|
}
|
|
});
|
|
break; // transaction semantics — stop on first failure
|
|
}
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
private static int Priority(Resource? r) => r switch
|
|
{
|
|
Hl7.Fhir.Model.Patient => 0,
|
|
Hl7.Fhir.Model.Encounter => 1,
|
|
_ => 2
|
|
};
|
|
|
|
private async Task<string> ProcessPatientAsync(Hl7.Fhir.Model.Patient fhir)
|
|
{
|
|
var req = _patientMapper.ToUpsertRequest(fhir);
|
|
var patient = await _patients.RegisterOrUpdateByIdentifierAsync(req);
|
|
return $"Patient/{patient.Id}";
|
|
}
|
|
|
|
private async Task<string> ProcessEncounterAsync(Hl7.Fhir.Model.Encounter fhir)
|
|
{
|
|
var req = await _encounterMapper.ToUpsertRequestAsync(fhir);
|
|
var encounter = await _encounters.OpenOrUpdateByIdentifierAsync(req);
|
|
return $"Encounter/{encounter.Id}";
|
|
}
|
|
|
|
private async Task<string> ProcessObservationAsync(Hl7.Fhir.Model.Observation fhir)
|
|
{
|
|
var mapped = await _observationMapper.ToIngestRequestsAsync(fhir);
|
|
Guid? lastId = null;
|
|
foreach (var item in mapped)
|
|
{
|
|
var result = await _observations.IngestAsync(item.EncounterId, item.Request);
|
|
lastId = result.Observation.Id;
|
|
}
|
|
return $"Observation/{lastId}";
|
|
}
|
|
|
|
private async Task<string> ProcessMedAsync(Hl7.Fhir.Model.MedicationAdministration fhir)
|
|
{
|
|
var (req, encounterId) = await _medMapper.ToCreateRequestAsync(fhir);
|
|
var med = await _medications.CreateAsync(encounterId, req);
|
|
return $"MedicationAdministration/{med.Id}";
|
|
}
|
|
} |