Пример #1
0
        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);
        }
Пример #2
0
        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>();
        }
Пример #3
0
        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())
                          } }
            });
        }
Пример #4
0
        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);
        }
    }