diff --git a/.Net Capstone Project/MedplumFhirServicevv1.cs b/.Net Capstone Project/MedplumFhirServicevv1.cs deleted file mode 100644 index 6a57c7b..0000000 --- a/.Net Capstone Project/MedplumFhirServicevv1.cs +++ /dev/null @@ -1,317 +0,0 @@ -using ClinicalInsightsPro.API.Data; -using ClinicalInsightsPro.API.DTOs; -using ClinicalInsightsPro.API.Services.Interfaces; -using Microsoft.EntityFrameworkCore; -using System.Text.Json; - -namespace ClinicalInsightsPro.API.Services; - -public class MedplumFhirService : IMedplumFhirService -{ - private readonly ApplicationDbContext _db; - private readonly ILogger _logger; - - public MedplumFhirService( - ApplicationDbContext db, - ILogger logger) - { - _db = db; - _logger = logger; - } - - public Task> GetMedplumResourcesAsync(string resourceType, string? patientId = null) - { - // Offline/demo mode has normalized tables, not the raw Medplum store. - // The unified Medplum browser is intentionally live-only so the UI - // always shows actual FHIR JSON when the feature is enabled. - throw new InvalidOperationException( - "The Medplum resource browser requires Fhir:UseLiveMedplum=true. " + - "Set MEDPLUM_USE_LIVE=true and configure MEDPLUM_BASE_URL, " + - "MEDPLUM_TOKEN_URL, MEDPLUM_CLIENT_ID and MEDPLUM_CLIENT_SECRET."); - } - - public async Task> GetPatientListAsync() - { - var patients = await _db.Patient - .AsNoTracking() - .OrderBy(x => x.GivenName) - .ThenBy(x => x.FamilyName) - .ToListAsync(); - - return patients.Select(p => new PatientSummaryDto - { - Id = p.Id, - FullName = $"{p.GivenName} {p.FamilyName}", - Age = CalculateAge(p.BirthDate), - Gender = p.Gender, - MedicalRecordNumber = p.MedicalRecordNumber - }).ToList(); - } - - public async Task GetPatientChartAsync(string patientId) - { - var patient = await _db.Patient - .AsNoTracking() - .FirstOrDefaultAsync(p => p.Id == patientId); - - if (patient == null) - { - throw new KeyNotFoundException( - $"Patient '{patientId}' was not found."); - } - - var conditions = await _db.Condition - .AsNoTracking() - .Where(x => x.PatientId == patientId) - .OrderByDescending(x => x.RecordedDate) - .ToListAsync(); - - var observations = await _db.Observation - .AsNoTracking() - .Where(x => x.PatientId == patientId) - .OrderByDescending(x => x.EffectiveDateTime) - .ToListAsync(); - - var allergies = await _db.AllergyIntolerance - .AsNoTracking() - .Where(x => x.PatientId == patientId) - .ToListAsync(); - - var medications = await _db.MedicationRequest - .AsNoTracking() - .Where(x => x.PatientId == patientId) - .ToListAsync(); - - var encounters = await _db.Encounter - .AsNoTracking() - .Where(x => x.PatientId == patientId) - .OrderByDescending(x => x.PeriodStart) - .ToListAsync(); - - _logger.LogInformation( - "Retrieved chart for patient {PatientId}", - patientId); - - return new PatientChartDto - { - PatientId = patient.Id, - - FullName = $"{patient.GivenName} {patient.FamilyName}", - - Age = CalculateAge(patient.BirthDate), - - MedicalRecordNumber = patient.MedicalRecordNumber, - - IdentifierSystem = patient.IdentifierSystem, - IdentifierValue = patient.IdentifierValue, - - NameUse = patient.NameUse, - Prefix = patient.Prefix, - - GivenName = patient.GivenName, - FamilyName = patient.FamilyName, - - TelecomSystem = patient.TelecomSystem, - TelecomUse = patient.TelecomUse, - TelecomValue = patient.TelecomValue, - - Gender = patient.Gender, - - BloodGroup = patient.BloodGroup, - Email = patient.Email, - - BirthDate = patient.BirthDate, - - AddressUse = patient.AddressUse, - AddressType = patient.AddressType, - AddressLine = patient.AddressLine, - - City = patient.City, - State = patient.State, - PostalCode = patient.PostalCode, - - MaritalStatusSystem = patient.MaritalStatusSystem, - MaritalStatusCode = patient.MaritalStatusCode, - MaritalStatusDisplay = patient.MaritalStatusDisplay, - - ContactNameUse = patient.ContactNameUse, - ContactPrefix = patient.ContactPrefix, - - ContactTelecomSystem = patient.ContactTelecomSystem, - ContactTelecomUse = patient.ContactTelecomUse, - ContactTelecomValue = patient.ContactTelecomValue, - - ContactAddressUse = patient.ContactAddressUse, - ContactAddressType = patient.ContactAddressType, - ContactAddressLine = patient.ContactAddressLine, - - ContactCity = patient.ContactCity, - ContactState = patient.ContactState, - ContactPostalCode = patient.ContactPostalCode, - - ContactGender = patient.ContactGender, - ContactOrganizationId = patient.ContactOrganizationId, - - ContactPeriodStart = patient.ContactPeriodStart, - ContactPeriodEnd = patient.ContactPeriodEnd, - - ManagingOrganizationId = patient.ManagingOrganizationId, - - PhotoContentType = patient.PhotoContentType, - PhotoUrl = patient.PhotoUrl, - PhotoTitle = patient.PhotoTitle, - - GeneralPractitionerId = patient.GeneralPractitionerId, - - Conditions = conditions.Select(c => new ChartConditionDto - { - Id = c.Id, - Code = c.ConditionCode, - Display = c.ConditionDisplay, - ClinicalStatus = c.ClinicalStatusDisplay, - VerificationStatus = c.VerificationStatusDisplay, - Severity = c.SeverityDisplay, - OnsetDate = c.OnsetDateTime, - AbatementDate = c.AbatementDateTime, - RecordedDate = c.RecordedDate - }).ToList(), - - Allergies = allergies.Select(a => new ChartAllergyDto - { - Id = a.Id, - Type = a.Type, - ClinicalStatus = a.ClinicalStatus, - VerificationStatus = a.VerificationStatus, - Criticality = a.Criticality, - RecorderPractitionerId = a.RecorderPractitionerId - }).ToList(), - - Medications = medications.Select(m => new ChartMedicationDto - { - Id = m.Id, - MedicationCode = m.MedicationCode, - MedicationDisplay = m.MedicationDisplay, - Status = m.Status, - Intent = m.Intent, - Priority = m.Priority - }).ToList(), - - Observations = observations.Select(o => new ChartObservationDto - { - Id = o.Id, - Code = o.ObservationCode, - Display = o.ObservationDisplay, - Status = o.Status, - CategoryDisplay = o.CategoryDisplay, - InterpretationCode = o.InterpretationCode, - InterpretationDisplay = o.InterpretationDisplay, - EffectiveDate = o.EffectiveDateTime, - NoteText = o.NoteText - }).ToList(), - - Encounters = encounters.Select(e => new ChartEncounterDto - { - Id = e.Id, - Status = e.Status, - ClassCode = e.ClassCode, - ClassDisplay = e.ClassDisplay, - TypeDisplay = e.TypeDisplay, - ServiceTypeDisplay = e.ServiceTypeDisplay, - PeriodStart = e.PeriodStart, - PeriodEnd = e.PeriodEnd - }).ToList() - }; - } - - private static int CalculateAge(DateTime birthDate) - { - var today = DateTime.UtcNow; - - var age = today.Year - birthDate.Year; - - if (birthDate.Date > today.AddYears(-age)) - { - age--; - } - - return age; - } - - // ---- Two-way sync additions ---- - // This class is the OFFLINE/local implementation (used when - // Fhir:UseLiveMedplum=false) — it reads/writes only the local database - // and never talks to a real Medplum server, so there is nothing to push - // or pull here. These methods exist only so this class still satisfies - // IMedplumFhirService; they throw/no-op with a clear message instead of - // silently pretending to sync. Set MEDPLUM_USE_LIVE=true in .env to - // switch the app over to LiveMedplumFhirService, which implements the - // real sync against Medplum's FHIR API. - public Task CreatePatientInMedplumAsync(Models.Patient patient) - { - _logger.LogWarning( - "CreatePatientInMedplumAsync called while running in offline/local mode " + - "(Fhir:UseLiveMedplum=false) — patient {Id} was saved locally only, not pushed to Medplum. " + - "Set MEDPLUM_USE_LIVE=true in .env to enable Medplum sync.", patient.Id); - return Task.FromResult(string.Empty); - } - - public Task UpdatePatientInMedplumAsync(Models.Patient patient) - { - _logger.LogWarning( - "UpdatePatientInMedplumAsync called while running in offline/local mode " + - "(Fhir:UseLiveMedplum=false) — patient {Id} was updated locally only, not pushed to Medplum.", patient.Id); - return Task.CompletedTask; - } - - public Task DeletePatientInMedplumAsync(string medplumId) - { - _logger.LogWarning( - "DeletePatientInMedplumAsync called while running in offline/local mode " + - "(Fhir:UseLiveMedplum=false) — nothing was deleted in Medplum."); - return Task.CompletedTask; - } - - public Task> PullAllPatientsFromMedplumAsync() - { - _logger.LogWarning( - "PullAllPatientsFromMedplumAsync called while running in offline/local mode " + - "(Fhir:UseLiveMedplum=false) — returning an empty list. Set MEDPLUM_USE_LIVE=true in .env " + - "to pull real data from Medplum."); - return Task.FromResult(new List()); - } - - // ---- Practitioner two-way sync (offline no-ops, mirrors Patient above) ---- - public Task CreatePractitionerInMedplumAsync(Models.Practitioner practitioner) - { - _logger.LogWarning( - "CreatePractitionerInMedplumAsync called while running in offline/local mode " + - "(Fhir:UseLiveMedplum=false) — practitioner {Id} was saved locally only, not pushed to Medplum. " + - "Set MEDPLUM_USE_LIVE=true in .env to enable Medplum sync.", practitioner.Id); - return Task.FromResult(string.Empty); - } - - public Task UpdatePractitionerInMedplumAsync(Models.Practitioner practitioner) - { - _logger.LogWarning( - "UpdatePractitionerInMedplumAsync called while running in offline/local mode " + - "(Fhir:UseLiveMedplum=false) — practitioner {Id} was updated locally only, not pushed to Medplum.", practitioner.Id); - return Task.CompletedTask; - } - - public Task DeletePractitionerInMedplumAsync(string medplumId) - { - _logger.LogWarning( - "DeletePractitionerInMedplumAsync called while running in offline/local mode " + - "(Fhir:UseLiveMedplum=false) — nothing was deleted in Medplum."); - return Task.CompletedTask; - } - - public Task> PullAllPractitionersFromMedplumAsync() - { - _logger.LogWarning( - "PullAllPractitionersFromMedplumAsync called while running in offline/local mode " + - "(Fhir:UseLiveMedplum=false) — returning an empty list. Set MEDPLUM_USE_LIVE=true in .env " + - "to pull real data from Medplum."); - return Task.FromResult(new List()); - } -} \ No newline at end of file