예제 #1
0
 /// <summary>Update only data that is different in newOrthoProcLink</summary>
 public static void Update(OrthoProcLink newOrthoProcLink, OrthoProcLink oldOrthoProcLink)
 {
     if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
     {
         Meth.GetVoid(MethodBase.GetCurrentMethod(), newOrthoProcLink, oldOrthoProcLink);
         return;
     }
     Crud.OrthoProcLinkCrud.Update(newOrthoProcLink, oldOrthoProcLink);
 }
예제 #2
0
 ///<summary>Inserts an OrthoProcLink into the database. Returns the OrthoProcLinkNum.</summary>
 public static long Insert(OrthoProcLink orthoProcLink)
 {
     if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
     {
         orthoProcLink.OrthoProcLinkNum = Meth.GetLong(MethodBase.GetCurrentMethod(), orthoProcLink);
         return(orthoProcLink.OrthoProcLinkNum);
     }
     return(Crud.OrthoProcLinkCrud.Insert(orthoProcLink));
 }
예제 #3
0
        ///<summary>Does not insert it in the DB. Returns an OrthoProcLink of the specified type for the OrthoCaseNum and procNum passed in.</summary>
        public static OrthoProcLink CreateHelper(long orthoCaseNum, long procNum, OrthoProcType procType)
        {
            //No remoting role check; no call to db
            OrthoProcLink orthoProcLink = new OrthoProcLink();

            orthoProcLink.OrthoCaseNum    = orthoCaseNum;
            orthoProcLink.ProcNum         = procNum;
            orthoProcLink.ProcLinkType    = procType;
            orthoProcLink.SecUserNumEntry = Security.CurUser.UserNum;
            return(orthoProcLink);
        }
예제 #4
0
 ///<summary>Fills ref parameters for an orthoProcLink, orthoCase, orthoSchedule, and list of orthoProcLinks for the orthoCase.
 ///These objects are used in several places to call Procedures.ComputeEstimates()</summary>
 public static void FillOrthoCaseObjectsForProc(long procNum, ref OrthoProcLink orthoProcLink, ref OrthoCase orthoCase, ref OrthoSchedule orthoSchedule,
                                                ref List <OrthoProcLink> listOrthoProcLinksForOrthoCase, Dictionary <long, OrthoProcLink> dictOrthoProcLinksForProcList,
                                                Dictionary <long, OrthoCase> dictOrthoCases, Dictionary <long, OrthoSchedule> dictOrthoSchedules, List <OrthoProcLink> listOrthoProcLinksAll)
 {
     //No remoting role check; no call to db
     listOrthoProcLinksForOrthoCase = null;
     dictOrthoProcLinksForProcList.TryGetValue(procNum, out orthoProcLink);
     //If proc is linked to an OrthoCase, get other OrthoCase data needed to update estimates.
     if (orthoProcLink != null)
     {
         long orthoCaseNum = orthoProcLink.OrthoCaseNum;
         dictOrthoCases.TryGetValue(orthoCaseNum, out orthoCase);
         dictOrthoSchedules.TryGetValue(orthoCaseNum, out orthoSchedule);
         listOrthoProcLinksForOrthoCase = listOrthoProcLinksAll.Where(x => x.OrthoCaseNum == orthoCaseNum).ToList();
     }
 }
예제 #5
0
        ///<summary>Sets the BandingDate or DebondDate for an OrthoCase.</summary>
        public static void UpdateDatesByLinkedProc(OrthoProcLink procLink, Procedure proc)
        {
            //No remoting role check; no call to db
            if (procLink.ProcLinkType == OrthoProcType.Visit)
            {
                return;
            }
            OrthoCase orthoCase    = GetOne(procLink.OrthoCaseNum);
            OrthoCase oldOrthoCase = orthoCase.Copy();

            //Update banding date only if banding proc is complete or it is treatment planned and attached to an appointment.
            if (procLink.ProcLinkType == OrthoProcType.Banding && proc.ProcStatus == ProcStat.C || (proc.ProcStatus == ProcStat.TP && proc.AptNum != 0))
            {
                orthoCase.BandingDate = proc.ProcDate;
            }
            else if (procLink.ProcLinkType == OrthoProcType.Debond)
            {
                orthoCase.DebondDate = proc.ProcDate;
            }
            Update(orthoCase, oldOrthoCase);
        }
예제 #6
0
        ///<summary>Returns true if OrthoCase feature is enabled, pat has an active ortho case, no debond procedures are linked to ortho case,
        ///banding procedure is complete if a link for one exists.</summary>
        public static bool WillProcLinkToOrthoCase(long patNum, string procCode, ref OrthoCase activeOrthoCase
                                                   , ref List <OrthoProcLink> listOrthoProcLinksForCase)
        {
            //No remoting role check; no call to db
            List <string> listVisitAndDebondCodes = new List <string>();

            listVisitAndDebondCodes.AddRange(OrthoCases.GetListProcTypeProcCodes(PrefName.OrthoVisitCodes));
            listVisitAndDebondCodes.AddRange(OrthoCases.GetListProcTypeProcCodes(PrefName.OrthoDebondCodes));
            //If Orthocases aren't enabled or code in question is not a visit or debond code return false.
            if (!OrthoCases.HasOrthoCasesEnabled() || !listVisitAndDebondCodes.Contains(procCode))
            {
                return(false);
            }
            if (activeOrthoCase == null)
            {
                activeOrthoCase = OrthoCases.GetActiveForPat(patNum);
            }
            if (activeOrthoCase == null)
            {
                return(false);               //If patient doesn't have an active ortho case return false.
            }
            if (listOrthoProcLinksForCase == null)
            {
                listOrthoProcLinksForCase = GetManyByOrthoCase(activeOrthoCase.OrthoCaseNum);
            }
            //If active ortho case already has a debond procedure completed return false. Ortho case is considered completed.
            if (listOrthoProcLinksForCase.Where(x => x.ProcLinkType == OrthoProcType.Debond).ToList().Count > 0)
            {
                return(false);
            }
            //If banding procedure is linked and it is not complete, return false.
            OrthoProcLink bandingProcLink = listOrthoProcLinksForCase.Where(x => x.ProcLinkType == OrthoProcType.Banding).ToList().FirstOrDefault();

            if (bandingProcLink != null && Procedures.GetOneProc(bandingProcLink.ProcNum, false).ProcStatus != ProcStat.C)
            {
                return(false);
            }
            return(true);
        }
예제 #7
0
        ///<summary>Changes procFee. Links procedure to an active OrthoCase. Returns new ProcLink if the procedure is linked, else returns null.
        ///Should only be used when a procedure is set complete. This will set the procedure's ProcFee but does not update the procedure in the DB.
        ///This must be done if this function returns true.</summary>
        public static OrthoProcLink LinkProcForActiveOrthoCase(Procedure proc, OrthoCase orthoCase = null, List <OrthoProcLink> listProcLinksForCase = null
                                                               , OrthoPlanLink schedulePlanLink    = null, OrthoSchedule orthoSchedule = null)
        {
            //No remoting role check; no call to db
            if (orthoCase == null)
            {
                orthoCase = OrthoCases.GetActiveForPat(proc.PatNum);
            }
            if (orthoCase == null)           //No active ortho case for pat so return.
            {
                return(null);
            }
            OrthoCase orthoCaseOld = orthoCase.Copy();

            if (listProcLinksForCase == null)
            {
                listProcLinksForCase = GetManyByOrthoCase(orthoCase.OrthoCaseNum);
            }
            List <OrthoProcLink> listAllVisitProcLinks = listProcLinksForCase.Where(x => x.ProcLinkType == OrthoProcType.Visit).ToList();

            //Don't link procs to an OrthoCase with a completed debond procedure
            if (listProcLinksForCase.FirstOrDefault(x => x.ProcLinkType == OrthoProcType.Debond) != null)
            {
                return(null);
            }
            if (!orthoCase.IsTransfer)
            {
                OrthoProcLink bandingProcLink = listProcLinksForCase.FirstOrDefault(x => x.ProcLinkType == OrthoProcType.Banding);
                //If proc being set complete is the banding, it is already linked. We just need to set the fee.
                if (bandingProcLink.ProcNum == proc.ProcNum)
                {
                    SetProcFeeForLinkedProc(orthoCase, proc, OrthoProcType.Banding, listAllVisitProcLinks);
                    orthoCase.BandingDate = proc.ProcDate;
                    OrthoCases.Update(orthoCase, orthoCaseOld);
                    return(bandingProcLink);
                }
                Procedure bandingProc = Procedures.GetOneProc(bandingProcLink.ProcNum, false);
                //If proc is not banding and banding is not complete yet, don't link procedure
                if (bandingProc.ProcStatus != ProcStat.C)
                {
                    return(null);
                }
            }
            if (listProcLinksForCase.Select(x => x.ProcNum).ToList().Contains(proc.ProcNum))
            {
                return(null);               //Procedure is not banding and is already linked so do nothing.
            }
            string        procCode        = ProcedureCodes.GetProcCode(proc.CodeNum).ProcCode;
            List <string> listDebondProcs = OrthoCases.GetListProcTypeProcCodes(PrefName.OrthoDebondCodes);
            List <string> listVisitProcs  = OrthoCases.GetListProcTypeProcCodes(PrefName.OrthoVisitCodes);

            if (listVisitProcs.Contains(procCode) || listDebondProcs.Contains(procCode))
            {
                if (schedulePlanLink == null)
                {
                    schedulePlanLink = OrthoPlanLinks.GetOneForOrthoCaseByType(orthoCase.OrthoCaseNum, OrthoPlanLinkType.OrthoSchedule);
                }
                if (orthoSchedule == null)
                {
                    orthoSchedule = OrthoSchedules.GetOne(schedulePlanLink.FKey);
                }
                //Link visit procedure
                if (listVisitProcs.Contains(procCode))
                {
                    OrthoProcLink newVisitProcLink = CreateHelper(orthoCase.OrthoCaseNum, proc.ProcNum, OrthoProcType.Visit);
                    newVisitProcLink.OrthoProcLinkNum = Insert(newVisitProcLink);
                    listAllVisitProcLinks.Add(newVisitProcLink);
                    listProcLinksForCase.Add(newVisitProcLink);
                    SetProcFeeForLinkedProc(orthoCase, proc, OrthoProcType.Visit, listAllVisitProcLinks, schedulePlanLink, orthoSchedule);
                    return(newVisitProcLink);
                }
                //Link debond procedure
                else if (listDebondProcs.Contains(procCode))
                {
                    OrthoProcLink newDebondProcLink = CreateHelper(orthoCase.OrthoCaseNum, proc.ProcNum, OrthoProcType.Debond);
                    newDebondProcLink.OrthoProcLinkNum = Insert(newDebondProcLink);
                    listProcLinksForCase.Add(newDebondProcLink);
                    OrthoCases.SetActiveState(orthoCase, schedulePlanLink, orthoSchedule, false);                 //deactivate the ortho case
                    SetProcFeeForLinkedProc(orthoCase, proc, OrthoProcType.Debond, listAllVisitProcLinks, schedulePlanLink, orthoSchedule);
                    orthoCase.DebondDate = proc.ProcDate;
                    OrthoCases.Update(orthoCase, orthoCaseOld);
                    return(newDebondProcLink);
                }
            }
            return(null);           //Procedure is not a Banding, Visit, or Debond. Do nothing.
        }
예제 #8
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);
        }