///<summary>Creates and inserts a payment similar to the load logic for the income transfer manager.</summary>
        private Payment CreatePaymentTransferHelper(Patient pat)
        {
            Payment payCur = new Payment();

            payCur.ClinicNum = 0;
            if (PrefC.HasClinicsEnabled)             //if clinics aren't enabled default to 0
            {
                payCur.ClinicNum = Clinics.ClinicNum;
                if ((PayClinicSetting)PrefC.GetInt(PrefName.PaymentClinicSetting) == PayClinicSetting.PatientDefaultClinic ||
                    (Clinics.ClinicNum == 0 && (PayClinicSetting)PrefC.GetInt(PrefName.PaymentClinicSetting) == PayClinicSetting.SelectedExceptHQ))
                {
                    payCur.ClinicNum = pat.ClinicNum;
                }
            }
            payCur.DateEntry     = DateTime.Now;
            payCur.PatNum        = pat.PatNum;
            payCur.PayDate       = datePicker.Value;
            payCur.PaymentSource = CreditCardSource.None;
            payCur.ProcessStatus = ProcessStat.OfficeProcessed;
            payCur.PayType       = 0;                       //Income transfer (will always be income transfer).
            payCur.PayAmt        = 0;                       //Income transfer payment.
            payCur.PayNum        = Payments.Insert(payCur); //Insert and get the payment PayNum which is used with linking the splits.
            SecurityLogs.MakeLogEntry(Permissions.PaymentCreate, pat.PatNum, $"{Patients.GetLim(pat.PatNum).GetNameLF()}, created by Family Balancer tool.");
            return(payCur);
        }
Exemple #2
0
        /// <summary>Only used to void or refund transactions from PayConnectPortal. Creates new cloned payment and paysplits for the refund or void.
        /// Returns true if the transaction was successful, otherwise false.</summary
        public static bool VoidOrRefundPayConnectPortalTransaction(PayConnectResponseWeb pcResponseWeb, Payment payment, PayConnectService.transType transType, string refNum, decimal amount)
        {
            if (!transType.In(PayConnectService.transType.RETURN, PayConnectService.transType.VOID))
            {
                return(false);
            }
            List <PaySplit> listPaySplits = PaySplits.GetForPayment(payment.PayNum);

            PayConnectService.creditCardRequest _payConnectRequest = new PayConnectService.creditCardRequest();
            PayConnectResponse response   = null;
            string             receiptStr = "";

            _payConnectRequest.TransType = transType;
            _payConnectRequest.RefNumber = refNum;
            _payConnectRequest.Amount    = amount;
            PayConnectService.transResponse transResponse = PayConnect.ProcessCreditCard(_payConnectRequest, payment.ClinicNum, x => MsgBox.Show(x));
            response   = new PayConnectResponse(transResponse, _payConnectRequest);
            receiptStr = PayConnect.BuildReceiptString(_payConnectRequest, transResponse, null, payment.ClinicNum);
            if (response == null || response.StatusCode != "0")         //error in transaction
            {
                return(false);
            }
            //Record a new payment for the voided transaction
            Payment clonePayment = payment.Clone();

            clonePayment.PayAmt *= -1;           //The negated amount of the original payment
            clonePayment.PayDate = DateTime.Now;
            clonePayment.Receipt = receiptStr;
            clonePayment.PayNote = Lan.g("PayConnectL", "Transaction Type") + ": " + Enum.GetName(typeof(PayConnectService.transType), transType)
                                   + Environment.NewLine + Lan.g("PayConnectL", "Status") + ": " + response.Description + Environment.NewLine
                                   + Lan.g("PayConnectL", "Amount") + ": " + clonePayment.PayAmt + Environment.NewLine
                                   + Lan.g("PayConnectL", "Auth Code") + ": " + response.AuthCode + Environment.NewLine
                                   + Lan.g("PayConnectL", "Ref Number") + ": " + response.RefNumber;
            clonePayment.PaymentSource = pcResponseWeb.CCSource;
            clonePayment.ProcessStatus = ProcessStat.OfficeProcessed;
            clonePayment.PayNum        = Payments.Insert(clonePayment);
            List <PaySplit> listClonedPaySplits = new List <PaySplit>();

            foreach (PaySplit paySplit in listPaySplits)
            {
                PaySplit copy = paySplit.Copy();
                copy.SplitAmt *= -1;
                copy.PayNum    = clonePayment.PayNum;
                copy.DatePay   = clonePayment.PayDate;
                listClonedPaySplits.Add(copy);
            }
            PaySplits.InsertMany(listClonedPaySplits);
            PayConnectResponseWeb newPCResponseWeb = new PayConnectResponseWeb()
            {
                PatNum            = payment.PatNum,
                PayNum            = clonePayment.PayNum,
                CCSource          = pcResponseWeb.CCSource,
                Amount            = clonePayment.PayAmt,
                PayNote           = Lan.g("PayConnectL", clonePayment.PayNote + Environment.NewLine + "From within Open Dental Proper."),
                ProcessingStatus  = PayConnectWebStatus.Completed,
                DateTimeEntry     = DateTime.Now,
                DateTimeCompleted = DateTime.Now,
                IsTokenSaved      = false,
                RefNumber         = transResponse.RefNumber,
                TransType         = transType,
                PaymentToken      = pcResponseWeb.PaymentToken,
            };

            PayConnectResponseWebs.Insert(newPCResponseWeb);
            SecurityLogs.MakeLogEntry(Permissions.PaymentCreate, clonePayment.PatNum,
                                      Patients.GetLim(clonePayment.PatNum).GetNameLF() + ", " + clonePayment.PayAmt.ToString("c"));
            return(true);
        }
Exemple #3
0
        ///<summary>Sets given appt.AptStatus to broken.
        ///Provide procCode that should be charted, can be null but will not chart a broken procedure.
        ///Also considers various broken procedure based prefs.
        ///Makes its own securitylog entries.</summary>
        public static void BreakApptHelper(Appointment appt, Patient pat, ProcedureCode procCode)
        {
            //suppressHistory is true due to below logic creating a log with a specific HistAppointmentAction instead of the generic changed.
            DateTime datePrevious    = appt.DateTStamp;
            bool     suppressHistory = false;

            if (procCode != null)
            {
                suppressHistory = (procCode.ProcCode.In("D9986", "D9987"));
            }
            Appointments.SetAptStatus(appt, ApptStatus.Broken, suppressHistory); //Appointments S-Class handles Signalods
            if (appt.AptStatus != ApptStatus.Complete)                           //seperate log entry for completed appointments.
            {
                SecurityLogs.MakeLogEntry(Permissions.AppointmentEdit, pat.PatNum,
                                          appt.ProcDescript + ", " + appt.AptDateTime.ToString()
                                          + ", Broken from the Appts module.", appt.AptNum, datePrevious);
            }
            else
            {
                SecurityLogs.MakeLogEntry(Permissions.AppointmentCompleteEdit, pat.PatNum,
                                          appt.ProcDescript + ", " + appt.AptDateTime.ToString()
                                          + ", Broken from the Appts module.", appt.AptNum, datePrevious);
            }
            #region HL7
            //If there is an existing HL7 def enabled, send a SIU message if there is an outbound SIU message defined
            if (HL7Defs.IsExistingHL7Enabled())
            {
                //S15 - Appt Cancellation event
                MessageHL7 messageHL7 = MessageConstructor.GenerateSIU(pat, Patients.GetPat(pat.Guarantor), EventTypeHL7.S15, appt);
                //Will be null if there is no outbound SIU message defined, so do nothing
                if (messageHL7 != null)
                {
                    HL7Msg hl7Msg = new HL7Msg();
                    hl7Msg.AptNum    = appt.AptNum;
                    hl7Msg.HL7Status = HL7MessageStatus.OutPending;                  //it will be marked outSent by the HL7 service.
                    hl7Msg.MsgText   = messageHL7.ToString();
                    hl7Msg.PatNum    = pat.PatNum;
                    HL7Msgs.Insert(hl7Msg);
#if DEBUG
                    MessageBox.Show("Appointments", messageHL7.ToString());
#endif
                }
            }
            #endregion
            List <Procedure> listProcedures = new List <Procedure>();
            //splits should only exist on procs if they are using tp pre-payments
            List <PaySplit> listSplitsForApptProcs = new List <PaySplit>();
            bool            isNonRefundable        = false;
            double          brokenProcAmount       = 0;
            Procedure       brokenProcedure        = new Procedure();
            bool            wasBrokenProcDeleted   = false;
            if (PrefC.GetYN(PrefName.PrePayAllowedForTpProcs))
            {
                listProcedures = Procedures.GetProcsForSingle(appt.AptNum, false);
                if (listProcedures.Count > 0)
                {
                    listSplitsForApptProcs = PaySplits.GetPaySplitsFromProcs(listProcedures.Select(x => x.ProcNum).ToList());
                }
            }
            #region Charting the proc
            if (procCode != null)
            {
                switch (procCode.ProcCode)
                {
                case "D9986":                        //Missed
                    HistAppointments.CreateHistoryEntry(appt.AptNum, HistAppointmentAction.Missed);
                    break;

                case "D9987":                        //Cancelled
                    HistAppointments.CreateHistoryEntry(appt.AptNum, HistAppointmentAction.Cancelled);
                    break;
                }
                brokenProcedure.PatNum       = pat.PatNum;
                brokenProcedure.ProvNum      = (procCode.ProvNumDefault > 0 ? procCode.ProvNumDefault : appt.ProvNum);
                brokenProcedure.CodeNum      = procCode.CodeNum;
                brokenProcedure.ProcDate     = DateTime.Today;
                brokenProcedure.DateEntryC   = DateTime.Now;
                brokenProcedure.ProcStatus   = ProcStat.C;
                brokenProcedure.ClinicNum    = appt.ClinicNum;
                brokenProcedure.UserNum      = Security.CurUser.UserNum;
                brokenProcedure.Note         = Lans.g("AppointmentEdit", "Appt BROKEN for") + " " + appt.ProcDescript + "  " + appt.AptDateTime.ToString();
                brokenProcedure.PlaceService = (PlaceOfService)PrefC.GetInt(PrefName.DefaultProcedurePlaceService);              //Default proc place of service for the Practice is used.
                List <InsSub>  listInsSubs    = InsSubs.RefreshForFam(Patients.GetFamily(pat.PatNum));
                List <InsPlan> listInsPlans   = InsPlans.RefreshForSubList(listInsSubs);
                List <PatPlan> listPatPlans   = PatPlans.Refresh(pat.PatNum);
                InsPlan        insPlanPrimary = null;
                InsSub         insSubPrimary  = null;
                if (listPatPlans.Count > 0)
                {
                    insSubPrimary  = InsSubs.GetSub(listPatPlans[0].InsSubNum, listInsSubs);
                    insPlanPrimary = InsPlans.GetPlan(insSubPrimary.PlanNum, listInsPlans);
                }
                double procFee;
                long   feeSch;
                if (insPlanPrimary == null || procCode.NoBillIns)
                {
                    feeSch = FeeScheds.GetFeeSched(0, pat.FeeSched, brokenProcedure.ProvNum);
                }
                else                  //Only take into account the patient's insurance fee schedule if the D9986 procedure is not marked as NoBillIns
                {
                    feeSch = FeeScheds.GetFeeSched(insPlanPrimary.FeeSched, pat.FeeSched, brokenProcedure.ProvNum);
                }
                procFee = Fees.GetAmount0(brokenProcedure.CodeNum, feeSch, brokenProcedure.ClinicNum, brokenProcedure.ProvNum);
                if (insPlanPrimary != null && insPlanPrimary.PlanType == "p" && !insPlanPrimary.IsMedical)         //PPO
                {
                    double provFee = Fees.GetAmount0(brokenProcedure.CodeNum, Providers.GetProv(brokenProcedure.ProvNum).FeeSched, brokenProcedure.ClinicNum,
                                                     brokenProcedure.ProvNum);
                    brokenProcedure.ProcFee = Math.Max(provFee, procFee);
                }
                else if (listSplitsForApptProcs.Count > 0 && PrefC.GetBool(PrefName.TpPrePayIsNonRefundable) && procCode.ProcCode == "D9986")
                {
                    //if there are pre-payments, non-refundable pre-payments is turned on, and the broken appointment is a missed code then auto-fill
                    //the window with the sum of the procs for the appointment. Transfer money below after broken procedure is confirmed by the user.
                    brokenProcedure.ProcFee = listSplitsForApptProcs.Sum(x => x.SplitAmt);
                    isNonRefundable         = true;
                }
                else
                {
                    brokenProcedure.ProcFee = procFee;
                }
                if (!PrefC.GetBool(PrefName.EasyHidePublicHealth))
                {
                    brokenProcedure.SiteNum = pat.SiteNum;
                }
                Procedures.Insert(brokenProcedure);
                //Now make a claimproc if the patient has insurance.  We do this now for consistency because a claimproc could get created in the future.
                List <Benefit>   listBenefits          = Benefits.Refresh(listPatPlans, listInsSubs);
                List <ClaimProc> listClaimProcsForProc = ClaimProcs.RefreshForProc(brokenProcedure.ProcNum);
                Procedures.ComputeEstimates(brokenProcedure, pat.PatNum, listClaimProcsForProc, false, listInsPlans, listPatPlans, listBenefits, pat.Age, listInsSubs);
                FormProcBroken FormPB = new FormProcBroken(brokenProcedure, isNonRefundable);
                FormPB.IsNew = true;
                FormPB.ShowDialog();
                brokenProcAmount     = FormPB.AmountTotal;
                wasBrokenProcDeleted = FormPB.IsProcDeleted;
            }
            #endregion
            #region BrokenApptAdjustment
            if (PrefC.GetBool(PrefName.BrokenApptAdjustment))
            {
                Adjustment AdjustmentCur = new Adjustment();
                AdjustmentCur.DateEntry = DateTime.Today;
                AdjustmentCur.AdjDate   = DateTime.Today;
                AdjustmentCur.ProcDate  = DateTime.Today;
                AdjustmentCur.ProvNum   = appt.ProvNum;
                AdjustmentCur.PatNum    = pat.PatNum;
                AdjustmentCur.AdjType   = PrefC.GetLong(PrefName.BrokenAppointmentAdjustmentType);
                AdjustmentCur.ClinicNum = appt.ClinicNum;
                FormAdjust FormA = new FormAdjust(pat, AdjustmentCur);
                FormA.IsNew = true;
                FormA.ShowDialog();
            }
            #endregion
            #region BrokenApptCommLog
            if (PrefC.GetBool(PrefName.BrokenApptCommLog))
            {
                Commlog commlogCur = new Commlog();
                commlogCur.PatNum       = pat.PatNum;
                commlogCur.CommDateTime = DateTime.Now;
                commlogCur.CommType     = Commlogs.GetTypeAuto(CommItemTypeAuto.APPT);
                commlogCur.Note         = Lan.g("Appointment", "Appt BROKEN for") + " " + appt.ProcDescript + "  " + appt.AptDateTime.ToString();
                commlogCur.Mode_        = CommItemMode.None;
                commlogCur.UserNum      = Security.CurUser.UserNum;
                commlogCur.IsNew        = true;
                FormCommItem FormCI = new FormCommItem(commlogCur);
                FormCI.ShowDialog();
            }
            #endregion
            #region Transfer money from TP Procedures if necessary
            //Note this MUST come after FormProcBroken since clicking cancel in that window will delete the procedure.
            if (isNonRefundable && !wasBrokenProcDeleted && listSplitsForApptProcs.Count > 0)
            {
                //transfer what the user specified in the broken appointment window.
                //transfer up to the amount specified by the user
                foreach (Procedure proc in listProcedures)
                {
                    if (brokenProcAmount == 0)
                    {
                        break;
                    }
                    List <PaySplit> listSplitsForAppointmentProcedure = listSplitsForApptProcs.FindAll(x => x.ProcNum == proc.ProcNum);
                    foreach (PaySplit split in listSplitsForAppointmentProcedure)
                    {
                        if (brokenProcAmount == 0)
                        {
                            break;
                        }
                        double amt = Math.Min(brokenProcAmount, split.SplitAmt);
                        Payments.CreateTransferForTpProcs(proc, new List <PaySplit> {
                            split
                        }, brokenProcedure, amt);
                        double amtPaidOnApt = listSplitsForApptProcs.Sum(x => x.SplitAmt);
                        if (amtPaidOnApt > amt)
                        {
                            //If the original prepayment amount is greater than the amt being specified for the appointment break, transfer
                            //the difference to an Unallocated Unearned Paysplit on the account.
                            double remainingAmt = amtPaidOnApt - amt;
                            //We have to create a new transfer payment here to correlate to the split.
                            Payment txfrPayment = new Payment();
                            txfrPayment.PayAmt    = 0;
                            txfrPayment.PayDate   = DateTime.Today;
                            txfrPayment.ClinicNum = split.ClinicNum;
                            txfrPayment.PayNote   = "Automatic transfer from treatment planned procedure prepayment.";
                            txfrPayment.PatNum    = split.PatNum;                       //ultimately where the payment ends up.
                            txfrPayment.PayType   = 0;
                            Payments.Insert(txfrPayment);
                            PaymentEdit.IncomeTransferData transferData = PaymentEdit.IncomeTransferData.CreateTransfer(split, txfrPayment.PayNum, true, remainingAmt);
                            PaySplit offset         = transferData.ListSplitsCur.FirstOrDefault(x => x.FSplitNum != 0);
                            long     offsetSplitNum = PaySplits.Insert(offset);                      //Get the FSplitNum from the offset
                            PaySplit allocation     = transferData.ListSplitsCur.FirstOrDefault(x => x.FSplitNum == 0);
                            allocation.FSplitNum = offsetSplitNum;
                            PaySplits.Insert(allocation);                            //Insert so the split is now up to date
                            SecurityLogs.MakeLogEntry(Permissions.PaymentCreate, txfrPayment.PatNum, "Automatic transfer of funds for treatment plan procedure pre-payments.");
                        }
                        brokenProcAmount -= amt;
                    }
                }
            }
            //if broken appointment procedure was deleted (user cancelled out of the window) just keep money on the original procedure.
            #endregion
            AppointmentEvent.Fire(ODEventType.AppointmentEdited, appt);
            AutomationL.Trigger(AutomationTrigger.BreakAppointment, null, pat.PatNum);
            Recalls.SynchScheduledApptFull(appt.PatNum);
        }
        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.");
        }