private void butOK_Click(object sender, System.EventArgs e) { if (textDateCalc.errorProvider1.GetError(textDateCalc) != "" ) { MsgBox.Show(this, "Please fix data entry errors first."); return; } if (!MsgBox.Show(this, true, "Click OK to update aging.")) { return; } Cursor = Cursors.WaitCursor; Patients.ResetAging(); int[] allGuarantors = Ledgers.GetAllGuarantors(); for (int i = 0; i < allGuarantors.Length; i++) { Ledgers.ComputeAging(allGuarantors[i], PIn.PDate(textDateCalc.Text)); Patients.UpdateAging(allGuarantors[i], Ledgers.Bal[0], Ledgers.Bal[1], Ledgers.Bal[2] , Ledgers.Bal[3], Ledgers.InsEst, Ledgers.BalTotal); } if (Prefs.UpdateString("DateLastAging", POut.PDate(DateTime.Today, false))) { DataValid.SetInvalid(InvalidTypes.Prefs); } Cursor = Cursors.Default; MsgBox.Show(this, "Aging Complete"); DialogResult = DialogResult.OK; }
private void butUndo_Click(object sender, EventArgs e) { if (radioFinanceCharge.Checked) { if (MessageBox.Show(Lan.g(this, "Undo all finance charges for ") + textDateUndo.Text + "?", "", MessageBoxButtons.OKCancel) != DialogResult.OK) { return; } long rowsAffected = Adjustments.UndoFinanceCharges(PIn.Date(textDateUndo.Text)); MessageBox.Show(Lan.g(this, "Finance charge adjustments deleted: ") + rowsAffected.ToString()); Ledgers.RunAging(); SecurityLogs.MakeLogEntry(Permissions.Setup, 0, "Finance Charges undo. Date " + textDateUndo.Text); DialogResult = DialogResult.OK; } else if (radioBillingCharge.Checked) { if (MessageBox.Show(Lan.g(this, "Undo all billing charges for ") + textDateUndo.Text + "?", "", MessageBoxButtons.OKCancel) != DialogResult.OK) { return; } long rowsAffected = Adjustments.UndoBillingCharges(PIn.Date(textDateUndo.Text)); MessageBox.Show(Lan.g(this, "Billing charge adjustments deleted: ") + rowsAffected.ToString()); Ledgers.RunAging(); SecurityLogs.MakeLogEntry(Permissions.Setup, 0, "Billing Charges undo. Date " + textDateUndo.Text); DialogResult = DialogResult.OK; } }
///<summary>If !isPreCharges, a message box will display for any errors instructing users to try again. If the failed aging attempt is after ///charges have been added/deleted, we don't want to inform the user that the transaction failed so run again since the charges were successfully ///inserted/deleted and it was only updating the aged balances that failed. If isPreCharges, this won't run aging again if the last aging run was ///today. If !isPreCharges, we will run aging even if it was run today to update aged bals to include the charges added/deleted.</summary> private bool RunAgingEnterprise(bool isOnLoad = false) { DateTime dtNow = MiscData.GetNowDateTime(); DateTime dtToday = dtNow.Date; DateTime dateLastAging = PrefC.GetDate(PrefName.DateLastAging); if (isOnLoad && dateLastAging.Date == dtToday) { return(true); //this is prior to inserting/deleting charges and aging has already been run for this date } Prefs.RefreshCache(); DateTime dateTAgingBeganPref = PrefC.GetDateT(PrefName.AgingBeginDateTime); if (dateTAgingBeganPref > DateTime.MinValue) { if (isOnLoad) { MessageBox.Show(this, Lan.g(this, "In order to add finance charges, aging must be calculated, but you cannot run aging until it has finished " + "the current calculations which began on") + " " + dateTAgingBeganPref.ToString() + ".\r\n" + Lans.g(this, "If you believe the current aging " + "process has finished, a user with SecurityAdmin permission can manually clear the date and time by going to Setup | Miscellaneous and " + "pressing the 'Clear' button.")); } return(false); } Prefs.UpdateString(PrefName.AgingBeginDateTime, POut.DateT(dtNow, false)); //get lock on pref to block others Signalods.SetInvalid(InvalidType.Prefs); //signal a cache refresh so other computers will have the updated pref as quickly as possible Action actionCloseProgress = null; try { actionCloseProgress = ODProgressOld.ShowProgressStatus("FinanceCharge", this, Lan.g(this, "Calculating enterprise aging for all patients as of") + " " + dtToday.ToShortDateString() + "..."); Cursor = Cursors.WaitCursor; Ledgers.ComputeAging(0, dtToday); Prefs.UpdateString(PrefName.DateLastAging, POut.Date(dtToday, false)); } catch (MySqlException ex) { actionCloseProgress?.Invoke(); //effectively terminates progress bar Cursor = Cursors.Default; if (ex == null || ex.Number != 1213) //not a deadlock error, just throw { throw; } if (isOnLoad) { MsgBox.Show(this, "Deadlock error detected in enterprise aging transaction and rolled back. Try again later."); } return(false); } finally { actionCloseProgress?.Invoke(); //effectively terminates progress bar Cursor = Cursors.Default; Prefs.UpdateString(PrefName.AgingBeginDateTime, ""); //clear lock on pref whether aging was successful or not Signalods.SetInvalid(InvalidType.Prefs); } return(true); }
private bool RunAgingEnterprise(DateTime dateCalc) { DateTime dateLastAging = PrefC.GetDate(PrefName.DateLastAging); if (dateLastAging.Date == dateCalc.Date) { if (MessageBox.Show(this, Lan.g(this, "Aging has already been calculated for") + " " + dateCalc.ToShortDateString() + " " + Lan.g(this, "and does not normally need to run more than once per day.\r\n\r\nRun anway?"), "", MessageBoxButtons.YesNo) != DialogResult.Yes) { return(false); } } //Refresh prefs because AgingBeginDateTime is very time sensitive Prefs.RefreshCache(); DateTime dateTAgingBeganPref = PrefC.GetDateT(PrefName.AgingBeginDateTime); if (dateTAgingBeganPref > DateTime.MinValue) { MessageBox.Show(this, Lan.g(this, "You cannot run aging until it has finished the current calculations which began on") + " " + dateTAgingBeganPref.ToString() + ".\r\n" + Lans.g(this, "If you believe the current aging process has finished, a user with SecurityAdmin permission " + "can manually clear the date and time by going to Setup | Miscellaneous and pressing the 'Clear' button.")); return(false); } Prefs.UpdateString(PrefName.AgingBeginDateTime, POut.DateT(MiscData.GetNowDateTime(), false)); //get lock on pref to block others Signalods.SetInvalid(InvalidType.Prefs); //signal a cache refresh so other computers will have the updated pref as quickly as possible Action actionCloseAgingProgress = null; try { actionCloseAgingProgress = ODProgressOld.ShowProgressStatus("ComputeAging", this, Lan.g(this, "Calculating enterprise aging for all patients as of") + " " + dateCalc.ToShortDateString() + "..."); Cursor = Cursors.WaitCursor; Ledgers.ComputeAging(0, dateCalc); Prefs.UpdateString(PrefName.DateLastAging, POut.Date(dateCalc, false)); } catch (MySqlException ex) { actionCloseAgingProgress?.Invoke(); Cursor = Cursors.Default; if (ex == null || ex.Number != 1213) //not a deadlock error, just throw { throw; } MsgBox.Show(this, "Deadlock error detected in aging transaction and rolled back. Try again later."); return(false); } finally { actionCloseAgingProgress?.Invoke(); Cursor = Cursors.Default; Prefs.UpdateString(PrefName.AgingBeginDateTime, ""); //clear lock on pref whether aging was successful or not Signalods.SetInvalid(InvalidType.Prefs); } return(true); }
private void butOK_Click(object sender, System.EventArgs e) { if (textDateCalc.errorProvider1.GetError(textDateCalc) != "") { MsgBox.Show(this, "Please fix data entry errors first."); return; } DateTime dateCalc = PIn.Date(textDateCalc.Text); Action actionCloseAgingProgress = null; if (PrefC.GetBool(PrefName.AgingIsEnterprise)) { //if this is true, dateCalc has to be DateTime.Today and aging calculated daily not monthly. if (!RunAgingEnterprise(dateCalc)) { //Errors displayed from RunAgingEnterprise return; } } else { try { actionCloseAgingProgress = ODProgressOld.ShowProgressStatus("ComputeAging", this, Lan.g(this, "Calculating aging for all patients as of") + " " + dateCalc.ToShortDateString() + "..."); Cursor = Cursors.WaitCursor; Ledgers.ComputeAging(0, dateCalc); } catch (MySqlException ex) { actionCloseAgingProgress?.Invoke(); Cursor = Cursors.Default; if (ex == null || ex.Number != 1213) //not a deadlock error, just throw { throw; } MsgBox.Show(this, "Deadlock error detected in aging transaction and rolled back. Try again later."); DialogResult = DialogResult.Cancel; return; } finally { actionCloseAgingProgress?.Invoke(); Cursor = Cursors.Default; } if (Prefs.UpdateString(PrefName.DateLastAging, POut.Date(dateCalc, false))) { DataValid.SetInvalid(InvalidType.Prefs); } } MsgBox.Show(this, "Aging Complete"); DialogResult = DialogResult.OK; }
private void FormFinanceCharges_Load(object sender, System.EventArgs e) { if (PrefC.GetLong(PrefName.FinanceChargeAdjustmentType) == 0) { MsgBox.Show(this, "No finance charge adjustment type has been set. Please go to Setup | Modules to fix this."); DialogResult = DialogResult.Cancel; return; } if (PrefC.GetLong(PrefName.BillingChargeAdjustmentType) == 0) { MsgBox.Show(this, "No billing charge adjustment type has been set. Please go to Setup | Modules to fix this."); DialogResult = DialogResult.Cancel; return; } Ledgers.RunAging(); if (DefC.Short[(int)DefCat.BillingTypes].Length == 0) //highly unlikely that this would happen { MsgBox.Show(this, "No billing types have been set up or are visible."); DialogResult = DialogResult.Cancel; return; } textDate.Text = DateTime.Today.ToShortDateString(); textAPR.MaxVal = 100; textAPR.MinVal = 0; textAPR.Text = PrefC.GetString(PrefName.FinanceChargeAPR); textBillingCharge.Text = PrefC.GetString(PrefName.BillingChargeAmount); for (int i = 0; i < DefC.Short[(int)DefCat.BillingTypes].Length; i++) { listBillType.Items.Add(DefC.Short[(int)DefCat.BillingTypes][i].ItemName); listBillType.SetSelected(i, true); } string defaultChargeMethod = PrefC.GetString(PrefName.BillingChargeOrFinanceIsDefault); if (defaultChargeMethod == "Finance") { radioFinanceCharge.Checked = true; textDateLastRun.Text = PrefC.GetDate(PrefName.FinanceChargeLastRun).ToShortDateString(); textDateUndo.Text = PrefC.GetDate(PrefName.FinanceChargeLastRun).ToShortDateString(); } else if (defaultChargeMethod == "Billing") { radioBillingCharge.Checked = true; textDateLastRun.Text = PrefC.GetDate(PrefName.BillingChargeLastRun).ToShortDateString(); textDateUndo.Text = PrefC.GetDate(PrefName.BillingChargeLastRun).ToShortDateString(); } }
private bool RunAgingEnterprise(DateTime dateCalc) { DateTime dateLastAging = PrefC.GetDate(PrefName.DateLastAging); if (dateLastAging.Date == dateCalc.Date) { if (MessageBox.Show(this, Lan.g(this, "Aging has already been calculated for") + " " + dateCalc.ToShortDateString() + " " + Lan.g(this, "and does not normally need to run more than once per day.\r\n\r\nRun anyway?"), "", MessageBoxButtons.YesNo) != DialogResult.Yes) { return(false); } } //Refresh prefs because AgingBeginDateTime is very time sensitive Prefs.RefreshCache(); DateTime dateTAgingBeganPref = PrefC.GetDateT(PrefName.AgingBeginDateTime); if (dateTAgingBeganPref > DateTime.MinValue) { MessageBox.Show(this, Lan.g(this, "You cannot run aging until it has finished the current calculations which began on") + " " + dateTAgingBeganPref.ToString() + ".\r\n" + Lans.g(this, "If you believe the current aging process has finished, a user with SecurityAdmin permission " + "can manually clear the date and time by going to Setup | Miscellaneous and pressing the 'Clear' button.")); return(false); } SecurityLogs.MakeLogEntry(Permissions.AgingRan, 0, "Aging Ran - Aging Form"); Prefs.UpdateString(PrefName.AgingBeginDateTime, POut.DateT(MiscData.GetNowDateTime(), false)); //get lock on pref to block others Signalods.SetInvalid(InvalidType.Prefs); //signal a cache refresh so other computers will have the updated pref as quickly as possible Cursor = Cursors.WaitCursor; bool result = true; ODProgress.ShowAction( () => { Ledgers.ComputeAging(0, dateCalc); Prefs.UpdateString(PrefName.DateLastAging, POut.Date(dateCalc, false)); }, startingMessage: Lan.g(this, "Calculating enterprise aging for all patients as of") + " " + dateCalc.ToShortDateString() + "...", actionException: ex => { Ledgers.AgingExceptionHandler(ex, this); result = false; } ); Cursor = Cursors.Default; Prefs.UpdateString(PrefName.AgingBeginDateTime, ""); //clear lock on pref whether aging was successful or not Signalods.SetInvalid(InvalidType.Prefs); return(result); }
private void butOK_Click(object sender, EventArgs e) { if (!Security.IsAuthorized(Permissions.PaymentCreate)) { return; } double splitTotal = _listSplitsCur.Select(x => x.SplitAmt).Sum(); if (!splitTotal.IsZero()) //income transfer { MsgBox.Show(this, "Income transfers must have a split total of 0."); return; } _listSplitsCur.RemoveAll(x => x.SplitAmt.IsZero()); //We don't want any zero splits. They were there just for display purposes. if (_listSplitsCur.Count == 0) { Payments.Delete(_paymentCur); } else { foreach (PaySplit split in _listSplitsCur) { PaySplits.Insert(split); } foreach (PaySplits.PaySplitAssociated split in _listSplitsAssociated) { //Update the FSplitNum after inserts are made. if (split.PaySplitLinked != null && split.PaySplitOrig != null) { PaySplits.UpdateFSplitNum(split.PaySplitOrig.SplitNum, split.PaySplitLinked.SplitNum); } } if (_listSplitsCur.Count > 0) //only make log when a payment with splits was made. { string logText = Payments.GetSecuritylogEntryText(_paymentCur, _paymentCur, isNew: true) + ", " + Lans.g(this, "from Income Transfer Manager."); SecurityLogs.MakeLogEntry(Permissions.PaymentCreate, _paymentCur.PatNum, logText); } string strErrorMsg = Ledgers.ComputeAgingForPaysplitsAllocatedToDiffPats(_patCur.PatNum, _listSplitsCur); if (!string.IsNullOrEmpty(strErrorMsg)) { MessageBox.Show(strErrorMsg); } } DialogResult = DialogResult.OK; }
private void butOK_Click(object sender, System.EventArgs e) { if (textDateCalc.errorProvider1.GetError(textDateCalc) != "" ) { MsgBox.Show(this, "Please fix data entry errors first."); return; } Cursor = Cursors.WaitCursor; Ledgers.ComputeAging(0, PIn.Date(textDateCalc.Text), false); if (Prefs.UpdateString(PrefName.DateLastAging, POut.Date(PIn.Date(textDateCalc.Text), false))) { DataValid.SetInvalid(InvalidType.Prefs); } Cursor = Cursors.Default; MsgBox.Show(this, "Aging Complete"); DialogResult = DialogResult.OK; }
private void butOK_Click(object sender, System.EventArgs e) { if (textDateCalc.errorProvider1.GetError(textDateCalc) != "") { MsgBox.Show(this, "Please fix data entry errors first."); return; } DateTime dateCalc = PIn.Date(textDateCalc.Text); if (PrefC.GetBool(PrefName.AgingIsEnterprise)) { //if this is true, dateCalc has to be DateTime.Today and aging calculated daily not monthly. if (!RunAgingEnterprise(dateCalc)) { //Errors displayed from RunAgingEnterprise return; } } else { SecurityLogs.MakeLogEntry(Permissions.AgingRan, 0, "Aging Ran - Aging Form"); Cursor = Cursors.WaitCursor; bool result = true; ODProgress.ShowAction(() => Ledgers.ComputeAging(0, dateCalc), startingMessage: Lan.g(this, "Calculating aging for all patients as of") + " " + dateCalc.ToShortDateString() + "...", actionException: ex => { Ledgers.AgingExceptionHandler(ex, this); result = false; } ); Cursor = Cursors.Default; if (!result) { DialogResult = DialogResult.Cancel; return; } if (Prefs.UpdateString(PrefName.DateLastAging, POut.Date(dateCalc, false))) { DataValid.SetInvalid(InvalidType.Prefs); } } MsgBox.Show(this, "Aging Complete"); DialogResult = DialogResult.OK; }
private void butOK_Click(object sender, System.EventArgs e) { if (textDate.errorProvider1.GetError(textDate) != "" || textAPR.errorProvider1.GetError(textAPR) != "") { MessageBox.Show(Lan.g(this, "Please fix data entry errors first.")); return; } DateTime date = PIn.Date(textDate.Text); if (PrefC.GetDate(PrefName.FinanceChargeLastRun).AddDays(25) > date) { if (!MsgBox.Show(this, true, "Warning. Finance charges should not be run more than once per month. Continue?")) { return; } } else if (PrefC.GetDate(PrefName.BillingChargeLastRun).AddDays(25) > date) { if (!MsgBox.Show(this, true, "Warning. Billing charges should not be run more than once per month. Continue?")) { return; } } if (listBillType.SelectedIndices.Count == 0) { MsgBox.Show(this, "Please select at least one billing type first."); return; } if (PIn.Long(textAPR.Text) < 2) { if (!MsgBox.Show(this, true, "The APR is much lower than normal. Do you wish to proceed?")) { return; } } if (PrefC.GetBool(PrefName.AgingCalculatedMonthlyInsteadOfDaily) && PrefC.GetDate(PrefName.DateLastAging).AddMonths(1) <= DateTime.Today) { if (!MsgBox.Show(this, MsgBoxButtons.OKCancel, "It has been more than a month since aging has been run. It is recommended that you update the aging date and run aging before continuing.")) { return; } //we might also consider a warning if textDate.Text does not match DateLastAging. Probably not needed for daily aging, though. } PatAging[] AgingList = Patients.GetAgingListArray(); double OverallBalance; int rowsAffected = 0; bool billingMatch; for (int i = 0; i < AgingList.Length; i++) //loop through each guarantor that owes money. { OverallBalance = 0; //this WILL NOT be the same as the patient's total balance if (radio30.Checked) { OverallBalance = AgingList[i].Bal_31_60 + AgingList[i].Bal_61_90 + AgingList[i].BalOver90; } else if (radio60.Checked) { OverallBalance = AgingList[i].Bal_61_90 + AgingList[i].BalOver90; } else if (radio90.Checked) { OverallBalance = AgingList[i].BalOver90; } if (OverallBalance <= .01d) { continue; } billingMatch = false; for (int b = 0; b < listBillType.SelectedIndices.Count; b++) { if (DefC.Short[(int)DefCat.BillingTypes][listBillType.SelectedIndices[b]].DefNum == AgingList[i].BillingType) { billingMatch = true; break; } } if (!billingMatch) { continue; } if (radioFinanceCharge.Checked) { AddFinanceCharge(AgingList[i].PatNum, date, textAPR.Text, OverallBalance, AgingList[i].PriProv); } else if (radioBillingCharge.Checked) { AddBillingCharge(AgingList[i].PatNum, date, textBillingCharge.Text, AgingList[i].PriProv); } rowsAffected++; } if (radioFinanceCharge.Checked) { if (Prefs.UpdateString(PrefName.FinanceChargeAPR, textAPR.Text) | Prefs.UpdateString(PrefName.FinanceChargeLastRun, POut.Date(date, false))) { DataValid.SetInvalid(InvalidType.Prefs); } if (Prefs.UpdateString(PrefName.BillingChargeOrFinanceIsDefault, "Finance")) { DataValid.SetInvalid(InvalidType.Prefs); } MessageBox.Show(Lan.g(this, "Finance Charges Added: ") + rowsAffected.ToString()); Ledgers.RunAging(); DialogResult = DialogResult.OK; } else if (radioBillingCharge.Checked) { if (Prefs.UpdateString(PrefName.BillingChargeAmount, textBillingCharge.Text) | Prefs.UpdateString(PrefName.BillingChargeLastRun, POut.Date(date, false))) { DataValid.SetInvalid(InvalidType.Prefs); } if (Prefs.UpdateString(PrefName.BillingChargeOrFinanceIsDefault, "Billing")) { DataValid.SetInvalid(InvalidType.Prefs); } MessageBox.Show(Lan.g(this, "Billing Charges Added: ") + rowsAffected.ToString()); Ledgers.RunAging(); DialogResult = DialogResult.OK; } }
private void butOK_Click(object sender, System.EventArgs e) { if (!checkBillTypesAll.Checked && listBillType.SelectedIndices.Count == 0) { MsgBox.Show(this, "At least one billing type must be selected."); return; } if (!checkProvAll.Checked && listProv.SelectedIndices.Count == 0) { MsgBox.Show(this, "At least one provider must be selected."); return; } if (textDate.errorProvider1.GetError(textDate) != "") { MsgBox.Show(this, "Invalid date."); return; } DateTime asOfDate = PIn.Date(textDate.Text); //The aging report always show historical numbers based on the date entered. Ledgers.ComputeAging(0, asOfDate, true); ReportSimpleGrid report = new ReportSimpleGrid(); string cmd = "SELECT "; if (PrefC.GetBool(PrefName.ReportsShowPatNum)) { cmd += DbHelper.Concat("Cast(PatNum AS CHAR)", "'-'", "LName", "', '", "FName", "' '", "MiddleI"); } else { cmd += DbHelper.Concat("LName", "', '", "FName", "' '", "MiddleI"); } cmd += ",Bal_0_30,Bal_31_60,Bal_61_90,BalOver90" + ",BalTotal " + ",InsEst" + ",BalTotal-InsEst AS "; //\"$pat\" "; if (DataConnection.DBtype == DatabaseType.MySql) { cmd += "$pat "; } else //Oracle needs quotes. { cmd += "\"$pat\" "; } cmd += "FROM patient " + "WHERE "; if (checkExcludeInactive.Checked) { cmd += "(patstatus != 2) AND "; } if (checkBadAddress.Checked) { cmd += "(zip !='') AND "; } if (checkOnlyNeg.Checked) { cmd += "BalTotal < '-.005' "; } else { if (radioAny.Checked) { cmd += "(Bal_0_30 > '.005' OR Bal_31_60 > '.005' OR Bal_61_90 > '.005' OR BalOver90 > '.005'"; } else if (radio30.Checked) { cmd += "(Bal_31_60 > '.005' OR Bal_61_90 > '.005' OR BalOver90 > '.005'"; } else if (radio60.Checked) { cmd += "(Bal_61_90 > '.005' OR BalOver90 > '.005'"; } else if (radio90.Checked) { cmd += "(BalOver90 > '.005'"; } if (checkIncludeNeg.Checked) { cmd += " OR BalTotal < '-.005'"; } cmd += ") "; } if (!checkBillTypesAll.Checked) { for (int i = 0; i < listBillType.SelectedIndices.Count; i++) { if (i == 0) { cmd += " AND (billingtype = "; } else { cmd += " OR billingtype = "; } cmd += POut.Long(DefC.Short[(int)DefCat.BillingTypes][listBillType.SelectedIndices[i]].DefNum); } cmd += ") "; } if (!checkProvAll.Checked) { for (int i = 0; i < listProv.SelectedIndices.Count; i++) { if (i == 0) { cmd += " AND (PriProv = "; } else { cmd += " OR PriProv = "; } cmd += POut.Long(ProviderC.ListShort[listProv.SelectedIndices[i]].ProvNum); } cmd += ") "; } cmd += "ORDER BY LName,FName"; report.Query = cmd; FormQuery2 = new FormQuery(report); FormQuery2.IsReport = true; FormQuery2.SubmitReportQuery(); //Recompute aging in a non-historical way, so that the numbers are returned to the way they //are normally used in other parts of the program. Ledgers.RunAging(); //if(Prefs.UpdateString(PrefName.DateLastAging",POut.PDate(asOfDate,false))) { // DataValid.SetInvalid(InvalidType.Prefs); //} report.Title = "AGING REPORT"; report.SubTitle.Add(PrefC.GetString(PrefName.PracticeTitle)); report.SubTitle.Add("As of " + textDate.Text); if (radioAny.Checked) { report.SubTitle.Add("Any Balance"); } if (radio30.Checked) { report.SubTitle.Add("Over 30 Days"); } if (radio60.Checked) { report.SubTitle.Add("Over 60 Days"); } if (radio90.Checked) { report.SubTitle.Add("Over 90 Days"); } if (checkBillTypesAll.Checked) { report.SubTitle.Add("All Billing Types"); } else { string subt = DefC.Short[(int)DefCat.BillingTypes][listBillType.SelectedIndices[0]].ItemName; for (int i = 1; i < listBillType.SelectedIndices.Count; i++) { subt += ", " + DefC.Short[(int)DefCat.BillingTypes][listBillType.SelectedIndices[i]].ItemName; } report.SubTitle.Add(subt); } //report.InitializeColumns(8); report.SetColumn(this, 0, "GUARANTOR", 160); report.SetColumn(this, 1, "0-30 DAYS", 80, HorizontalAlignment.Right); report.SetColumn(this, 2, "30-60 DAYS", 80, HorizontalAlignment.Right); report.SetColumn(this, 3, "60-90 DAYS", 80, HorizontalAlignment.Right); report.SetColumn(this, 4, "> 90 DAYS", 80, HorizontalAlignment.Right); report.SetColumn(this, 5, "TOTAL", 85, HorizontalAlignment.Right); report.SetColumn(this, 6, "-INS EST", 85, HorizontalAlignment.Right); report.SetColumn(this, 7, "=PATIENT", 85, HorizontalAlignment.Right); FormQuery2.ShowDialog(); DialogResult = DialogResult.OK; }
private void butOK_Click(object sender, System.EventArgs e) { if (textDate.errorProvider1.GetError(textDate) != "" || textAPR.errorProvider1.GetError(textAPR) != "" || textAtLeast.errorProvider1.GetError(textAtLeast) != "" || textOver.errorProvider1.GetError(textOver) != "") { MsgBox.Show(this, "Please fix data entry errors first."); return; } DateTime date = PIn.Date(textDate.Text); if (PrefC.GetDate(PrefName.FinanceChargeLastRun).AddDays(25) > date) { if (!MsgBox.Show(this, true, "Warning. Finance charges should not be run more than once per month. Continue?")) { return; } } else if (PrefC.GetDate(PrefName.BillingChargeLastRun).AddDays(25) > date) { if (!MsgBox.Show(this, true, "Warning. Billing charges should not be run more than once per month. Continue?")) { return; } } if (listBillType.SelectedIndices.Count == 0) { MsgBox.Show(this, "Please select at least one billing type first."); return; } if (PIn.Long(textAPR.Text) < 2) { if (!MsgBox.Show(this, true, "The APR is much lower than normal. Do you wish to proceed?")) { return; } } if (PrefC.GetBool(PrefName.AgingCalculatedMonthlyInsteadOfDaily) && PrefC.GetDate(PrefName.DateLastAging).AddMonths(1) <= DateTime.Today) { if (!MsgBox.Show(this, MsgBoxButtons.OKCancel, "It has been more than a month since aging has been run. It is recommended that you update the " + "aging date and run aging before continuing.")) { return; } //we might also consider a warning if textDate.Text does not match DateLastAging. Probably not needed for daily aging, though. } string chargeType = (radioFinanceCharge.Checked?"Finance":"Billing");//For display only List <long> listSelectedBillTypes = listBillType.SelectedIndices.OfType <int>().Select(x => _listBillingTypeDefs[x].DefNum).ToList(); Action actionCloseProgress = null; int chargesAdded = 0; try { actionCloseProgress = ODProgressOld.ShowProgressStatus("FinanceCharge", this, Lan.g(this, "Gathering patients with aged balances") + "..."); List <PatAging> listPatAgings = Patients.GetAgingListSimple(listSelectedBillTypes, new List <long> { }); //Ordered by PatNum, for thread concurrency long adjType = PrefC.GetLong(PrefName.FinanceChargeAdjustmentType); Dictionary <long, List <Adjustment> > dictPatAdjustments = new Dictionary <long, List <Adjustment> >(); if (!checkCompound.Checked) { int daysOver = (radio30.Checked ? 30 : radio60.Checked ? 60 : 90); DateTime maxAdjDate = MiscData.GetNowDateTime().Date.AddDays(-daysOver); dictPatAdjustments = Adjustments.GetAdjustForPatsByType(listPatAgings.Select(x => x.PatNum).ToList(), adjType, maxAdjDate); } int chargesProcessed = 0; List <Action> listActions = new List <Action>(); foreach (PatAging patAgingCur in listPatAgings) { listActions.Add(new Action(() => { if (++chargesProcessed % 5 == 0) { ODEvent.Fire(new ODEventArgs("FinanceCharge", Lan.g(this, "Processing " + chargeType + " charges") + ": " + chargesProcessed + " out of " + listPatAgings.Count)); } //This WILL NOT be the same as the patient's total balance. Start with BalOver90 since all options include that bucket. Add others if needed. double overallBalance = patAgingCur.BalOver90 + (radio60.Checked?patAgingCur.Bal_61_90:radio30.Checked?(patAgingCur.Bal_31_60 + patAgingCur.Bal_61_90):0); if (overallBalance <= .01d) { return; } if (radioBillingCharge.Checked) { AddBillingCharge(patAgingCur.PatNum, date, textBillingCharge.Text, patAgingCur.PriProv); } else //Finance charge { if (dictPatAdjustments.ContainsKey(patAgingCur.PatNum)) //Only contains key if checkCompound is not checked. { overallBalance -= dictPatAdjustments[patAgingCur.PatNum].Sum(x => x.AdjAmt); //Dict always contains patNum as key, but list can be empty. } if (!AddFinanceCharge(patAgingCur.PatNum, date, textAPR.Text, textAtLeast.Text, textOver.Text, overallBalance, patAgingCur.PriProv, adjType)) { return; } } chargesAdded++; })); } ODThread.RunParallel(listActions, TimeSpan.FromMinutes(2)); //each group of actions gets X minutes. if (radioFinanceCharge.Checked) { if (Prefs.UpdateString(PrefName.FinanceChargeAPR, textAPR.Text) | Prefs.UpdateString(PrefName.FinanceChargeLastRun, POut.Date(date, false)) | Prefs.UpdateString(PrefName.FinanceChargeAtLeast, textAtLeast.Text) | Prefs.UpdateString(PrefName.FinanceChargeOnlyIfOver, textOver.Text) | Prefs.UpdateString(PrefName.BillingChargeOrFinanceIsDefault, "Finance")) { DataValid.SetInvalid(InvalidType.Prefs); } } else if (radioBillingCharge.Checked) { if (Prefs.UpdateString(PrefName.BillingChargeAmount, textBillingCharge.Text) | Prefs.UpdateString(PrefName.BillingChargeLastRun, POut.Date(date, false)) | Prefs.UpdateString(PrefName.BillingChargeOrFinanceIsDefault, "Billing")) { DataValid.SetInvalid(InvalidType.Prefs); } } } finally { actionCloseProgress?.Invoke(); //terminates progress bar } MessageBox.Show(Lan.g(this, chargeType + " charges added") + ": " + chargesAdded); if (PrefC.GetBool(PrefName.AgingIsEnterprise)) { if (!RunAgingEnterprise()) { MsgBox.Show(this, "There was an error calculating aging after the " + chargeType.ToLower() + " charge adjustments were added.\r\n" + "You should run aging later to update affected accounts."); } } else { DateTime asOfDate = (PrefC.GetBool(PrefName.AgingCalculatedMonthlyInsteadOfDaily)?PrefC.GetDate(PrefName.DateLastAging):DateTime.Today); actionCloseProgress = ODProgressOld.ShowProgressStatus("FinanceCharge", this, Lan.g(this, "Calculating aging for all patients as of") + " " + asOfDate.ToShortDateString() + "..."); Cursor = Cursors.WaitCursor; try { Ledgers.RunAging(); } catch (MySqlException ex) { actionCloseProgress?.Invoke(); //terminates progress bar Cursor = Cursors.Default; if (ex == null || ex.Number != 1213) //not a deadlock error, just throw { throw; } MsgBox.Show(this, "There was a deadlock error calculating aging after the " + chargeType.ToLower() + " charge adjustments were added.\r\n" + "You should run aging later to update affected accounts."); } finally { actionCloseProgress?.Invoke(); //terminates progress bar Cursor = Cursors.Default; } } DialogResult = DialogResult.OK; }
private void butUndo_Click(object sender, EventArgs e) { string chargeType = (radioFinanceCharge.Checked?"Finance":"Billing"); if (MessageBox.Show(Lan.g(this, "Undo all " + chargeType.ToLower() + " charges for") + " " + textDateUndo.Text + "?", "", MessageBoxButtons.OKCancel) != DialogResult.OK) { return; } Action actionCloseProgress = null; int rowsAffected = 0; try { actionCloseProgress = ODProgressOld.ShowProgressStatus(chargeType + "Charge", this, Lan.g(this, "Deleting " + chargeType.ToLower() + " charge adjustments") + "..."); Cursor = Cursors.WaitCursor; rowsAffected = (int)Adjustments.UndoFinanceOrBillingCharges(PIn.Date(textDateUndo.Text), radioBillingCharge.Checked); } finally { actionCloseProgress?.Invoke(); //effectively terminates progress bar Cursor = Cursors.Default; } MessageBox.Show(Lan.g(this, chargeType + " charge adjustments deleted") + ": " + rowsAffected); if (rowsAffected == 0) { DialogResult = DialogResult.OK; return; } actionCloseProgress = null; if (PrefC.GetBool(PrefName.AgingIsEnterprise)) { if (!RunAgingEnterprise()) { MsgBox.Show(this, "There was an error calculating aging after the " + chargeType.ToLower() + " charge adjustments were deleted.\r\n" + "You should run aging later to update affected accounts."); } } else { try { DateTime asOfDate = (PrefC.GetBool(PrefName.AgingCalculatedMonthlyInsteadOfDaily)?PrefC.GetDate(PrefName.DateLastAging):DateTime.Today); actionCloseProgress = ODProgressOld.ShowProgressStatus("FinanceCharge", this, Lan.g(this, "Calculating aging for all patients as of") + " " + asOfDate.ToShortDateString() + "..."); Cursor = Cursors.WaitCursor; Ledgers.RunAging(); } catch (MySqlException ex) { actionCloseProgress?.Invoke(); //effectively terminates progress bar Cursor = Cursors.Default; if (ex == null || ex.Number != 1213) //not a deadlock error, just throw { throw; } MsgBox.Show(this, "There was a deadlock error calculating aging after the " + chargeType.ToLower() + " charge adjustments were deleted.\r\n" + "You should run aging later to update affected accounts."); } finally { actionCloseProgress?.Invoke(); //effectively terminates progress bar Cursor = Cursors.Default; } } SecurityLogs.MakeLogEntry(Permissions.Setup, 0, chargeType + " Charges undo. Date " + textDateUndo.Text); DialogResult = DialogResult.OK; }
private void FormFinanceCharges_Load(object sender, System.EventArgs e) { if (PrefC.GetLong(PrefName.FinanceChargeAdjustmentType) == 0) { MsgBox.Show(this, "No finance charge adjustment type has been set. Please go to Setup | Account to fix this."); DialogResult = DialogResult.Cancel; return; } if (PrefC.GetLong(PrefName.BillingChargeAdjustmentType) == 0) { MsgBox.Show(this, "No billing charge adjustment type has been set. Please go to Setup | Account to fix this."); DialogResult = DialogResult.Cancel; return; } _listBillingTypeDefs = Defs.GetDefsForCategory(DefCat.BillingTypes, true); if (_listBillingTypeDefs.Count == 0) //highly unlikely that this would happen { MsgBox.Show(this, "No billing types have been set up or are visible."); DialogResult = DialogResult.Cancel; return; } Action actionCloseAgingProgress = null; if (PrefC.GetBool(PrefName.AgingIsEnterprise)) { if (!RunAgingEnterprise(true)) { DialogResult = DialogResult.Cancel; return; } } else { try { DateTime asOfDate = (PrefC.GetBool(PrefName.AgingCalculatedMonthlyInsteadOfDaily)?PrefC.GetDate(PrefName.DateLastAging):DateTime.Today); actionCloseAgingProgress = ODProgressOld.ShowProgressStatus("ComputeAging", this, Lan.g(this, "Calculating aging for all patients as of") + " " + asOfDate.ToShortDateString() + "..."); Cursor = Cursors.WaitCursor; Ledgers.RunAging(); } catch (MySqlException ex) { actionCloseAgingProgress?.Invoke(); //effectively terminates progress bar Cursor = Cursors.Default; if (ex == null || ex.Number != 1213) //not a deadlock error, just throw { throw; } MsgBox.Show(this, "Deadlock error detected in aging transaction and rolled back. Try again later."); DialogResult = DialogResult.Cancel; return; } finally { actionCloseAgingProgress?.Invoke(); //effectively terminates progress bar Cursor = Cursors.Default; } } textDate.Text = DateTime.Today.ToShortDateString(); textAPR.MaxVal = 100; textAPR.MinVal = 0; textAPR.Text = PrefC.GetString(PrefName.FinanceChargeAPR); textBillingCharge.Text = PrefC.GetString(PrefName.BillingChargeAmount); for (int i = 0; i < _listBillingTypeDefs.Count; i++) { listBillType.Items.Add(_listBillingTypeDefs[i].ItemName); listBillType.SetSelected(i, true); } string defaultChargeMethod = PrefC.GetString(PrefName.BillingChargeOrFinanceIsDefault); if (defaultChargeMethod == "Finance") { radioFinanceCharge.Checked = true; textDateLastRun.Text = PrefC.GetDate(PrefName.FinanceChargeLastRun).ToShortDateString(); textDateUndo.Text = PrefC.GetDate(PrefName.FinanceChargeLastRun).ToShortDateString(); textBillingCharge.ReadOnly = true; textBillingCharge.BackColor = System.Drawing.SystemColors.Control; } else if (defaultChargeMethod == "Billing") { radioBillingCharge.Checked = true; textDateLastRun.Text = PrefC.GetDate(PrefName.BillingChargeLastRun).ToShortDateString(); textDateUndo.Text = PrefC.GetDate(PrefName.BillingChargeLastRun).ToShortDateString(); } textAtLeast.Text = PrefC.GetString(PrefName.FinanceChargeAtLeast); textOver.Text = PrefC.GetString(PrefName.FinanceChargeOnlyIfOver); }
private void butSend_Click(object sender, EventArgs e) { //Assuming the use of XCharge. If adding another vendor (PayConnect for example) //make sure to move XCharge validation in FillGrid() to here. if (prog == null) //Gets filled in FillGrid() { return; } if (gridMain.SelectedIndices.Length < 1) { MsgBox.Show(this, "Must select at least one recurring charge."); return; } if (!PaymentsWithinLockDate()) { return; } string recurringResultFile = "Recurring charge results for " + DateTime.Now.ToShortDateString() + " ran at " + DateTime.Now.ToShortTimeString() + "\r\n\r\n"; int failed = 0; int success = 0; string user = ProgramProperties.GetPropVal(prog.ProgramNum, "Username"); string password = ProgramProperties.GetPropVal(prog.ProgramNum, "Password"); #region Card Charge Loop for (int i = 0; i < gridMain.SelectedIndices.Length; i++) { #region X-Charge if (table.Rows[gridMain.SelectedIndices[i]]["XChargeToken"].ToString() != "" && CreditCards.IsDuplicateXChargeToken(table.Rows[gridMain.SelectedIndices[i]]["XChargeToken"].ToString())) { MessageBox.Show(Lan.g(this, "A duplicate token was found, the card cannot be charged for customer: ") + table.Rows[i]["PatName"].ToString()); continue; } insertPayment = false; ProcessStartInfo info = new ProcessStartInfo(xPath); long patNum = PIn.Long(table.Rows[gridMain.SelectedIndices[i]]["PatNum"].ToString()); string resultfile = Path.Combine(Path.GetDirectoryName(xPath), "XResult.txt"); File.Delete(resultfile); //delete the old result file. info.Arguments = ""; double amt = PIn.Double(table.Rows[gridMain.SelectedIndices[i]]["ChargeAmt"].ToString()); DateTime exp = PIn.Date(table.Rows[gridMain.SelectedIndices[i]]["CCExpiration"].ToString()); string address = PIn.String(table.Rows[gridMain.SelectedIndices[i]]["Address"].ToString()); string addressPat = PIn.String(table.Rows[gridMain.SelectedIndices[i]]["AddressPat"].ToString()); string zip = PIn.String(table.Rows[gridMain.SelectedIndices[i]]["Zip"].ToString()); string zipPat = PIn.String(table.Rows[gridMain.SelectedIndices[i]]["ZipPat"].ToString()); info.Arguments += "/AMOUNT:" + amt.ToString("F2") + " /LOCKAMOUNT "; info.Arguments += "/TRANSACTIONTYPE:PURCHASE /LOCKTRANTYPE "; if (table.Rows[gridMain.SelectedIndices[i]]["XChargeToken"].ToString() != "") { info.Arguments += "/XCACCOUNTID:" + table.Rows[gridMain.SelectedIndices[i]]["XChargeToken"].ToString() + " "; info.Arguments += "/RECURRING "; } else { info.Arguments += "/ACCOUNT:" + table.Rows[gridMain.SelectedIndices[i]]["CCNumberMasked"].ToString() + " "; } if (exp.Year > 1880) { info.Arguments += "/EXP:" + exp.ToString("MMyy") + " "; } if (address != "") { info.Arguments += "\"/ADDRESS:" + address + "\" "; } else if (addressPat != "") { info.Arguments += "\"/ADDRESS:" + addressPat + "\" "; } if (zip != "") { info.Arguments += "\"/ZIP:" + zip + "\" "; } else if (zipPat != "") { info.Arguments += "\"/ZIP:" + zipPat + "\" "; } info.Arguments += "/RECEIPT:Pat" + patNum + " "; //aka invoice# info.Arguments += "\"/CLERK:" + Security.CurUser.UserName + " R\" /LOCKCLERK "; info.Arguments += "/RESULTFILE:\"" + resultfile + "\" "; info.Arguments += "/USERID:" + user + " "; info.Arguments += "/PASSWORD:"******" "; info.Arguments += "/HIDEMAINWINDOW "; info.Arguments += "/AUTOPROCESS "; info.Arguments += "/SMALLWINDOW "; info.Arguments += "/AUTOCLOSE "; info.Arguments += "/NORESULTDIALOG "; Cursor = Cursors.WaitCursor; Process process = new Process(); process.StartInfo = info; process.EnableRaisingEvents = true; process.Start(); while (!process.HasExited) { Application.DoEvents(); } Thread.Sleep(200); //Wait 2/10 second to give time for file to be created. Cursor = Cursors.Default; string line = ""; string resultText = ""; recurringResultFile += "PatNum: " + patNum + " Name: " + table.Rows[i]["PatName"].ToString() + "\r\n"; using (TextReader reader = new StreamReader(resultfile)) { line = reader.ReadLine(); while (line != null) { if (resultText != "") { resultText += "\r\n"; } resultText += line; if (line.StartsWith("RESULT=")) { if (line == "RESULT=SUCCESS") { success++; labelCharged.Text = Lan.g(this, "Charged=") + success; insertPayment = true; } else { failed++; labelFailed.Text = Lan.g(this, "Failed=") + failed; } } line = reader.ReadLine(); } recurringResultFile += resultText + "\r\n\r\n"; } #endregion if (insertPayment) { Patient patCur = Patients.GetPat(patNum); Payment paymentCur = new Payment(); paymentCur.DateEntry = nowDateTime.Date; paymentCur.PayDate = GetPayDate(PIn.Date(table.Rows[gridMain.SelectedIndices[i]]["LatestPayment"].ToString()), PIn.Date(table.Rows[gridMain.SelectedIndices[i]]["DateStart"].ToString())); paymentCur.PatNum = patCur.PatNum; paymentCur.ClinicNum = PIn.Long(table.Rows[gridMain.SelectedIndices[i]]["ClinicNum"].ToString()); paymentCur.PayType = PIn.Int(ProgramProperties.GetPropVal(prog.ProgramNum, "PaymentType")); paymentCur.PayAmt = amt; paymentCur.PayNote = resultText; paymentCur.IsRecurringCC = true; Payments.Insert(paymentCur); long provNum = PIn.Long(table.Rows[gridMain.SelectedIndices[i]]["ProvNum"].ToString()); //for payment plans only if (provNum == 0) //Regular payments need to apply to the provider that the family owes the most money to. { DataTable dt = Patients.GetPaymentStartingBalances(patCur.Guarantor, paymentCur.PayNum); double highestAmt = 0; for (int j = 0; j < dt.Rows.Count; j++) { double afterIns = PIn.Double(dt.Rows[j]["AfterIns"].ToString()); if (highestAmt >= afterIns) { continue; } highestAmt = afterIns; provNum = PIn.Long(dt.Rows[j]["ProvNum"].ToString()); } } PaySplit split = new PaySplit(); split.PatNum = paymentCur.PatNum; split.ClinicNum = paymentCur.ClinicNum; split.PayNum = paymentCur.PayNum; split.ProcDate = paymentCur.PayDate; split.DatePay = paymentCur.PayDate; split.ProvNum = provNum; split.SplitAmt = paymentCur.PayAmt; split.PayPlanNum = PIn.Long(table.Rows[gridMain.SelectedIndices[i]]["PayPlanNum"].ToString()); PaySplits.Insert(split); if (PrefC.GetBool(PrefName.AgingCalculatedMonthlyInsteadOfDaily)) { Ledgers.ComputeAging(patCur.Guarantor, PrefC.GetDate(PrefName.DateLastAging), false); } else { Ledgers.ComputeAging(patCur.Guarantor, DateTimeOD.Today, false); if (PrefC.GetDate(PrefName.DateLastAging) != DateTime.Today) { Prefs.UpdateString(PrefName.DateLastAging, POut.Date(DateTime.Today, false)); //Since this is always called from UI, the above line works fine to keep the prefs cache current. } } } } #endregion try { File.WriteAllText(Path.Combine(Path.GetDirectoryName(xPath), "RecurringChargeResult.txt"), recurringResultFile); } catch { } //Do nothing cause this is just for internal use. FillGrid(); labelCharged.Text = Lan.g(this, "Charged=") + success; labelFailed.Text = Lan.g(this, "Failed=") + failed; MsgBox.Show(this, "Done charging cards.\r\nIf there are any patients remaining in list, print the list and handle each one manually."); }