private long GlobalUpdateWriteoffs(long clinicNum)
        {
            List <long> listWriteoffClinics = new List <long>()
            {
                clinicNum
            };
            ODProgressExtended progress = new ODProgressExtended(ODEventType.FeeSched, new FeeSchedEvent(), new System.Windows.Forms.Form(),
                                                                 tag: new ProgressBarHelper(Lans.g(this, "Write-off Update Progress"), progressBarEventType: ProgBarEventType.Header),
                                                                 cancelButtonText: Lans.g(this, "Close"));

            progress.Fire(ODEventType.FeeSched, new ProgressBarHelper("", "0%"
                                                                      , 0, 100, ProgBarStyle.Blocks, "WriteoffProgress"));
            return(FeeScheds.GlobalUpdateWriteoffs(listWriteoffClinics, progress));
        }
        private string RepairTables(List <string> listTablesToRepair, ODProgressExtended progExtended)
        {
            string results = "";

            for (int i = 0; i < listTablesToRepair.Count; i++)
            {
                DataTable table = GetTable("REPAIR TABLE " + listTablesToRepair[i]);
                for (int j = 0; j < table.Rows.Count; j++)
                {
                    if (progExtended.IsPauseOrCancel())
                    {
                        break;
                    }
                    string msg = "Repairing table " + listTablesToRepair[i];
                    textResults.AppendText(msg + "\r\n");
                    double percent = (100d * i) / listTablesToRepair.Count;
                    progExtended.UpdateProgress(msg, "", percent.ToString("F") + "%", (int)percent, 100);
                    progExtended.Fire(new ODEventArgs(ODEventType.Undefined, new ProgressBarHelper(msg, progressBarEventType: ProgBarEventType.TextMsg)));
                    string line = "";
                    for (int k = 0; k < table.Columns.Count; k++)
                    {
                        line += table.Rows[j][k].ToString() + ", ";
                        if (listTablesToRepair[i] == "patient")
                        {
                            if (line.Contains("Number of rows changed"))
                            {
                                string data = line.Substring(line.IndexOf("from") + 5).TrimEnd();
                                string num2 = data.Substring(data.IndexOf("to") + 3).TrimEnd(',');
                                string num1 = data.Remove(data.IndexOf("to")).TrimEnd();
                                if ((Convert.ToInt32(num1)) > (Convert.ToInt32(num2)))
                                {
                                    _patientRowsLost = true;
                                }
                            }
                        }
                    }
                    results += line + "\r\n";
                }
            }
            return(results);
        }
        private void butCheck_Click(object sender, EventArgs e)
        {
            if (_isCheckRunning || _isRepairRunning)
            {
                return;
            }
            if (!OpenConnection())
            {
                return;
            }
            _isCheckRunning = true;
            string             command      = "SHOW FULL TABLES WHERE Table_type='BASE TABLE'";//Tables, not views.  Does not work in MySQL 4.1, however we test for MySQL version >= 5.0 in PrefL.
            ODProgressExtended progExtended = new ODProgressExtended(ODEventType.Undefined, new DatabaseIntegrityEvent(),
                                                                     this, tag: new ProgressBarHelper(("Check Initializing...")));

            try {
                Cursor = Cursors.WaitCursor;
                DataTable     tableAllTables = GetTable(command);
                List <string> listTableNames = tableAllTables.Rows.OfType <DataRow>().Select(x => x[0].ToString()).ToList();
                _corruptTables = new List <string>();
                List <string> listCheckFailed = new List <string>();
                for (int i = 0; i < listTableNames.Count; i++)
                {
                    string tableName = listTableNames[i];
                    if (progExtended.IsPauseOrCancel())
                    {
                        break;
                    }
                    string msg = "Checking table " + tableName;
                    textResults.AppendText(msg + "\r\n");
                    double percent = (100d * i) / listTableNames.Count;
                    progExtended.UpdateProgress(msg, "", percent.ToString("F") + "%", (int)percent, 100);
                    progExtended.Fire(new ODEventArgs(ODEventType.Undefined, new ProgressBarHelper(msg, progressBarEventType: ProgBarEventType.TextMsg)));
                    try {
                        command = "CHECK TABLE " + tableName;
                        DataTable tableOneTable = GetTable(command);
                        int       lastRow       = tableOneTable.Rows.Count - 1;
                        int       lastCol       = tableOneTable.Columns.Count - 1;
                        string    lastcell      = tableOneTable.Rows[lastRow][lastCol].ToString();
                        if (lastcell != "OK")
                        {
                            _corruptTables.Add(tableName);
                        }
                    }
                    catch {
                        listCheckFailed.Add(tableName);
                    }
                }
                Cursor = Cursors.Default;
                if (listCheckFailed.Count > 0)
                {
                    MessageBox.Show("Table check failed for some tables.\r\n"
                                    + "For these tables, we could not determine if repair is needed:\r\n\r\n"
                                    + string.Join(",", listCheckFailed));
                }
            }
            catch (Exception ex) {
                MessageBox.Show(ex.Message + "\r\n" + ex.StackTrace);
            }
            finally {
                progExtended.Close();
                Cursor = Cursors.Default;
                _con.Close();
                _isCheckRunning = false;
            }
            if (_corruptTables.Count == 0)
            {
                textResults.AppendText("You have no corrupt tables.\r\n\r\n");
            }
            else
            {
                string msgCorrupt = "You have the following corrupt tables:\r\n"
                                    + string.Join(",", _corruptTables) + "\r\n"
                                    + "Select 'Repair' while on the server to repair corrupt tables. A backup will be made for you.";
                MessageBox.Show(msgCorrupt);
                textResults.AppendText(msgCorrupt);
            }
        }
        private void butRepair_Click(object sender, EventArgs e)
        {
            if (_isCheckRunning || _isRepairRunning)
            {
                return;
            }
            _patientRowsLost = false;
            if (!OpenConnection())
            {
                return;
            }
            if (CheckInnoDb() > 0)
            {
                MessageBox.Show(this, "This tool cannot be run with InnoDb tables.");
                return;
            }
            //If tool is not currently being run on the server (i.e, textComputer.Text is not the current computer or localhost), they cannot use the Repair function.
            if (textComputerName.Text.ToLower() != Environment.MachineName.ToLower() && textComputerName.Text.ToLower() != "localhost")
            {
                MessageBox.Show("Repair must be run on the server.");
                return;
            }
            string    command        = "SELECT @@datadir";//this finds the path to the data directory that the databases are stored in.
            DataTable pathTable      = GetTable(command);
            string    dataPath       = pathTable.Rows[0][0].ToString();
            string    backupDateTime = DateTime.Now.ToString("ddMMyyyy_HHmmss");

            if (!DirectoryCopy(dataPath, textDatabase.Text))
            {
                return;
            }
            if (MessageBox.Show(this, "Backup of selected Database has been created.\r\n"
                                + "Would you like to continue?\r\n"
                                + "Click OK to continue, otherwise click Cancel.", "", MessageBoxButtons.OKCancel) != DialogResult.OK)
            {
                return;
            }
            //this tool would only be used with MySQL, so the current code is just fine.
            _isRepairRunning = true;
            ODProgressExtended progExtended = new ODProgressExtended(ODEventType.Undefined, new DatabaseIntegrityEvent(),
                                                                     this, tag: new ProgressBarHelper(("Repair Initializing...")));

            try {
                Cursor = Cursors.WaitCursor;
                string results = "";
                if (_corruptTables == null || _corruptTables.Count <= 0)
                {
                    //run on all tables
                    command = "SHOW FULL TABLES WHERE Table_type='BASE TABLE'";
                    DataTable     table      = GetTable(command);
                    List <string> listTables = table.Rows.OfType <DataRow>().Select(x => x[0].ToString()).ToList();
                    results = RepairTables(listTables, progExtended);
                }
                else
                {
                    results = RepairTables(_corruptTables, progExtended);
                }
                SaveToLog(results, backupDateTime);
                if (_corruptTables != null)
                {
                    _corruptTables.Clear();
                }
                if (_patientRowsLost)
                {
                    MessageBox.Show("Rows have been lost in the patient table. Please call support and escalate to a conversions engineer or a senior engineer.");
                }
                textResults.AppendText("Finished table repair. Check information in 'RepairLog_" + backupDateTime + ".txt' to verify that tables are not corrupt."
                                       + "\r\n\r\nResults:\r\n" + results + "\r\n");
            }
            catch (Exception ex) {
                MessageBox.Show(ex.Message);
            }
            finally {
                progExtended.Close();
                Cursor = Cursors.Default;
                _con.Close();
                _isRepairRunning = false;
            }
        }
Beispiel #5
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);
        }