///<summary>Gets a good chunk of the data used in the TP Module.</summary> public static TPModuleData GetModuleData(long patNum, bool doMakeSecLog) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) //Remoting role check here to reduce round-trips to the server. { return(Meth.GetObject <TPModuleData>(MethodBase.GetCurrentMethod(), patNum, doMakeSecLog)); } TPModuleData tpData = new TPModuleData(); tpData.Fam = Patients.GetFamily(patNum); tpData.Pat = tpData.Fam.GetPatient(patNum); tpData.PatPlanList = PatPlans.Refresh(patNum); if (!PatPlans.IsPatPlanListValid(tpData.PatPlanList)) { //PatPlans had invalid references and need to be refreshed. tpData.PatPlanList = PatPlans.Refresh(patNum); } tpData.SubList = InsSubs.RefreshForFam(tpData.Fam); tpData.InsPlanList = InsPlans.RefreshForSubList(tpData.SubList); tpData.BenefitList = Benefits.Refresh(tpData.PatPlanList, tpData.SubList); tpData.ClaimList = Claims.Refresh(tpData.Pat.PatNum); tpData.HistList = ClaimProcs.GetHistList(tpData.Pat.PatNum, tpData.BenefitList, tpData.PatPlanList, tpData.InsPlanList, DateTime.Today, tpData.SubList); tpData.ListSubstLinks = SubstitutionLinks.GetAllForPlans(tpData.InsPlanList); TreatPlanType tpTypeCur = (tpData.Pat.DiscountPlanNum == 0?TreatPlanType.Insurance:TreatPlanType.Discount); TreatPlans.AuditPlans(patNum, tpTypeCur); tpData.ListProcedures = Procedures.Refresh(patNum); tpData.ListTreatPlans = TreatPlans.GetAllForPat(patNum); tpData.ArrProcTPs = ProcTPs.Refresh(patNum); if (doMakeSecLog) { SecurityLogs.MakeLogEntry(Permissions.TPModule, patNum, ""); } return(tpData); }
///<summary>Inserts a copy of all of the planNumOld SubstitutionLinks with the planNumNew. This should be done every time a new insplan gets created ///and you want to maintain the SubstitutionLink of the old insplan.</summary> public static void CopyLinksToNewPlan(long planNumNew, long planNumOld) { //No need to check RemotingRole; no call to db. //Get a list of the sub links of the old insplan. After the foreach loop below, this list will no longer contain the sub links for the old insplan. List <SubstitutionLink> listSubstLinksOfOldPlan = SubstitutionLinks.GetAllForPlans(planNumOld); foreach (SubstitutionLink subLink in listSubstLinksOfOldPlan) { //Only change the old planNum with the new planNum. Insert will "create" a new SubstitutionLink with a new primary key. subLink.PlanNum = planNumNew; } InsertMany(listSubstLinksOfOldPlan); }
///<summary>Adds procedures to the appointment.</summary> ///<returns>First item of tuple is the newly added procedures. Second item is all procedures for the appointment.</returns> public static ODTuple <List <Procedure>, List <Procedure> > QuickAddProcs(Appointment apt, Patient pat, List <string> listProcCodesToAdd, long provNum, long provHyg, List <InsSub> SubList, List <InsPlan> listInsPlans, List <PatPlan> listPatPlans, List <Benefit> listBenefits) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { return(Meth.GetObject <ODTuple <List <Procedure>, List <Procedure> > >(MethodBase.GetCurrentMethod(), apt, pat, listProcCodesToAdd, provNum, provHyg, SubList, listInsPlans, listPatPlans, listBenefits)); } Procedures.SetDateFirstVisit(apt.AptDateTime.Date, 1, pat); List <ClaimProc> ClaimProcList = ClaimProcs.Refresh(apt.PatNum); List <ProcedureCode> listProcedureCodes = new List <ProcedureCode>(); foreach (string procCode in listProcCodesToAdd) { listProcedureCodes.Add(ProcedureCodes.GetProcCode(procCode)); } List <long> listProvNumsTreat = new List <long>(); listProvNumsTreat.Add(provNum); listProvNumsTreat.Add(provHyg); //these were both passed in List <SubstitutionLink> listSubstLinks = SubstitutionLinks.GetAllForPlans(listInsPlans); //not available in FormApptEdit List <Fee> listFees = Fees.GetListFromObjects(listProcedureCodes, null, //no procs to pull medicalCodes from listProvNumsTreat, pat.PriProv, pat.SecProv, pat.FeeSched, listInsPlans, new List <long>() { apt.ClinicNum }, null, //procNums for appt already handled above listSubstLinks, pat.DiscountPlanNum); //null,listProvNumsTreat,listProcedureCodes.Select(x=>x.ProvNumDefault).ToList(), //pat.PriProv,pat.SecProv,pat.FeeSched,listInsPlans,new List<long>(){apt.ClinicNum},listProcCodesToAdd,null);//procnums for appt already handled above List <Procedure> listAddedProcs = new List <Procedure>(); //Make a copy of apt with provNum and provHyg, in order to maintain behavior of this method prior to using Procedures.ConstructProcedureForAppt //provNum and provHyg are sent in and are the selected provs in FormApptEdit, which may be different than the current provs on apt Appointment aptCur = apt.Copy(); aptCur.ProvNum = provNum; aptCur.ProvHyg = provHyg; foreach (string procCode in listProcCodesToAdd) { ProcedureCode procCodeCur = ProcedureCodes.GetProcCode(procCode); Procedure proc = Procedures.ConstructProcedureForAppt(procCodeCur.CodeNum, aptCur, pat, listPatPlans, listInsPlans, SubList, listFees); Procedures.Insert(proc); //recall synch not required Procedures.ComputeEstimates(proc, pat.PatNum, ref ClaimProcList, true, listInsPlans, listPatPlans, listBenefits, null, null, true, pat.Age, SubList, null, false, false, listSubstLinks, false, listFees); listAddedProcs.Add(proc); } return(new ODTuple <List <Procedure>, List <Procedure> >(listAddedProcs, Procedures.GetProcsForApptEdit(apt))); }
///<summary>Gets most of the data needed to load the active treatment plan.</summary> ///<param name="doFillHistList">If false, then LoadActiveTPData.HistList will be null.</param> public static LoadActiveTPData GetLoadActiveTpData(long patNum, long treatPlanNum, List <Benefit> listBenefits, List <PatPlan> listPatPlans, List <InsPlan> listInsPlans, DateTime dateTimeTP, List <InsSub> listInsSubs, bool doFillHistList) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) //Remoting role check here to reduce round-trips to the server. { return(Meth.GetObject <LoadActiveTPData>(MethodBase.GetCurrentMethod(), patNum, treatPlanNum, listBenefits, listPatPlans, listInsPlans, dateTimeTP, listInsSubs, doFillHistList)); } LoadActiveTPData data = new LoadActiveTPData(); data.ListTreatPlanAttaches = TreatPlanAttaches.GetAllForTreatPlan(treatPlanNum); data.listProcForTP = Procedures.GetListTPandTPi(Procedures.GetManyProc(data.ListTreatPlanAttaches.Select(x => x.ProcNum).ToList(), false), data.ListTreatPlanAttaches).ToList(); //One thing to watch out for here is that we must be absolutely sure to include all claimprocs for the procedures listed, //regardless of status. Needed for Procedures.ComputeEstimates. This should be fine. data.ClaimProcList = ClaimProcs.RefreshForTP(patNum); if (doFillHistList) { data.HistList = ClaimProcs.GetHistList(patNum, listBenefits, listPatPlans, listInsPlans, -1, dateTimeTP, listInsSubs); } data.ListSubLinks = SubstitutionLinks.GetAllForPlans(listInsPlans); return(data); }
///<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); }