using Hl7.Fhir.Model; using Microsoft.EntityFrameworkCore; public class FhirBundleProcessor { private readonly AppDbContext _db; 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( AppDbContext db, IPatientService patients, IEncounterService encounters, IObservationService observations, IMedicationService medications, PatientFhirMapper patientMapper, EncounterFhirMapper encounterMapper, ObservationFhirMapper observationMapper, MedicationAdministrationFhirMapper medMapper) { _db = db; _patients = patients; _encounters = encounters; _observations = observations; _medications = medications; _patientMapper = patientMapper; _encounterMapper = encounterMapper; _observationMapper = observationMapper; _medMapper = medMapper; } public async Task ProcessTransactionAsync(Bundle transaction) { var response = new Bundle { Type = Bundle.BundleType.TransactionResponse }; var entries = transaction.Entry .OrderBy(e => Priority(e.Resource)) .ToList(); await using var tx = await _db.Database.BeginTransactionAsync(); 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) { await tx.RollbackAsync(); response.Entry.Add(new Bundle.EntryComponent { Response = new Bundle.ResponseComponent { Status = "422 Unprocessable Entity", Outcome = FhirOperationOutcomeBuilder.FromException(ex) } }); return response; } } await tx.CommitAsync(); return response; } private static int Priority(Resource? r) => r switch { Hl7.Fhir.Model.Patient => 0, Hl7.Fhir.Model.Encounter => 1, _ => 2 }; private async Task ProcessPatientAsync(Hl7.Fhir.Model.Patient fhir) { var req = _patientMapper.ToUpsertRequest(fhir); var patient = await _patients.RegisterOrUpdateByIdentifierAsync(req); return $"Patient/{patient.Id}"; } private async Task 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 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 ProcessMedAsync(Hl7.Fhir.Model.MedicationAdministration fhir) { var (req, encounterId) = await _medMapper.ToCreateRequestAsync(fhir); var med = await _medications.CreateAsync(encounterId, req); return $"MedicationAdministration/{med.Id}"; } }