예제 #1
0
파일: Pool.cs 프로젝트: sundersb/invox
        public IEnumerable <Model.InvoiceRecord> LoadInvoiceRecords(Model.OrderSection section, Model.ProphSubsection subsection)
        {
            string sql = SectionizeQuery(Queries.SELECT_INVOICE_PEOPLE, section, subsection);

            sql = RecoursizeQuery(sql);
            return(aInvoice.Load(connectionMain, LocalizeQuery(sql)));
        }
예제 #2
0
파일: Pool.cs 프로젝트: sundersb/invox
        public IEnumerable <Model.Recourse> LoadRecourses(Model.InvoiceRecord irec, Model.OrderSection section, Model.ProphSubsection subsection)
        {
            // Query is cached
            if (section != lastRecoursesSection || lastRecourceSubsection != subsection)
            {
                selectRecourses        = null;
                lastRecoursesSection   = section;
                lastRecourceSubsection = subsection;
            }

            if (selectRecourses == null)
            {
                string sql = LocalizeQuery(Queries.SELECT_RECOURSES);
                sql                         = RecoursizeQuery(sql);
                selectRecourses             = connectionAlt.CreateCommand();
                selectRecourses.CommandText = SectionizeQuery(sql, section, subsection);
                AddStringParameters(selectRecourses, SELECT_RECOURSE_CASES_PARAMS);
            }
            string id = string.Format("{0,6}", irec.Person.Identity);

            selectRecourses.Parameters[0].Value = id;

            List <RecourseAux> rs = aRecourse.Load(selectRecourses).ToList();

            foreach (RecourseAux ra in rs)
            {
                Model.Recourse rec = ra.ToRecourse();
                invox.Dict.ResultOutcome.Instance.Repair(rec);
                rec.Events = LoadEvents(rec, ra, section);
                yield return(rec);
            }
        }
예제 #3
0
파일: Pool.cs 프로젝트: sundersb/invox
        /// <summary>
        /// Подставить в запрос коды отделений в соответствие разделу приложения Д к приказу
        /// </summary>
        string SectionizeQuery(string sql, Model.OrderSection section, Model.ProphSubsection subsection)
        {
            switch (section)
            {
            case Model.OrderSection.D1:
                return(sql.Replace(APPENDIX_SECTION_MARKER, D1_SELECTION));

            case Model.OrderSection.D2:
                return(sql.Replace(APPENDIX_SECTION_MARKER, D2_SELECTION));

            case Model.OrderSection.D3:
                switch (subsection)
                {
                case Model.ProphSubsection.Stage1:
                    return(sql.Replace(APPENDIX_SECTION_MARKER, D3_SELECTION_STAGE1));

                case Model.ProphSubsection.Stage2:
                    return(sql.Replace(APPENDIX_SECTION_MARKER, D3_SELECTION_STAGE2));

                case Model.ProphSubsection.Prophylaxis:
                    return(sql.Replace(APPENDIX_SECTION_MARKER, D3_SELECTION_PROF));

                default: throw new NotImplementedException();
                }

            case Model.OrderSection.D4:
                return(sql.Replace(APPENDIX_SECTION_MARKER, D4_SELECTION));
            }
            return(sql);
        }
예제 #4
0
파일: Pool.cs 프로젝트: sundersb/invox
        public decimal Total(Model.OrderSection section, Model.ProphSubsection subsection)
        {
            string sql    = SectionizeQuery(Queries.SELECT_TOTAL, section, subsection);
            object result = ExecuteScalar(connectionMain, LocalizeQuery(sql));

            return(result != null && result != DBNull.Value ? (decimal)result : 0);
        }
예제 #5
0
파일: Pool.cs 프로젝트: sundersb/invox
        public IEnumerable <Model.Person> LoadPeople(Model.OrderSection section, Model.ProphSubsection subsection)
        {
            string sql = SectionizeQuery(Queries.SELECT_PEOPLE, section, subsection);

            sql = RecoursizeQuery(sql);
            return(aPerson.Load(connectionMain, LocalizeQuery(sql)));
        }
예제 #6
0
        /// <summary>
        /// Создать событие и заполнить его доступными полями
        /// </summary>
        public Model.Event ToEvent(Model.Recourse rec, Model.OrderSection section)
        {
            Model.Event result = new Model.Event();

            // result.Services;                         - Pool.LoadEvents
            result.Identity = ServiceId;
            result.Unit     = Unit;

            if (rec.IsHospitalization)
            {
                result.BedProfile = BedProfile;
                result.Transfer   = Model.Transfer.Independently;
            }
            else
            {
                result.Transfer = Model.Transfer.None;
            }

            result.Child  = Child;
            result.Reason = AidConditions == "3" ? InternalReasonHelper.ToVisitAim(InternalReason) : string.Empty;

#if FOMS
            result.LocalReason = InternalReason.ToFomsReason(soul);
#endif

            result.CardNumber = CardNumber;
            //result.Transfer;                          - Pool.LoadEvents
            //result.DateFrom;                          - Pool.LoadEvents
            result.DateTill = Date;
            //result.BedDays;                           - Pool.LoadEvents
            //result.PrimaryDiagnosis;                  - Pool.LoadEvents

            result.MainDiagnosis = MainDiagnosis;

            //result.FirstIdentified;                   - Pool.LoadEvents
            //result.ConcurrentDiagnosis;               - Pool.LoadEvents
            //result.ComplicationDiagnosis;             - Pool.LoadEvents
            //result.DispensarySupervision;             - Pool.LoadEvents
            //result.ConcurrentMesCode;                 - Pool.LoadEvents

            // Hack to avoid oncology treatment services in polyclinic
            //result.Rehabilitation = Rehabilitation || (section == Model.OrderSection.D4 && !rec.SuspectOncology);
            result.Rehabilitation = Rehabilitation && !rec.SuspectOncology;

            result.Quantity       = Quantity;
            result.SpecialityCode = SpecialityCode;
            result.DoctorCode     = DoctorCode;

            //result.Tariff;                            - Pool.LoadEvents
            //result.Total;                             - Pool.LoadEvents

            // TODO: RecourseAux - HiTech data
            //result.HiTechKind;
            //result.HiTechMethod;
            //result.HiTechCheckDate;
            //result.HiTechCheckNumber;
            //result.HiTechPlannedHospitalizationDate;

            return(result);
        }
예제 #7
0
파일: Pool.cs 프로젝트: sundersb/invox
        public int GetInvoiceRecordsCount(Model.OrderSection section, Model.ProphSubsection subsection)
        {
            string sql = SectionizeQuery(Queries.SELECT_INVOICE_RECORDS_COUNT, section, subsection);

            sql = RecoursizeQuery(sql);
            object result = ExecuteScalar(connectionMain, LocalizeQuery(sql));

            return(result != null && result != DBNull.Value ? (int)(decimal)result : 0);
        }
예제 #8
0
        static bool Run(Data.IInvoice pool, Model.OrderSection section, ref int packet)
        {
            foreach (Model.ProphSubsection s in Model.ProphSubsectionHelper.GetSubsections(section, Options.Pediatric))
            {
                Lib.InvoiceFilename files = Lib.InvoiceFilename.ToAssuranceFund(
                    Options.LpuCode,
                    Options.FomsCode,
                    Options.Year,
                    Options.Month,
                    ++packet,
                    section,
                    s);

                Model.Invoice invoice = new Model.Invoice(files);

                if (!invoice.Export(pool, Options.OutputLocation, Options.LeaveFiles))
                {
                    Console.WriteLine("\r\nОшибка!\r\n");
                    return(false);
                }
            }

            return(true);
        }
예제 #9
0
파일: Pool.cs 프로젝트: sundersb/invox
        /// <summary>
        /// Загрузить события для законченного случая
        /// </summary>
        /// <remarks>
        /// В настоящий момент одному законченному случаю соответствует одно события (т.к. нет
        /// внутрибольничных переводов). Здесь также загружаются услуги для события и обновляются
        /// поля законченного случая данными, которые удалось получить на этом этапе.
        /// </remarks>
        List <Model.Event> LoadEvents(Model.Recourse rec, RecourseAux ra, Model.OrderSection section)
        {
            // Extract single event from the RecourseAux:
            List <Model.Event> result = new List <Model.Event>();

            Model.Event evt = ra.ToEvent(rec, section);
            result.Add(evt);

            // Load auxilliary service records and service models
            List <ServiceAux> ss = LoadServices(ra, evt).Distinct(new ServiceComparer()).OrderBy(s => s.Date).ToList();

            if (ra.InternalReason == InternalReason.SurgeryDayHosp &&
                ss.Count(s => s.ServiceCode == ra.ServiceCode) > 1)
            {
                // Fix for:
                // Два случая ЦАХ у одного пациента с одним и тем же диагнозом
                //  будут выгружены как два случая, но в каждом ВСЕ услуги из обеих госпитализаций

                // Get main service
                ServiceAux sa = ss.FirstOrDefault(s => s.Date == ra.Date && s.ServiceCode == ra.ServiceCode);

                if (sa != null)
                {
                    // Get hospitalization dates
                    DateTime till = sa.Date;
                    DateTime from = till.WorkingDaysBefore(sa.BedDays, true);

                    // Select only services with relevant dates
                    IEnumerable <ServiceAux> sas = ss.Where(s => s.Date <= till && s.Date >= from);
                    ra.UpdateMedicalAid(rec, sas.Last());
                    evt.Services = sas.Select(s => s.ToService(ra)).ToList();

                    // ...supposedly at least one services is selected: the main one
                }
                else
                {
                    ra.UpdateMedicalAid(rec, ss.Last());
                    evt.Services = ss.Select(s => s.ToService(ra)).ToList();
                }
            }
            else
            {
                ra.UpdateMedicalAid(rec, ss.Last());
                evt.Services = ss.Select(s => s.ToService(ra)).ToList();
            }

            // 20190902 - Блядский вид медицинского вмешательства
            if (ra.InternalReason == InternalReason.SurgeryDayHosp)
            {
                Model.Service service = evt.Services.FirstOrDefault(s => s.ServiceCode / 100000 == 3);
                if (service != null)
                {
                    string interventionKind = GetInterventionKind(service.ServiceCode);
                    if (!string.IsNullOrEmpty(interventionKind))
                    {
                        evt.Services.ForEach(s => s.InterventionKind = interventionKind);
                    }
                }
            }

            // Код врача и специальности должны соответствовать закрывающей записи,
            // приводим в соответствие из ra (где было изменено в UpdateMedicalAid())
            evt.SpecialityCode = ra.SpecialityCode;
            evt.DoctorCode     = ra.DoctorCode;

            if (rec.IsHospitalization)
            {
                // Update profile-shifting transfer and total of the bed days
                ServiceAux serv = ss.Where(s => s.Transfer == Model.Transfer.Transferred).FirstOrDefault();

                // Turn transfer to ProfileShift if there has been bed profile change:
                if (serv != null &&
                    ss.GroupBy(s => s.BedProfile).Count() > 1)
                {
                    serv.Transfer = Model.Transfer.ProfileShift;
                }
                evt.BedDays = ss.Select(s => s.BedDays).Sum();
            }

            // Event dates
            if (ra.InternalReason == InternalReason.Stage1 || ra.InternalReason == InternalReason.Prof)
            {
                evt.DateTill = evt.Services.Max(s => s.DateTill);

                // For DD1 - start of the recourse is an antropometry
                ServiceAux sa = ss.Where(s => s.IsAntropometry()).FirstOrDefault();
                if (sa != null)
                {
                    evt.DateFrom = sa.Date;
                }
                else
                {
                    evt.DateFrom = ss.Min(s => s.Date);
                }

#if FOMS1
            }
            else if (ra.InternalReason == InternalReason.Prof)
            {
                // Work around error "Код способа оплаты не соответствует периоду лечения;
                // Цель обращения не соответствует способу оплаты медицинской помощи"
                // Prof events within a single day are discarded with this error
                evt.DateFrom = ra.Date.ShiftDays(-1);

                if (evt.DateFrom == ra.Date)
                {
                    evt.DateTill = ra.Date.ShiftDays(1);
                    Model.Service s = evt.Services.First();
                    if (s != null)
                    {
                        s.DateFrom = evt.DateTill;
                        s.DateTill = evt.DateTill;
                    }
                }
                else
                {
                    evt.DateTill = ra.Date;
                }
#endif
            }
            else
            {
                // For other cases service with minimal date (mayhap hospitalization - reason why not ss.Min())
                // 2 этап - пустая выборка
                try {
                    evt.DateFrom = evt.Services.Min(s => s.DateFrom);
                } catch (Exception e) {
                    Logger.Log(e.Message + string.Format(" - повод {0}, услуга {1}, S.RECID {2}", ra.InternalReason, ra.ServiceCode, ra.ServiceId));
                }
                evt.DateTill = evt.Services.Max(s => s.DateTill);
            }

#if FOMS
            // Задолбал ФОМС с их дурацкими ошибками: дд раз в 2 года ставит "неправильные даты", если дата начала и окончания не совпадают
            // В подушевой услуге ставим даты начала и окончания как во всем закрытом случае

            // 20190417 Хрен там, теперь не только обрезанная ДД
            Model.Service ser = evt.Services.FirstOrDefault(s => s.ServiceCode / 10000 == 5);
            if (ser != null)
            {
                ser.DateFrom = evt.DateFrom;
                ser.DateTill = evt.DateTill;
            }
#endif

            // May change evt and ra's MainDiagnosis:
            ra.FindConcurrentDiagnoses(evt, ss, section);

            // Service diagnosis as recorse's in case of diagnostics
            if (ra.InternalReason == InternalReason.Diagnostics)
            {
                evt.Services.ForEach(s => s.Diagnosis = ra.MainDiagnosis);
            }

            evt.ComplicationDiagnoses = ServiceAux.GetComplicationDiagnoses(ss);

            // Statistic code
            if (!string.IsNullOrEmpty(ra.MainDiagnosis) && ra.MainDiagnosis.First() != 'Z')
            {
                StatisticCode[] sc = ss
                                     .Select(s => s.StatisticCode)
                                     .Where(s => s > StatisticCode.None && s < StatisticCode.Dispensary)
                                     .ToArray();

                if (sc != null && sc.Count() > 0)
                {
                    evt.StatisticsCode = (((int)sc.Max()) - 1).ToString();
                }
                else
                {
                    evt.StatisticsCode = Dict.StatisticsCode.Instance.Get(ra.MainDiagnosis);
                }
            }

            // Профиль МП случая - по профилю закрывающей записи
            rec.Profile = ss.OrderBy(s => s.Date).Last().AidProfile;

            // Other Event fields which can be taken from the services
            evt.Tariff = evt.Services.Sum(s => s.Tariff);
            evt.Total  = evt.Services.Sum(s => s.Total);

            evt.PrimaryDiagnosis = ss.Max(s => s.PrimaryDiagnosis);
            evt.FirstIdentified  = ss.Any(s => s.FirstIdentified);

            if (ra.InternalReason == InternalReason.DispRegister)
            {
                evt.DispensarySupervision = ss.Max(s => s.DispensarySupervision);
                if (evt.DispensarySupervision == Model.DispensarySupervision.None)
                {
                    evt.DispensarySupervision = Model.DispensarySupervision.Observed;
                }
            }
            else if (section == Model.OrderSection.D3)
            {
                // 20190430 - D3 section: disp supervision is explicit
                evt.DispensarySupervision = ss.Max(s => s.DispensarySupervision);
                // Диагнозы на R ФОМС считает подлежащими Д-учету
                if (evt.DispensarySupervision < Model.DispensarySupervision.Observed ||
                    evt.DispensarySupervision > Model.DispensarySupervision.NotSubject)
                {
                    if ("ZY".Contains(evt.MainDiagnosis.First()))
                    {
                        evt.DispensarySupervision = Model.DispensarySupervision.NotSubject;
                    }
                    else
                    {
                        if (evt.FirstIdentified)
                        {
                            evt.DispensarySupervision = Model.DispensarySupervision.Taken;
                        }
                        else
                        {
                            evt.DispensarySupervision = Model.DispensarySupervision.Observed;
                        }
                    }
                }
            }

            evt.ConcurrentMesCode = ss.Max(s => s.ConcurrentMesCode);

            var d2 = ss.Where(s => s.Transfer != Model.Transfer.None);
            if (d2 != null && d2.Count() > 0)
            {
                evt.Transfer = d2.Min(s => s.Transfer);
            }

            // Other Recourse fields -"-
            rec.UnitShift   = ss.Any(s => s.Transfer == Model.Transfer.ProfileShift);
            rec.BirthWeight = ss.Max(s => s.BirthWeight);

            rec.DateFrom = evt.DateFrom;
            rec.DateTill = evt.DateTill;
            rec.Total    = evt.Total;
            rec.BedDays  = evt.BedDays;

            if (RecourseAux.NeedsDirection(rec))
            {
                // Extract directed-from in case when it is needed
                rec.DirectedFrom = ss.Max(s => s.DirectedFrom);
                if (string.IsNullOrEmpty(rec.DirectedFrom))
                {
                    // TODO: LPU code from local to federal
                    rec.DirectedFrom = Options.LpuCode;
                }
                rec.DirectionDate = rec.DateFrom;
            }

            return(result);
        }
예제 #10
0
        public static InvoiceFilename ToAssuranceCompany(string lpuCode,
                                                         string assuranceCompanyCode,
                                                         int year,
                                                         int month,
                                                         int packetNumber,
                                                         Model.OrderSection orderSection,
                                                         Model.ProphSubsection subSection)
        {
            StringBuilder sb = new StringBuilder();

            // Source
            sb.Append('M');
            sb.Append(lpuCode);

            // Destination
            sb.Append('S');
            sb.Append(assuranceCompanyCode);

            sb.Append('_');
            sb.Append(year % 100);
            sb.Append(month.ToString("D2"));
            sb.Append((packetNumber % 100).ToString("D2"));

            string bulk    = sb.ToString();
            string invoice = null;
            string persons = null;

            switch (orderSection)
            {
            case Model.OrderSection.D1:
                invoice = "H" + bulk;
                persons = "L" + bulk;
                break;

            case Model.OrderSection.D2:
                invoice = "T" + bulk;
                persons = "LT" + bulk;
                break;

            case Model.OrderSection.D3:
                bulk    = Model.ProphSubsectionHelper.GetCode(subSection) + bulk;
                invoice = "D" + bulk;
                persons = "L" + bulk;
                break;

            case Model.OrderSection.D4:
                invoice = "C" + bulk;
                persons = "LC" + bulk;
                break;
            }

            return(new InvoiceFilename(persons, invoice)
            {
                clinicCode = lpuCode,
                smoCode = assuranceCompanyCode,
                section = orderSection,
                subsection = subSection,
                year = year,
                month = month,
                code = (year % 100) * 10000 + month * 100 + (packetNumber % 100)
            });
        }
예제 #11
0
        /// <summary>
        /// Загрузить сопутствующие заболевания для события
        /// </summary>
        /// <param name="evt">Событие, которому требуется установить сопутствующие заболевания</param>
        /// <param name="services">Услуги, оказанные в рамках события. Сопутствующие берутся из них</param>
        public void FindConcurrentDiagnoses(Model.Event evt, List <ServiceAux> services, Model.OrderSection section)
        {
            var d1 = services.Select(s => s.ConcurrentDiagnosis)
                     .Where(d => !string.IsNullOrEmpty(d) && d != evt.MainDiagnosis)
                     .Distinct();

            if (d1.Count() > 0)
            {
                evt.ConcurrentDiagnoses = d1.ToList();
            }
            else
            {
                evt.ConcurrentDiagnoses = null;
            }

            // Проверить соответствие диагноза цели обращения (только для разделов D1 и D4)
            if (section == Model.OrderSection.D1 || section == Model.OrderSection.D4)
            {
                DiagnosisKind kind = InternalReason.GetDiagnosisKind();

                if (!kind.Matches(MainDiagnosis))
                {
                    // Если не соответствует

                    // Переносим основное заболевание в сопутствующие
                    if (evt.ConcurrentDiagnoses == null)
                    {
                        evt.ConcurrentDiagnoses = new List <string>();
                    }
                    evt.ConcurrentDiagnoses.Add(MainDiagnosis);

                    // Попытаться найти подходящий в услугах...
                    d1 = services.Select(s => s.PrimaryDiagnosis).Where(d => kind.Matches(d));
                    if (d1.Count() > 0)
                    {
                        evt.MainDiagnosis = MainDiagnosis = d1.First();
                    }
                    else
                    {
                        // ...либо поставить диагноз по умолчанию
                        if (kind == DiagnosisKind.Treatment)
                        {
                            Lib.Logger.Log(string.Format("Не найден подходящий диагноз для случая лечебной цели: RECID {0} (диагноз {1})",
                                                         evt.CardNumber,
                                                         MainDiagnosis));
                        }
                        evt.MainDiagnosis = MainDiagnosis = InternalReason.DefaultDiagnosis();
                        evt.Services.ForEach(s => s.Diagnosis = MainDiagnosis);
                    }
                }
            }
        }