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; } }
///<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); }