Пример #1
0
        ///<summary>Updates writeoff estimated for claimprocs for the passed in clinics. Called only in FormFeeSchedTools, located here to allow unit
        ///testing. Requires an ODProgressExtended to display UI updates.  If clinics are enabled and the user is not clinic restricted and chooses to run
        ///for all clinics, set doUpdatePrevClinicPref to true so that the ClinicNums will be stored in the preference table as they are finished to allow
        ///for pausing/resuming the process.</summary>
        public static long GlobalUpdateWriteoffs(List <long> listWriteoffClinicNums, ODProgressExtended progress, bool doUpdatePrevClinicPref = false)
        {
            //No need to check RemotingRole; no call to db.
            long       totalWriteoffsUpdated = 0;
            List <Fee> listFeesHQ            = Fees.GetByClinicNum(0);//All HQ fees
            Dictionary <long, List <Procedure> > dictPatProcs;
            List <FamProc> listFamProcs;
            Dictionary <long, List <ClaimProc> > dictClaimProcs;
            List <Fee>            listFeesHQandClinic;
            Lookup <FeeKey2, Fee> lookupFeesByCodeAndSched;
            List <InsSub>         listInsSubs;
            List <InsPlan>        listInsPlans;
            List <PatPlan>        listPatPlans;
            List <Benefit>        listBenefits;
            List <Action>         listActions;
            //Get all objects needed to check if procedures are linked to an orthocase here to avoid querying in loops.
            List <OrthoProcLink>             listOrthoProcLinksAll = new List <OrthoProcLink>();
            Dictionary <long, OrthoProcLink> dictOrthoProcLinksAll = new Dictionary <long, OrthoProcLink>();
            Dictionary <long, OrthoCase>     dictOrthoCases        = new Dictionary <long, OrthoCase>();
            Dictionary <long, OrthoSchedule> dictOrthoSchedules    = new Dictionary <long, OrthoSchedule>();

            OrthoCases.GetDataForAllProcLinks(ref listOrthoProcLinksAll, ref dictOrthoProcLinksAll, ref dictOrthoCases, ref dictOrthoSchedules);
            OrthoProcLink        orthoProcLink = null;
            OrthoCase            orthoCase     = null;
            OrthoSchedule        orthoSchedule = null;
            List <OrthoProcLink> listOrthoProcLinksForOrthoCase = null;

            foreach (long clinicNumCur in listWriteoffClinicNums)
            {
                progress.Fire(ODEventType.FeeSched, new ProgressBarHelper(Clinics.GetAbbr(clinicNumCur), "0%", 0, 100, ProgBarStyle.Blocks, "WriteoffProgress"));
                long   rowCurIndex = 0;               //reset for each clinic.
                object lockObj     = new object();    //used to lock rowCurIndex so the threads will correctly increment the count
                progress.Fire(ODEventType.FeeSched, new ProgressBarHelper(Lans.g("FeeSchedEvent", "Getting list to update writeoffs..."),
                                                                          progressBarEventType: ProgBarEventType.TextMsg));
                listFeesHQandClinic = Fees.GetByClinicNum(clinicNumCur);              //could be empty for some clinics that don't use overrides
                listFeesHQandClinic.AddRange(listFeesHQ);
                lookupFeesByCodeAndSched = (Lookup <FeeKey2, Fee>)listFeesHQandClinic.ToLookup(x => new FeeKey2(x.CodeNum, x.FeeSched));
                dictPatProcs             = Procedures.GetAllTp(clinicNumCur)
                                           .GroupBy(x => x.PatNum)
                                           .ToDictionary(x => x.Key, x => Procedures.SortListByTreatPlanPriority(x.ToList()).ToList());
                #region Has Paused or Cancelled
                while (progress.IsPaused)
                {
                    progress.AllowResume();
                    if (progress.IsCanceled)
                    {
                        break;
                    }
                }
                if (progress.IsCanceled)
                {
                    break;
                }
                #endregion Has Paused or Cancelled
                if (dictPatProcs.Count == 0)
                {
                    continue;
                }
                int procCount = dictPatProcs.Sum(x => x.Value.Count);
                listFamProcs = Patients.GetFamilies(dictPatProcs.Keys.ToList()).Where(x => x.Guarantor != null)
                               .Select(x => new FamProc {
                    GuarNum      = x.Guarantor.PatNum,
                    ListPatProcs = x.ListPats.Select(y => new PatProc {
                        PatNum    = y.PatNum,
                        Age       = y.Age,
                        ListProcs = dictPatProcs.TryGetValue(y.PatNum, out List <Procedure> listProcsCurr)?listProcsCurr:new List <Procedure>()
                    }).ToList()
                }).ToList();
                listPatPlans = PatPlans.GetPatPlansForPats(dictPatProcs.Keys.ToList());
                listInsSubs  = InsSubs.GetListInsSubs(dictPatProcs.Keys.ToList());
                List <long> listInsSubNums = listInsSubs.Select(x => x.InsSubNum).ToList();
                listInsSubs.AddRange(InsSubs.GetMany(listPatPlans.Select(x => x.InsSubNum).Distinct().Where(x => !listInsSubNums.Contains(x)).ToList()));
                listInsSubs  = listInsSubs.DistinctBy(x => x.InsSubNum).ToList();
                listInsPlans = InsPlans.RefreshForSubList(listInsSubs);
                listBenefits = Benefits.GetAllForPatPlans(listPatPlans, listInsSubs);
                #region Has Paused or Cancelled
                while (progress.IsPaused)
                {
                    progress.AllowResume();
                    if (progress.IsCanceled)
                    {
                        break;
                    }
                }
                if (progress.IsCanceled)
                {
                    break;
                }
                #endregion Has Paused or Cancelled
                //dictionary of key=PatNum, value=list of claimprocs, i.e. a dictionary linking each PatNum to a list of claimprocs for the given procs
                dictClaimProcs = ClaimProcs.GetForProcs(dictPatProcs.SelectMany(x => x.Value.Select(y => y.ProcNum)).ToList(), useDataReader: true)
                                 .GroupBy(x => x.PatNum)
                                 .ToDictionary(x => x.Key, x => x.ToList());
                #region Has Paused or Cancelled
                while (progress.IsPaused)
                {
                    progress.AllowResume();
                    if (progress.IsCanceled)
                    {
                        break;
                    }
                }
                if (progress.IsCanceled)
                {
                    break;
                }
                #endregion Has Paused or Cancelled
                progress.Fire(ODEventType.FeeSched, new ProgressBarHelper(Lans.g("FeeSchedEvent", "Updating writeoff estimates for patients..."),
                                                                          progressBarEventType: ProgBarEventType.TextMsg));
                listActions = listFamProcs.Select(x => new Action(() => {
                    #region Has Cancelled
                    if (progress.IsCanceled)
                    {
                        return;
                    }
                    #endregion Has Cancelled
                    List <long> listPatNums = x.ListPatProcs.Select(y => y.PatNum).ToList();
                    List <long> listInsSubNumsPatPlanCur          = listPatPlans.Where(y => y.PatNum.In(listPatNums)).Select(y => y.InsSubNum).ToList();
                    List <InsSub> listInsSubsCur                  = listInsSubs.FindAll(y => listPatNums.Contains(y.Subscriber) || y.InsSubNum.In(listInsSubNumsPatPlanCur));
                    List <long> listInsSubPlanNumsCur             = listInsSubsCur.Select(y => y.PlanNum).ToList();
                    List <InsPlan> listInsPlansCur                = listInsPlans.FindAll(y => listInsSubPlanNumsCur.Contains(y.PlanNum));
                    List <SubstitutionLink> listSubstitutionLinks = SubstitutionLinks.GetAllForPlans(listInsPlansCur);
                    List <PatPlan> listPatPlansCur;
                    List <Benefit> listBenefitsCur;
                    foreach (PatProc patProc in x.ListPatProcs)                     //foreach patient in the family
                    {
                        if (patProc.ListProcs.IsNullOrEmpty())
                        {
                            continue;
                        }
                        listPatPlansCur = listPatPlans.FindAll(y => y.PatNum == patProc.PatNum);
                        List <long> listInsPlanNumsCur = listInsPlansCur.Select(y => y.PlanNum).ToList();
                        List <long> listPatPlanNumsCur = listPatPlansCur.Select(y => y.PatPlanNum).ToList();
                        listBenefitsCur = listBenefits
                                          .FindAll(y => listInsPlanNumsCur.Contains(y.PlanNum) || listPatPlanNumsCur.Contains(y.PatPlanNum));
                        listBenefitsCur.Sort(Benefits.SortBenefits);
                        if (!dictClaimProcs.TryGetValue(patProc.PatNum, out List <ClaimProc> listClaimProcsCur))
                        {
                            listClaimProcsCur = new List <ClaimProc>();
                        }
                        foreach (Procedure procCur in patProc.ListProcs)                         //foreach proc for this patient
                        {
                            OrthoCases.FillOrthoCaseObjectsForProc(procCur.ProcNum, ref orthoProcLink, ref orthoCase, ref orthoSchedule
                                                                   , ref listOrthoProcLinksForOrthoCase, dictOrthoProcLinksAll, dictOrthoCases, dictOrthoSchedules, listOrthoProcLinksAll);
                            Procedures.ComputeEstimates(procCur, patProc.PatNum, ref listClaimProcsCur, false, listInsPlansCur, listPatPlansCur, listBenefitsCur,
                                                        null, null, true, patProc.Age, listInsSubsCur, listSubstLinks: listSubstitutionLinks, lookupFees: lookupFeesByCodeAndSched,
                                                        orthoProcLink: orthoProcLink, orthoCase: orthoCase, orthoSchedule: orthoSchedule, listOrthoProcLinksForOrthoCase: listOrthoProcLinksForOrthoCase);
                            double percentage = 0;
                            lock (lockObj) {
                                percentage = Math.Ceiling(((double)(++rowCurIndex) / procCount) * 100);
                            }
                            progress.Fire(ODEventType.FeeSched,
                                          new ProgressBarHelper(Clinics.GetAbbr(clinicNumCur), (int)percentage + "%", (int)percentage, 100, ProgBarStyle.Blocks, "WriteoffProgress"));
                        }
                    }
                })).ToList();
                ODThread.RunParallel(listActions, TimeSpan.FromHours(3),
                                     onException: new ODThread.ExceptionDelegate((ex) => {
                    //Notify the user what went wrong via the text box.
                    progress.Fire(ODEventType.FeeSched, new ProgressBarHelper("Error updating writeoffs: " + ex.Message,
                                                                              progressBarEventType: ProgBarEventType.TextMsg));
                })
                                     );
                if (listWriteoffClinicNums.Count > 1)               //only show if more than one clinic
                {
                    progress.Fire(ODEventType.FeeSched,
                                  new ProgressBarHelper(rowCurIndex + " " + Lans.g("FeeSchedTools", "procedures processed from") + " " + Clinics.GetAbbr(clinicNumCur),
                                                        progressBarEventType: ProgBarEventType.TextMsg));
                }
                totalWriteoffsUpdated += rowCurIndex;
                if (doUpdatePrevClinicPref && rowCurIndex == procCount)
                {
                    //if storing previously completed clinic and we actually completed this clinic's procs, update the pref
                    if (listWriteoffClinicNums.Last() == clinicNumCur)
                    {
                        //if this is the last clinic in the list, clear the last clinic pref so the next time it will run for all clinics
                        Prefs.UpdateString(PrefName.GlobalUpdateWriteOffLastClinicCompleted, "");
                    }
                    else
                    {
                        Prefs.UpdateString(PrefName.GlobalUpdateWriteOffLastClinicCompleted, POut.Long(clinicNumCur));
                    }
                    Signalods.SetInvalid(InvalidType.Prefs);
                }
                #region Has Cancelled
                if (progress.IsCanceled)
                {
                    break;
                }
                #endregion Has Cancelled
            }
            progress.OnProgressDone();
            progress.Fire(ODEventType.FeeSched, new ProgressBarHelper("Writeoffs updated. " + totalWriteoffsUpdated + " procedures processed.\r\nDone.",
                                                                      progressBarEventType: ProgBarEventType.TextMsg));
            return(totalWriteoffsUpdated);
        }