/// <summary>Returns true if a finance charge is added, false if one is not added</summary> private bool AddFinanceCharge(long PatNum, DateTime date, string APR, string atLeast, string ifOver, double OverallBalance, long PriProv, long adjType) { if (date > DateTime.Today && !PrefC.GetBool(PrefName.FutureTransDatesAllowed)) { MsgBox.Show(this, "Adjustments cannot be made for future dates. Finance charge was not added."); return(false); } InstallmentPlan installPlan = InstallmentPlans.GetOneForFam(PatNum); if (installPlan != null) //Patient has an installment plan so use that APR instead. { APR = installPlan.APR.ToString(); } Adjustment AdjustmentCur = new Adjustment(); AdjustmentCur.PatNum = PatNum; //AdjustmentCur.DateEntry=PIn.PDate(textDate.Text);//automatically handled AdjustmentCur.AdjDate = date; AdjustmentCur.ProcDate = date; AdjustmentCur.AdjType = adjType; AdjustmentCur.AdjNote = ""; //"Finance Charge"; AdjustmentCur.AdjAmt = Math.Round(((PIn.Double(APR) * .01d / 12d) * OverallBalance), 2); if (AdjustmentCur.AdjAmt.IsZero() || AdjustmentCur.AdjAmt < PIn.Double(ifOver)) { //Don't add the charge if it is less than FinanceChargeOnlyIfOver; if the charge is exactly equal to FinanceChargeOnlyIfOver, //the charge will be added. Ex., AdjAmt=2.00 and FinanceChargeOnlyIfOver=2.00, the charge will be added. //Unless AdjAmt=0.00, in which case don't add a $0.00 finance charge return(false); } //Add an amount that is at least the amount of FinanceChargeAtLeast AdjustmentCur.AdjAmt = Math.Max(AdjustmentCur.AdjAmt, PIn.Double(atLeast)); AdjustmentCur.ProvNum = PriProv; Adjustments.Insert(AdjustmentCur); return(true); }
private void FormProcSelect_Load(object sender, System.EventArgs e) { if (_isMultiSelect) { gridMain.SelectionMode = OpenDental.UI.GridSelectionMode.MultiExtended; } _listSelectedProcs = new List <Procedure>(); _listProcedures = Procedures.GetCompleteForPats(new List <long> { _patNumCur }); _listAdjustments = Adjustments.GetAdjustForPats(new List <long> { _patNumCur }); _listPayPlanCharges = PayPlanCharges.GetDueForPayPlans(PayPlans.GetForPats(null, _patNumCur), _patNumCur).ToList(); //Does not get charges for the future. _listPaySplits = PaySplits.GetForPats(new List <long> { _patNumCur }); //Might contain payplan payments. _listInsPayAsTotal = ClaimProcs.GetByTotForPats(new List <long> { _patNumCur }); _listClaimProcs = ClaimProcs.GetForProcs(_listProcedures.Select(x => x.ProcNum).ToList()); labelUnallocated.Visible = _doShowUnallocatedLabel; if (PrefC.GetInt(PrefName.RigorousAdjustments) == (int)RigorousAdjustments.DontEnforce) { radioIncludeAllCredits.Checked = true; } else { radioOnlyAllocatedCredits.Checked = true; } FillGrid(); }
private void butOK_Click(object sender, EventArgs e) { bool hasNegAmt = false; foreach (MultiAdjEntry mae in _listGridEntries) { if (mae.Adj == null) { continue; //Procedures } decimal remAfter = (decimal)mae.AmtRemBefore + (decimal)mae.Adj.AdjAmt; if (remAfter.IsLessThanZero()) { hasNegAmt = true; break; } } if (hasNegAmt && !MsgBox.Show(this, MsgBoxButtons.OKCancel, "Remaining amount on a procedure is negative. Continue?", "Overpaid Procedure Warning")) { return; } foreach (MultiAdjEntry row in _listGridEntries) { if (row.Adj == null) //skip over Procedure rows { continue; } Adjustments.Insert(row.Adj); } DialogResult = DialogResult.OK; }
private void FormPayPlanCredits_Load(object sender, EventArgs e) { _listPatNums = new List <long>(); _listPatNums.Add(_patCur.PatNum); _listAdjustments = Adjustments.GetAdjustForPats(_listPatNums); _listProcs = Procedures.GetCompAndTpForPats(_listPatNums); List <PayPlan> listPayPlans = PayPlans.GetForPats(_listPatNums, _patCur.PatNum); //Used to figure out how much we need to pay off procs with, also contains insurance payplans. _listPayPlanCharges = new List <PayPlanCharge>(); if (listPayPlans.Count > 0) { //get all current payplan charges for plans already on the patient, excluding the current one. _listPayPlanCharges = PayPlanCharges.GetDueForPayPlans(listPayPlans, _patCur.PatNum) //Does not get charges for the future. .Where(x => !(x.PayPlanNum == _payPlanCur.PayPlanNum && x.ChargeType == PayPlanChargeType.Credit)).ToList(); //do not get credits for current payplan } List <PaySplit> tempListPaySplits = PaySplits.GetForPats(_listPatNums).Where(x => x.UnearnedType == 0).ToList(); //Might contain payplan payments. Do not include unearned. _listPaySplits = tempListPaySplits.FindAll(x => x.PayPlanNum == 0 || listPayPlans.Exists(y => y.PayPlanNum == x.PayPlanNum)); _listPayments = Payments.GetNonSplitForPats(_listPatNums); _listInsPayAsTotal = ClaimProcs.GetByTotForPats(_listPatNums); //Claimprocs paid as total, might contain ins payplan payments. _listClaimProcs = ClaimProcs.GetForProcs(_listProcs.Select(x => x.ProcNum).ToList()); textCode.Text = Lan.g(this, "None"); FillGrid(); if (!Security.IsAuthorized(Permissions.PayPlanEdit, true)) { this.DisableForm(butCancel, checkHideUnattached, checkShowImplicit, butPrint, gridMain); } }
/// <summary>Returns true if ClaimProcAllowCreditsGreaterThanProcFee preference allows the user to add credits greater than the proc fee. Otherwise returns false </summary> private bool isClaimProcGreaterThanProcFee() { ClaimProcCreditsGreaterThanProcFee creditsGreaterPref = (ClaimProcCreditsGreaterThanProcFee)PrefC.GetInt(PrefName.ClaimProcAllowCreditsGreaterThanProcFee); if (creditsGreaterPref == ClaimProcCreditsGreaterThanProcFee.Allow) { return(true); } List <Procedure> listProcs = Procedures.GetManyProc(ClaimProcsToEdit.Select(x => x.ProcNum).ToList(), false); List <ClaimProc> listClaimProcsForPat = ClaimProcs.Refresh(PatCur.PatNum); List <PaySplit> listPaySplitForSelectedCP = PaySplits.GetPaySplitsFromProcs(ClaimProcsToEdit.Select(x => x.ProcNum).ToList()); List <Adjustment> listAdjForSelectedCP = Adjustments.GetForProcs(ClaimProcsToEdit.Select(x => x.ProcNum).ToList()); bool isCreditGreater = false; List <string> listProcDescripts = new List <string>(); for (int i = 0; i < ClaimProcsToEdit.Length; i++) { ClaimProc claimProcCur = ClaimProcsToEdit[i]; int insPayIdx = gridMain.ListGridColumns.GetIndex(Lan.g("TableClaimProc", "Ins Pay")); int writeoffIdx = gridMain.ListGridColumns.GetIndex(Lan.g("TableClaimProc", "Writeoff")); int feeAcctIdx = gridMain.ListGridColumns.GetIndex(Lan.g("TableClaimProc", "Fee")); decimal insPayAmt = (decimal)ClaimProcs.ProcInsPay(listClaimProcsForPat.FindAll(x => x.ClaimProcNum != claimProcCur.ClaimProcNum), claimProcCur.ProcNum) + PIn.Decimal(gridMain.ListGridRows[i].Cells[insPayIdx].Text); decimal writeOff = (decimal)ClaimProcs.ProcWriteoff(listClaimProcsForPat.FindAll(x => x.ClaimProcNum != claimProcCur.ClaimProcNum), claimProcCur.ProcNum) + PIn.Decimal(gridMain.ListGridRows[i].Cells[writeoffIdx].Text); decimal feeAcct = PIn.Decimal(gridMain.ListGridRows[i].Cells[feeAcctIdx].Text); decimal adj = listAdjForSelectedCP.Where(x => x.ProcNum == claimProcCur.ProcNum).Select(x => (decimal)x.AdjAmt).Sum(); decimal patPayAmt = listPaySplitForSelectedCP.Where(x => x.ProcNum == claimProcCur.ProcNum).Select(x => (decimal)x.SplitAmt).Sum(); //Any changes to this calculation should also consider FormClaimProc.IsClaimProcGreaterThanProcFee(). decimal creditRem = feeAcct - patPayAmt - insPayAmt - writeOff + adj; isCreditGreater |= (creditRem.IsLessThanZero()); if (creditRem.IsLessThanZero()) { Procedure proc = listProcs.FirstOrDefault(x => x.ProcNum == claimProcCur.ProcNum); listProcDescripts.Add((proc == null ? "" : ProcedureCodes.GetProcCode(proc.CodeNum).ProcCode) + "\t" + Lan.g(this, "Fee") + ": " + feeAcct.ToString("F") + "\t" + Lan.g(this, "Credits") + ": " + (Math.Abs(-patPayAmt - insPayAmt - writeOff + adj)).ToString("F") + "\t" + Lan.g(this, "Remaining") + ": (" + Math.Abs(creditRem).ToString("F") + ")"); } } if (!isCreditGreater) { return(true); } if (creditsGreaterPref == ClaimProcCreditsGreaterThanProcFee.Block) { MsgBoxCopyPaste msgBox = new MsgBoxCopyPaste(Lan.g(this, "Remaining amount is negative for the following procedures") + ":\r\n" + string.Join("\r\n", listProcDescripts) + "\r\n" + Lan.g(this, "Not allowed to continue.")); msgBox.Text = Lan.g(this, "Overpaid Procedure Warning"); msgBox.ShowDialog(); return(false); } if (creditsGreaterPref == ClaimProcCreditsGreaterThanProcFee.Warn) { return(MessageBox.Show(Lan.g(this, "Remaining amount is negative for the following procedures") + ":\r\n" + string.Join("\r\n", listProcDescripts.Take(10)) + "\r\n" + (listProcDescripts.Count > 10?"...\r\n":"") + Lan.g(this, "Continue?") , Lan.g(this, "Overpaid Procedure Warning"), MessageBoxButtons.OKCancel) == DialogResult.OK); } return(true); //should never get to this line, only possible if another enum value is added to allow, warn, and block }
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; } if (PIn.PInt(textAPR.Text) < 2) { if (MessageBox.Show(Lan.g(this, "The APR is much lower than normal. Do you wish to proceed?"), "", MessageBoxButtons.OKCancel) != DialogResult.OK) { return; } } //Patients.ResetAging(); //Ledgers.UpdateFinanceCharges(PIn.PDate(textDate.Text)); PatAging[] AgingList = Patients.GetAgingList(); double OverallBalance; for (int i = 0; i < AgingList.Length; i++) { 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; } if (radio60.Checked) { OverallBalance = AgingList[i].Bal_61_90 + AgingList[i].BalOver90; } if (radio90.Checked) { OverallBalance = AgingList[i].BalOver90; } if (OverallBalance > 0) { Adjustment AdjustmentCur = new Adjustment(); AdjustmentCur.PatNum = AgingList[i].PatNum; //AdjustmentCur.DateEntry=PIn.PDate(textDate.Text);//automatically handled AdjustmentCur.AdjDate = PIn.PDate(textDate.Text); AdjustmentCur.ProcDate = PIn.PDate(textDate.Text); AdjustmentCur.AdjType = DefB.Short[(int)DefCat.AdjTypes] [(int)ALPosIndices[listAdjType.SelectedIndex]].DefNum; AdjustmentCur.AdjNote = "Finance Charge"; AdjustmentCur.AdjAmt = Math.Round(((PIn.PDouble(textAPR.Text) * .01 / 12) * OverallBalance), 2); AdjustmentCur.ProvNum = AgingList[i].PriProv; Adjustments.InsertOrUpdate(AdjustmentCur, true); } } Prefs.UpdateString("FinanceChargeAPR", textAPR.Text); Prefs.UpdateInt("FinanceChargeAdjustmentType", DefB.Short[(int)DefCat.AdjTypes][(int)ALPosIndices[listAdjType.SelectedIndex]].DefNum); Prefs.UpdateString("FinanceChargeLastRun", POut.PDate(DateTime.Today, false)); DataValid.SetInvalid(InvalidTypes.Prefs); MessageBox.Show(Lan.g(this, "Finance Charges Added.")); DialogResult = DialogResult.OK; }
private void butCancel_Click(object sender, System.EventArgs e) { if (IsNew) { if (Patients.GetPat(_procCur.PatNum).DiscountPlanNum != 0) { Adjustments.DeleteForProcedure(_procCur.ProcNum); //Delete discount plan adjustment } Procedures.Delete(_procCur.ProcNum); } DialogResult = DialogResult.Cancel; }
private void FormProcBroken_FormClosing(object sender, FormClosingEventArgs e) { if (DialogResult == DialogResult.Cancel && IsNew) { if (Patients.GetPat(_procCur.PatNum).DiscountPlanNum != 0) { Adjustments.DeleteForProcedure(_procCur.ProcNum); //Delete discount plan adjustment } Procedures.Delete(_procCur.ProcNum); IsProcDeleted = true; } }
///<summary>This method converts the AccountEntry objects we get back from AccountModules.GetListUnpaidAccountCharges() to MultiAdjEntry objects. ///These are used to fill the grid and do all relevant logic in this form. This method will return a fresh list of procedures and will not show ///any existing adjustments that may have been made in this form already. Called on load and when checkShowImplicit is clicked. ///When called from checkShowImplicit any existing adjustments made will not be shown.(Ask Andrew about this functionality)</summary> private List <MultiAdjEntry> FillListGridEntries(CreditCalcType calc) { List <MultiAdjEntry> retVal = new List <MultiAdjEntry>(); #region Get required data List <Procedure> listProcedures = Procedures.GetCompleteForPats(new List <long> { _patCur.PatNum }); //Does not get charges for the future. List <PaySplit> listPaySplits = PaySplits.GetForPats(new List <long> { _patCur.PatNum }).Where(x => x.UnearnedType == 0).ToList(); List <Adjustment> listAdjustments = Adjustments.GetAdjustForPats(new List <long> { _patCur.PatNum }); //Might contain payplan payments. Do not include unearned. List <PayPlanCharge> listPayPlanCharges = PayPlanCharges.GetDueForPayPlans(PayPlans.GetForPats(null, _patCur.PatNum), _patCur.PatNum).ToList(); List <ClaimProc> listInsPayAsTotal = ClaimProcs.GetByTotForPats(new List <long> { _patCur.PatNum }); List <ClaimProc> listClaimProcs = ClaimProcs.GetForProcs(listProcedures.Select(x => x.ProcNum).ToList()); #endregion List <AccountEntry> listAccountCharges = AccountModules.GetListUnpaidAccountCharges(listProcedures, listAdjustments , listPaySplits, listClaimProcs, listPayPlanCharges, listInsPayAsTotal, calc, new List <PaySplit>()); List <AccountEntry> listAccountChargesIncludeAll = null; if (calc == CreditCalcType.ExcludeAll) { //We need to get all credits so that our AmtRemBefore can reflect what has truly been allocated to the procedure. listAccountChargesIncludeAll = AccountModules.GetListUnpaidAccountCharges(listProcedures, listAdjustments , listPaySplits, listClaimProcs, listPayPlanCharges, listInsPayAsTotal, CreditCalcType.IncludeAll, new List <PaySplit>()); } MultiAdjEntry multiEntry = null; foreach (AccountEntry entry in listAccountCharges) { //We only want AccountEntries that are completed procedures. if (entry.GetType() != typeof(ProcExtended)) { continue; } ProcExtended procEntry = (ProcExtended)entry.Tag; if ((_listSelectedProcs != null && _listSelectedProcs.Any(x => x.ProcNum == procEntry.Proc.ProcNum)) || //Allow selected procs to show if paid off entry.AmountEnd != 0) //All unpaid procedures should always show up per Nathan { double amtRemBefore = (double)(listAccountChargesIncludeAll?.FirstOrDefault(x => x.Tag.GetType() == typeof(ProcExtended) && ((ProcExtended)x.Tag).Proc.ProcNum == procEntry.Proc.ProcNum) ?? entry).AmountStart; multiEntry = new MultiAdjEntry(procEntry.Proc, (double)entry.AmountStart, (double)entry.AmountEnd, amtRemBefore); retVal.Add(multiEntry); } } OrderListGridEntries(); return(retVal); }
private void FormAdjustmentPicker_Load(object sender, EventArgs e) { if (_isUnattachedMode) { checkUnattached.Checked = true; checkUnattached.Enabled = false; } if (_listAdjustments == null) { _listAdjustments = Adjustments.Refresh(_patNum).ToList(); } FillGrid(); }
private void AddFinanceCharge(long PatNum, DateTime date, string APR, double OverallBalance, long PriProv) { Adjustment AdjustmentCur = new Adjustment(); AdjustmentCur.PatNum = PatNum; //AdjustmentCur.DateEntry=PIn.PDate(textDate.Text);//automatically handled AdjustmentCur.AdjDate = date; AdjustmentCur.ProcDate = date; AdjustmentCur.AdjType = PrefC.GetLong(PrefName.FinanceChargeAdjustmentType); AdjustmentCur.AdjNote = ""; //"Finance Charge"; AdjustmentCur.AdjAmt = Math.Round(((PIn.Double(APR) * .01d / 12d) * OverallBalance), 2); AdjustmentCur.ProvNum = PriProv; Adjustments.Insert(AdjustmentCur); }
private void butOK_Click(object sender, EventArgs e) { if (_listGridEntries.Any(x => x.RemAfter.IsLessThan(0)) && !MsgBox.Show(this, MsgBoxButtons.OKCancel, "Remaining amount on a procedure is negative. Continue?", "Overpaid Procedure Warning")) { return; } foreach (MultiAdjEntry row in _listGridEntries) { if (row.Adj == null) //skip over Procedure rows { continue; } Adjustments.Insert(row.Adj); } DialogResult = DialogResult.OK; }
///<summary>Returns true if InsPayNoWriteoffMoreThanProc preference is turned on and the sum of write off amount is greater than the proc fee. ///Otherwise returns false </summary> private bool IsWriteOffGreaterThanProcFee() { if (!PrefC.GetBool(PrefName.InsPayNoWriteoffMoreThanProc)) { return(false); //InsPayNoWriteoffMoreThanProc preference is off. No need to check. } List <ClaimProc> listClaimProcsForPat = ClaimProcs.Refresh(PatCur.PatNum); List <Adjustment> listAdjustmentsForPat = Adjustments.GetForProcs(ClaimProcsToEdit.Select(x => x.ProcNum).Where(x => x != 0).ToList()); bool isWriteoffGreater = false; List <string> listProcDescripts = new List <string>(); for (int i = 0; i < ClaimProcsToEdit.Length; i++) { ClaimProc claimProcCur = ClaimProcsToEdit[i]; //Fetch all adjustments for the given procedure. List <Adjustment> listClaimProcAdjustments = listAdjustmentsForPat.Where(x => x.ProcNum == claimProcCur.ProcNum).ToList(); int writeoffIdx = gridMain.ListGridColumns.GetIndex(Lan.g("TableClaimProc", "Writeoff")); int feeAcctIdx = gridMain.ListGridColumns.GetIndex(Lan.g("TableClaimProc", "Fee")); decimal writeOff = (decimal)ClaimProcs.ProcWriteoff(listClaimProcsForPat.FindAll(x => x.ClaimProcNum != claimProcCur.ClaimProcNum), claimProcCur.ProcNum) + PIn.Decimal(gridMain.ListGridRows[i].Cells[writeoffIdx].Text); decimal feeAcct = PIn.Decimal(gridMain.ListGridRows[i].Cells[feeAcctIdx].Text); decimal adjAcct = listClaimProcAdjustments.Sum(x => (decimal)x.AdjAmt); //Any changes to this calculation should also consider FormClaimProc.IsWriteOffGreaterThanProc(). decimal writeoffRem = feeAcct - writeOff + adjAcct; isWriteoffGreater |= (writeoffRem.IsLessThanZero() && writeOff.IsGreaterThanZero()); if (writeoffRem.IsLessThanZero() && writeOff.IsGreaterThanZero()) { Procedure proc = Procedures.GetProcFromList(ProcList, claimProcCur.ProcNum); //will return a new procedure if none found. listProcDescripts.Add((proc == null ? "" : ProcedureCodes.GetProcCode(proc.CodeNum).ProcCode) + "\t" + Lan.g(this, "Fee") + ": " + feeAcct.ToString("F") + "\t" + Lan.g(this, "Adjustments") + ": " + adjAcct.ToString("F") + "\t" + Lan.g(this, "Write-off") + ": " + (Math.Abs(-writeOff)).ToString("F") + "\t" + Lan.g(this, "Remaining") + ": (" + Math.Abs(writeoffRem).ToString("F") + ")"); } } if (isWriteoffGreater) { MsgBoxCopyPaste msgBox = new MsgBoxCopyPaste(Lan.g(this, "Write-off amount is greater than the adjusted procedure fee for the following " + "procedure(s)") + ":\r\n" + string.Join("\r\n", listProcDescripts) + "\r\n" + Lan.g(this, "Not allowed to continue.")); msgBox.Text = Lan.g(this, "Excessive Write-off"); msgBox.ShowDialog(); return(true); } return(false); }
private void AddBillingCharge(long PatNum, DateTime date, string BillingChargeAmount, long PriProv) { if (date > DateTime.Today && !PrefC.GetBool(PrefName.FutureTransDatesAllowed)) { MsgBox.Show(this, "Adjustments cannot be made for future dates"); return; } Adjustment AdjustmentCur = new Adjustment(); AdjustmentCur.PatNum = PatNum; //AdjustmentCur.DateEntry=PIn.PDate(textDate.Text);//automatically handled AdjustmentCur.AdjDate = date; AdjustmentCur.ProcDate = date; AdjustmentCur.AdjType = PrefC.GetLong(PrefName.BillingChargeAdjustmentType); AdjustmentCur.AdjNote = ""; //"Billing Charge"; AdjustmentCur.AdjAmt = PIn.Double(BillingChargeAmount); AdjustmentCur.ProvNum = PriProv; Adjustments.Insert(AdjustmentCur); }
private void FormAdjustSelect_Load(object sender, EventArgs e) { List <Adjustment> listAdjusts = Adjustments.GetAdjustForPats(new List <long>() { PatNumCur }).FindAll(x => x.ProcNum == 0); //Get all unallocated adjustments for current pat. foreach (Adjustment adjust in listAdjusts) { _listAdjusts.Add(new AccountEntry(adjust)); } _listSplitsForAdjusts = PaySplits.GetForAdjustments(listAdjusts.Select(x => x.AdjNum).ToList()); foreach (AccountEntry entry in _listAdjusts) { //Figure out how much each adjustment has left, not counting this payment. entry.AmountStart -= (decimal)Adjustments.GetAmtAllocated(entry.PriKey, PayNumCur, _listSplitsForAdjusts.FindAll(x => x.AdjNum == entry.PriKey)); //Reduce adjustments based on current payment's splits as well (this is in-memory list, could be new, could be modified) but not the current split entry.AmountStart -= (decimal)Adjustments.GetAmtAllocated(entry.PriKey, 0, ListSplitsForPayment.FindAll(x => x.AdjNum == entry.PriKey && x != PaySplitCur)); } FillGrid(); }
private void butPreviousProc_Click(object sender, EventArgs e) { FormProcSelect FormPS = new FormProcSelect(_patCur.PatNum, false); if (FormPS.ShowDialog() != DialogResult.OK) { return; } //isMultiSelect is set to false so should only ever be one procedure, constructing in a way to handle multiple in case we ever want to change //isMultiSelect to be true. foreach (Procedure proc in FormPS.ListSelectedProcs) { //Use our list of ProcedureCodes so irrelevant codes result in a new ProcedureCode with blank values. ProcedureCode procCode = ProcedureCodes.GetProcCode(proc.CodeNum, _listPrePaySupportCodes); //Didn't exist in our list of ProcedureCodes, tell user it won't be added. if (procCode.CodeNum == 0) { //Did not translate because HQ only. MsgBox.Show(this, "Selected procedure cannot be used with the Prepayment Tool."); continue; } ProcedureCharge procCharge = new ProcedureCharge(procCode, proc.ProcFee); Adjustment taxAdjustment = Adjustments.GetSalesTaxForProc(proc.ProcNum); if (taxAdjustment != null) { procCharge.EstTax = taxAdjustment.AdjAmt; procCharge.HasTaxAdjustment = true; } else { procCharge.EstTax = 0; } procCharge.Calc(); _listPreviouslyCompProcedureCharges.Add(procCharge); _listCompletedProcs.Add(proc); } //This calls FillGridCompletedProcs() FillGridPrepayment(); }
private void butOK_Click(object sender, System.EventArgs e) { bool isDiscountPlanAdj = (Defs.GetValue(DefCat.AdjTypes, _adjustmentCur.AdjType) == "dp"); if (textAdjDate.errorProvider1.GetError(textAdjDate) != "" || textProcDate.errorProvider1.GetError(textProcDate) != "" || textAmount.errorProvider1.GetError(textAmount) != "") { MsgBox.Show(this, "Please fix data entry errors first."); return; } if (PIn.Date(textAdjDate.Text).Date > DateTime.Today.Date && !PrefC.GetBool(PrefName.FutureTransDatesAllowed)) { MsgBox.Show(this, "Adjustment date can not be in the future."); return; } if (textAmount.Text == "") { MessageBox.Show(Lan.g(this, "Please enter an amount.")); return; } if (!isDiscountPlanAdj && listTypeNeg.SelectedIndex == -1 && listTypePos.SelectedIndex == -1) { MsgBox.Show(this, "Please select a type first."); return; } if (IsNew && AvaTax.IsEnabled() && listTypePos.SelectedIndex > -1 && (_listAdjPosCats[listTypePos.SelectedIndex].DefNum == AvaTax.SalesTaxAdjType || _listAdjPosCats[listTypePos.SelectedIndex].DefNum == AvaTax.SalesTaxReturnAdjType) && !Security.IsAuthorized(Permissions.SalesTaxAdjEdit)) { return; } if (PrefC.GetInt(PrefName.RigorousAdjustments) == 0 && _adjustmentCur.ProcNum == 0) { MsgBox.Show(this, "You must attach a procedure to the adjustment."); return; } if (_adjRemAmt < 0) { if (!MsgBox.Show(this, MsgBoxButtons.OKCancel, "Remaining amount is negative. Continue?", "Overpaid Procedure Warning")) { return; } } bool changeAdjSplit = false; List <PaySplit> listPaySplitsForAdjust = new List <PaySplit>(); if (IsNew) { //prevents backdating of initial adjustment if (!Security.IsAuthorized(Permissions.AdjustmentCreate, PIn.Date(textAdjDate.Text), true)) //Give message later. { if (!_checkZeroAmount) //Let user create as long as Amount is zero and has edit zero permissions. This was checked on load. { MessageBox.Show(Lans.g("Security", "Not authorized for") + "\r\n" + GroupPermissions.GetDesc(Permissions.AdjustmentCreate)); return; } } } else { //Editing an old entry will already be blocked if the date was too old, and user will not be able to click OK button //This catches it if user changed the date to be older. if (!Security.IsAuthorized(Permissions.AdjustmentEdit, PIn.Date(textAdjDate.Text))) { return; } if (_adjustmentCur.ProvNum != comboProv.GetSelectedProvNum()) { listPaySplitsForAdjust = PaySplits.GetForAdjustments(new List <long>() { _adjustmentCur.AdjNum }); foreach (PaySplit paySplit in listPaySplitsForAdjust) { if (!Security.IsAuthorized(Permissions.PaymentEdit, Payments.GetPayment(paySplit.PayNum).PayDate)) { return; } if (comboProv.GetSelectedProvNum() != paySplit.ProvNum && PrefC.GetInt(PrefName.RigorousAccounting) == (int)RigorousAdjustments.EnforceFully) { changeAdjSplit = true; break; } } if (changeAdjSplit && !MsgBox.Show(this, MsgBoxButtons.OKCancel, "The provider for the associated payment splits will be changed to match the provider on the " + "adjustment.")) { return; } } } //DateEntry not allowed to change DateTime datePreviousChange = _adjustmentCur.SecDateTEdit; _adjustmentCur.AdjDate = PIn.Date(textAdjDate.Text); _adjustmentCur.ProcDate = PIn.Date(textProcDate.Text); _adjustmentCur.ProvNum = comboProv.GetSelectedProvNum(); _adjustmentCur.ClinicNum = comboClinic.SelectedClinicNum; if (listTypePos.SelectedIndex != -1) { _adjustmentCur.AdjType = _listAdjPosCats[listTypePos.SelectedIndex].DefNum; _adjustmentCur.AdjAmt = PIn.Double(textAmount.Text); } if (listTypeNeg.SelectedIndex != -1) { _adjustmentCur.AdjType = _listAdjNegCats[listTypeNeg.SelectedIndex].DefNum; _adjustmentCur.AdjAmt = -PIn.Double(textAmount.Text); } if (isDiscountPlanAdj) { //AdjustmentCur.AdjType is already set to a "discount plan" adj type. _adjustmentCur.AdjAmt = -PIn.Double(textAmount.Text); } if (_checkZeroAmount && _adjustmentCur.AdjAmt != 0) { MsgBox.Show(this, "Amount has to be 0.00 due to security permission."); return; } _adjustmentCur.AdjNote = textNote.Text; try{ if (IsNew) { Adjustments.Insert(_adjustmentCur); SecurityLogs.MakeLogEntry(Permissions.AdjustmentCreate, _adjustmentCur.PatNum, _patCur.GetNameLF() + ", " + _adjustmentCur.AdjAmt.ToString("c")); TsiTransLogs.CheckAndInsertLogsIfAdjTypeExcluded(_adjustmentCur, _isTsiAdj); } else { Adjustments.Update(_adjustmentCur); SecurityLogs.MakeLogEntry(Permissions.AdjustmentEdit, _adjustmentCur.PatNum, _patCur.GetNameLF() + ", " + _adjustmentCur.AdjAmt.ToString("c"), 0 , datePreviousChange); } } catch (Exception ex) { //even though it doesn't currently throw any exceptions MessageBox.Show(ex.Message); return; } if (changeAdjSplit) { PaySplits.UpdateProvForAdjust(_adjustmentCur, listPaySplitsForAdjust); } DialogResult = DialogResult.OK; }
private void FillProcedure() { if (_adjustmentCur.ProcNum == 0) { textProcDate2.Text = ""; textProcProv.Text = ""; textProcTooth.Text = ""; textProcDescription.Text = ""; textProcFee.Text = ""; textProcWriteoff.Text = ""; textProcInsPaid.Text = ""; textProcInsEst.Text = ""; textProcAdj.Text = ""; textProcPatPaid.Text = ""; textProcAdjCur.Text = ""; labelProcRemain.Text = ""; _adjRemAmt = 0; return; } Procedure procCur = Procedures.GetOneProc(_adjustmentCur.ProcNum, false); List <ClaimProc> listClaimProcs = ClaimProcs.Refresh(procCur.PatNum); List <Adjustment> listAdjustments = Adjustments.Refresh(procCur.PatNum) .Where(x => x.ProcNum == procCur.ProcNum && x.AdjNum != _adjustmentCur.AdjNum).ToList(); textProcDate.Text = procCur.ProcDate.ToShortDateString(); textProcDate2.Text = procCur.ProcDate.ToShortDateString(); textProcProv.Text = Providers.GetAbbr(procCur.ProvNum); textProcTooth.Text = Tooth.ToInternat(procCur.ToothNum); textProcDescription.Text = ProcedureCodes.GetProcCode(procCur.CodeNum).Descript; double procWO = -ClaimProcs.ProcWriteoff(listClaimProcs, procCur.ProcNum); double procInsPaid = -ClaimProcs.ProcInsPay(listClaimProcs, procCur.ProcNum); double procInsEst = -ClaimProcs.ProcEstNotReceived(listClaimProcs, procCur.ProcNum); double procAdj = listAdjustments.Sum(x => x.AdjAmt); double procPatPaid = -PaySplits.GetTotForProc(procCur); textProcFee.Text = procCur.ProcFeeTotal.ToString("F"); textProcWriteoff.Text = procWO == 0?"":procWO.ToString("F"); textProcInsPaid.Text = procInsPaid == 0?"":procInsPaid.ToString("F"); textProcInsEst.Text = procInsEst == 0?"":procInsEst.ToString("F"); textProcAdj.Text = procAdj == 0?"":procAdj.ToString("F"); textProcPatPaid.Text = procPatPaid == 0?"":procPatPaid.ToString("F"); //Intelligently sum the values above based on statuses instead of blindly adding all of the values together. //The remaining amount is typically called the "patient portion" so utilze the centralized method that gets the patient portion. decimal patPort = ClaimProcs.GetPatPortion(procCur, listClaimProcs, listAdjustments); double procAdjCur = 0; if (textAmount.errorProvider1.GetError(textAmount) == "") { if (listTypePos.SelectedIndex > -1) //pos { procAdjCur = PIn.Double(textAmount.Text); } else if (listTypeNeg.SelectedIndex > -1 || Defs.GetValue(DefCat.AdjTypes, _adjustmentCur.AdjType) == "dp") //neg or discount plan { procAdjCur = -PIn.Double(textAmount.Text); } } textProcAdjCur.Text = procAdjCur == 0?"":procAdjCur.ToString("F"); //Add the current adjustment amount to the patient portion which will give the newly calculated remaining amount. _adjRemAmt = (decimal)procAdjCur + (decimal)procPatPaid + patPort; labelProcRemain.Text = _adjRemAmt.ToString("c"); }
private void butOK_Click(object sender, System.EventArgs e) { if (textAdjDate.errorProvider1.GetError(textAdjDate) != "" || textProcDate.errorProvider1.GetError(textProcDate) != "" || textAmount.errorProvider1.GetError(textAmount) != "" ) { MsgBox.Show(this, "Please fix data entry errors first."); return; } if (textAmount.Text == "") { MessageBox.Show(Lan.g(this, "Please enter an amount.")); return; } if (listTypeNeg.SelectedIndex == -1 && listTypePos.SelectedIndex == -1) { MsgBox.Show(this, "Please select a type first."); return; } //DateEntry not allowed to change AdjustmentCur.AdjDate = PIn.PDate(textAdjDate.Text); AdjustmentCur.ProcDate = PIn.PDate(textProcDate.Text); if (listProvider.SelectedIndex == -1) { AdjustmentCur.ProvNum = PatCur.PriProv; } else { AdjustmentCur.ProvNum = Providers.List[this.listProvider.SelectedIndex].ProvNum; } if (listTypePos.SelectedIndex != -1) { AdjustmentCur.AdjType = DefB.Short[(int)DefCat.AdjTypes][(int)PosIndex[listTypePos.SelectedIndex]].DefNum; } if (listTypeNeg.SelectedIndex != -1) { AdjustmentCur.AdjType = DefB.Short[(int)DefCat.AdjTypes][(int)NegIndex[listTypeNeg.SelectedIndex]].DefNum; } if (DefB.GetValue(DefCat.AdjTypes, AdjustmentCur.AdjType) == "+") //pos { AdjustmentCur.AdjAmt = PIn.PDouble(textAmount.Text); } else //neg { AdjustmentCur.AdjAmt = -PIn.PDouble(textAmount.Text); } AdjustmentCur.AdjNote = textNote.Text; try{ Adjustments.InsertOrUpdate(AdjustmentCur, IsNew); } catch (Exception ex) { //even though it doesn't currently throw any exceptions MessageBox.Show(ex.Message); return; } if (IsNew) { SecurityLogs.MakeLogEntry(Permissions.AdjustmentCreate, AdjustmentCur.PatNum, Patients.GetLim(AdjustmentCur.PatNum).GetNameLF() + ", " + AdjustmentCur.AdjAmt.ToString("c")); } else { SecurityLogs.MakeLogEntry(Permissions.AdjustmentEdit, AdjustmentCur.PatNum, Patients.GetLim(AdjustmentCur.PatNum).GetNameLF() + ", " + AdjustmentCur.AdjAmt.ToString("c")); } 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 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 int ReallocateAll() { string command = "SELECT DefNum FROM definition WHERE Category=1 AND ItemName='Reallocation'"; DataTable table = General.GetTable(command); int defnum; if (table.Rows.Count == 0) { Def def = new Def(); def.Category = DefCat.AdjTypes; def.ItemName = "Reallocation"; def.ItemValue = "+"; def.ItemOrder = DefB.Long[(int)DefCat.AdjTypes].Length; Defs.Insert(def); defnum = def.DefNum; DataValid.SetInvalid(InvalidTypes.Defs); } else { defnum = PIn.PInt(table.Rows[0][0].ToString()); } //find all families where someone has a negative balance. command = "SELECT DISTINCT Guarantor FROM patient WHERE EstBalance < 0"; DataTable tableGuarantors = General.GetTable(command); int changed = 0; //bool result; double[] familyBals; DataTable tablePatients; Adjustment adj; Double delta; for (int i = 0; i < tableGuarantors.Rows.Count; i++) { command = "SELECT PatNum,EstBalance FROM patient WHERE Guarantor=" + tableGuarantors.Rows[i][0].ToString(); tablePatients = General.GetTable(command); if (tablePatients.Rows.Count == 1) //impossible to allocate { continue; } familyBals = new double[tablePatients.Rows.Count]; for (int p = 0; p < tablePatients.Rows.Count; p++) { familyBals[p] = PIn.PDouble(tablePatients.Rows[p]["EstBalance"].ToString()); } for (int p = 0; p < familyBals.Length; p++) { if (familyBals[p] < 0) //if a negative bal found { for (int j = 0; j < familyBals.Length; j++) //look for a positive bal to adjust { if (j == p) { continue; //skip same patient } if (familyBals[j] <= 0) { continue; //no neg bal } if (familyBals[j] >= -familyBals[p]) //if sufficient bal to zero out the neg { familyBals[j] += familyBals[p]; //because p is neg familyBals[p] = 0; break; //quit looking for a pos bal to adj. } else //only enough bal to reduce the negative, not eliminate it { familyBals[p] += familyBals[j]; //because p is neg familyBals[j] = 0; } } } } //now, save any changes to db: for (int p = 0; p < familyBals.Length; p++) { if (familyBals[p] == PIn.PDouble(tablePatients.Rows[p]["EstBalance"].ToString())) { continue; //same, so no change to db } adj = new Adjustment(); adj.PatNum = PIn.PInt(tablePatients.Rows[p]["PatNum"].ToString()); adj.AdjDate = DateTime.Today; adj.AdjNote = "Automatic"; adj.AdjType = defnum; adj.ProcDate = DateTime.Today; adj.ProvNum = PrefB.GetInt("PracticeDefaultProv"); delta = familyBals[p] - PIn.PDouble(tablePatients.Rows[p]["EstBalance"].ToString()); //works whether pos or neg adj.AdjAmt = delta; Adjustments.InsertOrUpdate(adj, true); command = "UPDATE patient SET EstBalance=EstBalance+'" + POut.PDouble(delta) + "' WHERE PatNum=" + tablePatients.Rows[p]["PatNum"].ToString(); General.NonQ(command); changed++; } } return(changed); }