protected override Resource ExecuteCore(EnrichedOperationContext context) { var resultBundle = new Bundle() { Type = Bundle.BundleType.Collection, Entry = new List <Bundle.BundleEntryComponent>() }; if (context.OperationContext.OperationParameters.Parameter.Count(p => p.Name.Equals(MedicationDispenseParameterName)) != 1) { throw new FhirHttpResponseException(HttpStatusCode.BadRequest, "Необходимо указать один MedicationDispense"); } var parameters = new OperationParameters(context.OperationContext.OperationParameters); if (parameters.MedicationDispense == null) { throw new FhirHttpResponseException(HttpStatusCode.BadRequest, "Необходимо указать MedicationDispense"); } if (parameters.MedicationDispense.AuthorizingPrescription == null || parameters.MedicationDispense.AuthorizingPrescription.Count != 1) { throw new FhirHttpResponseException(HttpStatusCode.BadRequest, "Необходимо в MedicationDispense указать ссылку на один MedicationPrescription"); } if (parameters.MedicationDispense.Status != MedicationDispense.MedicationDispenseStatus.Completed) { throw new FhirHttpResponseException(HttpStatusCode.BadRequest, "У MedicationDispense статус должен быть Completed"); } if (parameters.MedicationDispense.Contained == null || parameters.MedicationDispense.Contained.Count(e => e.ResourceType == ResourceType.Location) != 1) { throw new FhirHttpResponseException(HttpStatusCode.BadRequest, "Необходимо в MedicationDispense указать один ресурс Location"); } var medicationPrescription = GetAndValidateMedicationPrescription(parameters.MedicationDispense); if (medicationPrescription.Status != MedicationPrescription.MedicationPrescriptionStatus.Active) { throw new FhirHttpResponseException(HttpStatusCode.BadRequest, "У MedicationPrescription статус должен быть Active"); } GetAndValidatePatient(medicationPrescription); var medicationPrescriptionFactor = medicationPrescription.Extension.FirstOrDefault(e => e.Url.Equals(MedicalPrescriptionFactorUrl))?.Value as FhirDecimal; if (medicationPrescriptionFactor?.Value != null && medicationPrescriptionFactor.Value >= 0 && medicationPrescriptionFactor.Value < 1) { if (context.OperationContext.OperationParameters.Parameter.Count(p => p.Name.Equals(ClaimParameterName)) != 1) { throw new FhirHttpResponseException(HttpStatusCode.BadRequest, "Для льготных рецептов должен указываться один ресурс Claim"); } if (parameters.Claim.Item == null || parameters.Claim.Item.Count > 1 || parameters.Claim.Item.Any() == false) { throw new FhirHttpResponseException(HttpStatusCode.BadRequest, "Для льготных рецептов должен указываться один ресурс в секции Товары и услуги (Claim.Item)"); } var claimItem = parameters.Claim.Item.First(); if (claimItem.Factor == null) { throw new FhirHttpResponseException(HttpStatusCode.BadRequest, "Необходимо указать Коэфициент для определения суммы оплаты"); } if (claimItem.Factor == null) { throw new FhirHttpResponseException(HttpStatusCode.BadRequest, "Необходимо указать Коэфициент для определения суммы оплаты"); } if (claimItem.Factor + medicationPrescriptionFactor?.Value != 1) { throw new FhirHttpResponseException(HttpStatusCode.BadRequest, "Процент оплаты организации не соответствует информации из электронного рецепта"); } } //Рецепт не льготный Claim быть не должно if ((medicationPrescriptionFactor?.Value == null || medicationPrescriptionFactor.Value == 1) && parameters.Claim != null) { throw new FhirHttpResponseException(HttpStatusCode.BadRequest, "Для рецептов, не являющихся льготными, ресурс Claim не нужен"); } //MedicationDispense embedded resource Location установить ссылку на организацию (аптечную сеть), полученную с помощью ОКПО (parameters.MedicationDispense.Contained.FirstOrDefault(e => e.ResourceType == ResourceType.Location) as Location).ManagingOrganization = context.OrganizationReference; var createdMedicationDispense = FhirBase.Create(parameters.MedicationDispense).GetResult <MedicationDispense>(); resultBundle.Entry.Add(new Bundle.BundleEntryComponent() { Resource = createdMedicationDispense }); if (parameters.Claim != null) { //Claim установить ссылку на организацию (аптечную сеть), полученную с помощью ОКПО parameters.Claim.Payee = new Claim.PayeeComponent() { Organization = context.OrganizationReference }; parameters.Claim.SetExtension(ClaimMedicalDispanceUrl, new ResourceReference() { Reference = $"{createdMedicationDispense.TypeName}/{createdMedicationDispense.Id}" }); var createdClaim = FhirBase.Create(parameters.Claim).GetResult <Claim>(); resultBundle.Entry.Add(new Bundle.BundleEntryComponent() { Resource = createdClaim }); } var medicationDispenseFinal = parameters.MedicationDispense.Extension.FirstOrDefault(e => e.Url.Equals(MedicationDispanceFinalDispanceUrl))?.Value as FhirBoolean; if (parameters.MedicationDispense.Status == MedicationDispense.MedicationDispenseStatus.Completed && medicationDispenseFinal != null && medicationDispenseFinal.Value == true) { medicationPrescription.Status = MedicationPrescription.MedicationPrescriptionStatus.Completed; FhirBase.Update(medicationPrescription).GetResult <MedicationPrescription>(); } return(resultBundle); }
public virtual void ConfigureServices(IServiceCollection services) { services.AddCors(); Configuration.GetSection("Toggles").Bind(_toggles); var mvcCoreBuilder = services.AddMvcCore(opt => { opt.RespectBrowserAcceptHeader = true; // false by default opt.InputFormatters.Clear(); opt.InputFormatters.Add(new FhirJsonMediaTypeInputFormatter()); opt.InputFormatters.Add(new FhirXmlMediaTypeInputFormatter()); opt.OutputFormatters.Clear(); opt.OutputFormatters.Add(new FhirJsonMediaTypeOutputFormatter()); opt.OutputFormatters.Add(new FhirXmlMediaTypeOutputFormatter()); } ) .AddFormatterMappings(map => { map.SetMediaTypeMappingForFormat(ContentType.FORMAT_PARAM_XML, ContentType.XML_CONTENT_HEADER); map.SetMediaTypeMappingForFormat(ContentType.FORMAT_PARAM_JSON, ContentType.JSON_CONTENT_HEADER); }) ; //if (_toggles.Authentication) //{ // mvcCoreBuilder.AddScopeRequirementPolicy("EHR"); // services.Configure<Endpoints>(Configuration.GetSection("Endpoints")); //} services.Scan(scan => scan .FromAssembliesOf(typeof(Startup)) .AddClasses(filter => filter.AssignableTo <IValidator>()) .AsImplementedInterfaces()); services.Scan(scan => scan .FromAssembliesOf(typeof(Startup)) .AddClasses(filter => filter.AssignableTo <IInputFormatter>()) .AsImplementedInterfaces()); services.Scan(scan => scan .FromAssembliesOf(typeof(Startup)) .AddClasses(filter => filter.AssignableTo <IOutputFormatter>()) .AsImplementedInterfaces()); services.AddTransient <OperationEngine, OperationEngine>(); services.Scan(scan => scan .FromAssembliesOf(typeof(Startup)) .AddClasses(filter => filter.AssignableTo <IOperationHandler>()) .AsImplementedInterfaces()); services.AddMediatR(typeof(Startup).GetTypeInfo().Assembly); services .Decorate(typeof(IRequestHandler <,>), typeof(FluentValidationRequestHandler <,>)); var connectionString = Configuration.GetConnectionString("prescription_db"); services.UseMediaTypeHeaderEnricher(); services.AddTransient <Func <NpgsqlConnection> >(provider => () => new NpgsqlConnection(connectionString)); services.AddScoped <IFhirDataBaseProvider, FhirDataBaseProvider>(); services.AddTransient <IFhirBase, FhirBase>(); services.AddSingleton(provider => { using (var fhirDataProvider = new FhirDataBaseProvider(() => new NpgsqlConnection(connectionString))) { var fhirBase = new FhirBase(fhirDataProvider); return((Conformance)fhirBase.Conformance("UIIP", "1.2.0", "0.5.0", false)); } }); services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>(); }
protected override Resource ExecuteCore(EnrichedOperationContext context) { var medicalDispanceIdentifier = context.OperationContext.ResourceId; var medicalDispance = FhirBase.Read(ResourceType.MedicationDispense.ToString(), medicalDispanceIdentifier) as MedicationDispense; if (medicalDispance == null) { throw new FhirHttpResponseException(HttpStatusCode.NotFound, "MedicationDispense не найден"); } if (medicalDispance.Status != MedicationDispense.MedicationDispenseStatus.Completed && medicalDispance.Status != MedicationDispense.MedicationDispenseStatus.InProgress) { throw new FhirHttpResponseException(HttpStatusCode.BadRequest, "У MedicationDispense должен быть статус complete или in-progress"); } var medicationPrescription = GetAndValidateMedicationPrescription(medicalDispance); if (medicationPrescription.Status != MedicationPrescription.MedicationPrescriptionStatus.Active && medicationPrescription.Status != MedicationPrescription.MedicationPrescriptionStatus.Completed) { throw new FhirHttpResponseException(HttpStatusCode.BadRequest, "У MedicationPrescription статус должен быть Active или Completed"); } var medicalDispanceLocation = medicalDispance.Contained?.FirstOrDefault(e => e.ResourceType == ResourceType.Location) as Location; if (medicalDispanceLocation == null) { throw new FhirHttpResponseException(HttpStatusCode.BadRequest, "У в MedicationDispense не указан один ресурс Location"); } if (medicalDispanceLocation.ManagingOrganization.ExtractId() != context.OrganizationId) { throw new FhirHttpResponseException(HttpStatusCode.BadRequest, "Аптека может отменять только MedicationDispense, которые были созданы только её аптечной сетью."); } GetAndValidatePatient(medicationPrescription); //Обновляеться статус для MedicationDispense medicalDispance.Status = MedicationDispense.MedicationDispenseStatus.EnteredInError; FhirBase.Update(medicalDispance).GetResult <MedicationDispense>(); //Удаляеться Claim var ballClaims = GetAllClaimsForPrescriptions(new[] { medicationPrescription }); var claim = ballClaims.FirstOrDefault(e => e.GetExtensionValue <ResourceReference>(ClaimMedicalDispanceUrl)?.ExtractId() == medicalDispance.Id); if (claim != null) { FhirBase.Delete(ResourceType.Claim.ToString(), claim.Id); } //Устанавливаеться MedicationPrescription статус Active if (medicationPrescription.Status != MedicationPrescription.MedicationPrescriptionStatus.Active) { medicationPrescription.Status = MedicationPrescription.MedicationPrescriptionStatus.Active; FhirBase.Update(medicationPrescription).GetResult <MedicationPrescription>(); } // Устанавливаеться MedicationDispense.finalDispence = false для всех MedicationDispense var alledicationDispance = GetAllMedicationDIspanceForPrescriptions(new [] { medicationPrescription }); foreach (var medicationDispance in alledicationDispance.Where(m => m.Id != context.OperationContext.ResourceId) .Where(m => m.GetExtensionValue <FhirBoolean>(MedicationDispanceFinalDispanceUrl)? .Value == true)) { medicationDispance.SetExtension(MedicationDispanceFinalDispanceUrl, new FhirBoolean(false)); FhirBase.Update(medicationDispance).GetResult <MedicationDispense>(); } return(new OperationOutcome() { Issue = { new OperationOutcome.OperationOutcomeIssueComponent() { Details = "Операция успешно выполнена", Severity = OperationOutcome.IssueSeverity.Information, Code = new CodeableConcept("http://hl7.org/fhir/http-code", HttpStatusCode.OK.ToString()) } } }); }
protected override Resource ExecuteCore(EnrichedOperationContext context) { var patientIdentifier = context.OperationContext.OperationParameters?.Get(PatientIdentifierParameterName).FirstOrDefault()?.Value as FhirString; var medicationPrescriptionStatus = context.OperationContext.OperationParameters?.Get(MedicalPrescriptionStatusParameterName).FirstOrDefault()?.Value as FhirString; if (patientIdentifier == null) { throw new FhirHttpResponseException(HttpStatusCode.BadRequest, "Необходимо указать параметр patientIdentifier"); } var patient = FhirBase .Search(ResourceType.Patient.ToString(), $"identifier={patientIdentifier.Value}") .GetResult <Bundle>().Entry.Select(e => e.Resource).OfType <Patient>().FirstOrDefault(); if (patient == null || patient.Active == false) { throw new FhirHttpResponseException(HttpStatusCode.NotFound, "Пациент с указанным идентификатором не найден"); } //Получаються все MedicationPrescriptions без учета даты //Потомучто при создании SearchParameter with xpatx f:MedicationPrescription/f:dispense/f:validityPeriod когда в MedicationPrescriptions указан не валидный переод //получаеться ошибка - "22000: range lower bound must be less than or equal to range upper bound" //При попытки создания SearchParameter with xpatx f:MedicationPrescription/f:dispense/f:validityPeriod/f:end //запрос select * from fhir.search_sql('MedicationPrescription', 'end=>2010-06-17') //SELECT ... WHERE((fhirbase_date_idx.index_as_date(medicationprescription.content, '{dispense,validityPeriod,end}'::text[], NULL::text) && '["2010-06-17 00:00:00+03",)')) //а должно быть SELECT ... WHERE((fhirbase_date_idx.index_as_date(medicationprescription.content, '{dispense,validityPeriod,end}'::text[], 'date') && '["2010-06-17 00:00:00+03",)')) //нечто похожее уже обсуждали https://groups.google.com/forum/#!topic/fhirbase/fiuPApM7P9g //Поэтому отсеивание по датам происходит дальше в коде после получения из бд var medicationPrescriptions = FhirBase.Search(ResourceType.MedicationPrescription.ToString(), $"patient:Patient.identifier={patientIdentifier.Value}" + $"&status={ (string.IsNullOrEmpty(medicationPrescriptionStatus?.Value)? "active": medicationPrescriptionStatus.Value)}" + $"&_count={int.MaxValue}") .GetResult <Bundle>().Entry.Select(e => e.Resource).OfType <MedicationPrescription>().Where(m => { DateTime.TryParse(m.Dispense?.ValidityPeriod?.End, out var parsedEndDate); return(parsedEndDate >= DateTime.Today); } ).ToList(); if (medicationPrescriptions.Any() == false) { return new Bundle() { Type = Bundle.BundleType.Searchset } } ; var allMedicationDispense = GetAllMedicationDIspanceForPrescriptions(medicationPrescriptions).ToList(); var allClaims = GetAllClaimsForPrescriptions(medicationPrescriptions).ToList(); var result = new Bundle() { Entry = new List <Bundle.BundleEntryComponent>() }; result.Entry.Add(new Bundle.BundleEntryComponent() { Resource = new Patient() { Name = patient.Name, Active = patient.Active, BirthDate = patient.BirthDate, Gender = patient.Gender, Identifier = patient.Identifier.Where(i => i.System.Equals(MedicalCardIdentifierSystem)).ToList() } }); foreach (var prescription in medicationPrescriptions) { var entry = new List <Bundle.BundleEntryComponent>() { new Bundle.BundleEntryComponent() { Search = new Bundle.BundleEntrySearchComponent() { Mode = Bundle.SearchEntryMode.Match }, Resource = prescription } }; entry.AddRange(allMedicationDispense.Where(m => m.AuthorizingPrescription.Any(p => p.ExtractId() == prescription.Id)).Select(m => new Bundle.BundleEntryComponent() { Resource = m, Search = new Bundle.BundleEntrySearchComponent() { Mode = Bundle.SearchEntryMode.Include } })); entry.AddRange(allClaims.Where(m => m.OriginalPrescription.ExtractId() == prescription.Id).Select(m => new Bundle.BundleEntryComponent() { Resource = m, Search = new Bundle.BundleEntrySearchComponent() { Mode = Bundle.SearchEntryMode.Include } })); result.Entry.Add(new Bundle.BundleEntryComponent() { Resource = new Bundle() { Entry = entry } }); } return(result); } }