Esempio n. 1
0
        ///<summary>Insert Payment and PaySplit. Returns newly inserted Payment.PayNum.  Throws exceptions if PayConnect Program Properties are invalid.</summary>
        public static long InsertFromPayConnect(long patNum, long provNum, long clinicNum, double amount, string payNote, string receipt, CreditCardSource ccSource)
        {
            //No need to check RemotingRole;no call to db.
            long ret = Payments.Insert(new Payment()
            {
                ClinicNum     = clinicNum,
                IsRecurringCC = false,
                IsSplit       = false,
                PatNum        = patNum,
                PayAmt        = amount,
                PayDate       = DateTime.Now,
                PaymentSource = ccSource,
                PayType       = PIn.Long(ProgramProperties.GetPropVal(Programs.GetCur(ProgramName.PayConnect).ProgramNum, "PaymentType", clinicNum)),
                ProcessStatus = ProcessStat.OnlinePending,
                Receipt       = receipt,
                PayNote       = payNote,
            });

            PaySplits.Insert(new PaySplit()
            {
                ClinicNum = clinicNum,
                DatePay   = DateTime.Now,
                PatNum    = patNum,
                PayNum    = ret,
                ProvNum   = provNum,
                SplitAmt  = amount,
            });
            SecurityLogs.MakeLogEntry(Permissions.PaymentCreate, patNum, Lans.g("Payments.InsertFromPayConnect", "PayConnect payment by") + " "
                                      + OpenDentBusiness.Patients.GetLim(patNum).GetNameLF() + ", " + amount.ToString("c"), LogSources.PatientPortal);
            return(ret);
        }
Esempio n. 2
0
        ///<summary>Gets the current balance of the passed in payment plan num.
        ///Performs the same calculation as the "balance" column in the payment plans grid in ContrAccount.
        ///Optionally pass in the list of PayPlanCharges and list of PaySplits to avoid unneccesary database calls.
        ///Will filter out paysplits and charges associated to different payplans as well as payplan charges that are for the future or have a charge type of debit. </summary>
        public static double GetBalance(long payPlanNum, List <PayPlanCharge> listPayPlanCharges = null, List <PaySplit> listPaySplits = null)
        {
            //No need to check RemotingRole; no call to db.
            double amtBal = 0;

            if (listPayPlanCharges == null)
            {
                listPayPlanCharges = PayPlanCharges.GetForPayPlan(payPlanNum);
            }
            if (listPaySplits == null)
            {
                listPaySplits = PaySplits.GetFromBundled(PaySplits.GetForPayPlan(payPlanNum));
            }
            foreach (PayPlanCharge chargeCur in listPayPlanCharges)
            {
                if (chargeCur.PayPlanNum == payPlanNum &&
                    chargeCur.ChargeType == PayPlanChargeType.Debit)
                {
                    amtBal += chargeCur.Principal;
                    if (chargeCur.ChargeDate <= DateTime.Today)
                    {
                        amtBal += chargeCur.Interest;
                    }
                }
            }
            foreach (PaySplit splitCur in listPaySplits)
            {
                if (splitCur.PayPlanNum == payPlanNum)
                {
                    amtBal -= splitCur.SplitAmt;
                }
            }
            return(amtBal);
        }
Esempio n. 3
0
        ///<summary>Insert Payment and PaySplit. Returns newly inserted Payment.PayNum.  Throws exceptions if XWeb Program Properties are invalid.</summary>
        public static long InsertFromXWeb(long patNum, long provNum, long clinicNum, double amount, string payNote, string receipt, CreditCardSource ccSource)
        {
            //No need to check RemotingRole;no call to db.
            OpenDentBusiness.WebTypes.Shared.XWeb.WebPaymentProperties xwebProperties;
            OpenDentBusiness.ProgramProperties.GetXWebCreds(clinicNum, out xwebProperties);
            long ret = Payments.Insert(new Payment()
            {
                ClinicNum     = clinicNum,
                IsRecurringCC = false,
                IsSplit       = false,
                PatNum        = patNum,
                PayAmt        = amount,
                PayDate       = DateTime.Now,
                PaymentSource = ccSource,
                PayType       = xwebProperties.PaymentTypeDefNum,
                ProcessStatus = ProcessStat.OnlinePending,
                Receipt       = receipt,
                PayNote       = payNote,
            });

            PaySplits.Insert(new PaySplit()
            {
                ClinicNum = clinicNum,
                DatePay   = DateTime.Now,
                PatNum    = patNum,
                PayNum    = ret,
                ProvNum   = provNum,
                SplitAmt  = amount,
            });
            SecurityLogs.MakeLogEntry(Permissions.PaymentCreate, patNum, Lans.g("Payments.InsertFromXWeb", "XWeb payment by") + " "
                                      + OpenDentBusiness.Patients.GetLim(patNum).GetNameLF() + ", " + amount.ToString("c"), LogSources.PatientPortal);
            return(ret);
        }
Esempio n. 4
0
        ///<summary>Gets the data necessary to load FormProcEdit.</summary>
        public static LoadData GetLoadData(Procedure proc, Patient pat, Family fam)
        {
            if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
            {
                return(Meth.GetObject <LoadData>(MethodBase.GetCurrentMethod(), proc, pat, fam));
            }
            LoadData data = new LoadData();

            data.ListPatPlans = PatPlans.Refresh(pat.PatNum);
            if (!PatPlans.IsPatPlanListValid(data.ListPatPlans))             //PatPlans had invalid references and need to be refreshed.
            {
                data.ListPatPlans = PatPlans.Refresh(pat.PatNum);
            }
            data.ListInsSubs           = InsSubs.RefreshForFam(fam);
            data.ListInsPlans          = InsPlans.RefreshForSubList(data.ListInsSubs);
            data.ListClaims            = Claims.Refresh(pat.PatNum);
            data.ListClaimProcsForProc = ClaimProcs.RefreshForProc(proc.ProcNum);
            data.ListBenefits          = Benefits.Refresh(data.ListPatPlans, data.ListInsSubs);
            data.ListRefAttaches       = RefAttaches.RefreshFiltered(proc.PatNum, false, proc.ProcNum);
            data.ArrPaySplits          = PaySplits.Refresh(proc.PatNum);
            List <long> listPayNums = data.ArrPaySplits.Where(x => x.ProcNum == proc.ProcNum).Select(x => x.PayNum).ToList();

            data.ListPaymentsForProc = Payments.GetPayments(listPayNums);
            data.ArrAdjustments      = Adjustments.Refresh(proc.PatNum);
            data.OrthoProcedureLink  = OrthoProcLinks.GetByProcNum(proc.ProcNum);
            return(data);
        }
Esempio n. 5
0
        ///<summary>Creates a transfer originating from the prepayment containing the procOriginal, back to the procOriginal.
        ///Used to transfer money from TP unearned back onto the procedure as an allocated non pre-pay split.
        ///Optionally pass in procNumAttaching when wanting to attach to a procedure other than the procOriginal.
        ///Optionally pass in transferAmountOverride when transferring an amount that is not the split amount, as in the case for broken procs.</summary>
        public static void CreateTransferForTpProcs(Procedure procOriginal, List <PaySplit> listSplitsForProc, Procedure procAttaching = null,
                                                    double transferAmountOverride = 0)
        {
            if (listSplitsForProc.IsNullOrEmpty() || listSplitsForProc.Sum(x => x.SplitAmt) == 0)
            {
                return;
            }
            //procAttaching will be null when transferring from unearned to same procedure.
            procAttaching = procAttaching ?? procOriginal;
            Payment transferPayment = new Payment();

            transferPayment.PayDate   = DateTime.Today;
            transferPayment.ClinicNum = procOriginal.ClinicNum;
            transferPayment.PayNote   = "Automatic transfer from treatment planned procedure prepayment.";
            transferPayment.PatNum    = procAttaching.PatNum;       //ultimately where the payment ends up.
            transferPayment.PayType   = 0;
            Insert(transferPayment);
            foreach (PaySplit prepaySplit in listSplitsForProc)
            {
                //make negative split to remove the 'tp prepayment'
                PaySplit negSplitForTxfr = new PaySplit {
                    ClinicNum = procOriginal.ClinicNum,
                    DatePay   = DateTime.Today,
                    FSplitNum = prepaySplit.SplitNum,
                    ProcNum   = 0,                //either the procedure is being set complete, or pref for Non-Refundable TP prepay is set and transferring to procAttaching.
                    //If non-refundable the procedure needs to be disassociated as well as we will not have a way to determine when procOriginal eventually
                    //gets set complete and unearned cannot exist with a completed procedure attached.
                    PatNum       = procOriginal.PatNum,
                    PayNum       = transferPayment.PayNum,
                    SplitAmt     = (transferAmountOverride == 0?prepaySplit.SplitAmt:transferAmountOverride) * -1,
                    UnearnedType = prepaySplit.UnearnedType,
                    ProcDate     = procOriginal.ProcDate,
                    ProvNum      = prepaySplit.ProvNum,
                };
                PaySplits.Insert(negSplitForTxfr);
                //Update original pre-payment split to disassociate the procedure now that the procedure is complete (Splits cannot have unaerned and C proc)
                prepaySplit.ProcNum = 0;
                PaySplits.Update(prepaySplit);
                PaySplit positiveSplit = new PaySplit {
                    ClinicNum    = procAttaching.ClinicNum,
                    DatePay      = DateTime.Today,
                    FSplitNum    = negSplitForTxfr.SplitNum,               //if meant for unearned, FSplitNum must be 0 to show up correctly.
                    ProcNum      = procAttaching.ProcNum,
                    PatNum       = procAttaching.PatNum,
                    PayNum       = transferPayment.PayNum,
                    SplitAmt     = transferAmountOverride == 0?prepaySplit.SplitAmt:transferAmountOverride,
                    ProcDate     = procAttaching.ProcDate,
                    ProvNum      = procAttaching.ProvNum,
                    UnearnedType = 0                  //necessary for when broken appointments do not get a procedure created for them to transfer to.
                };
                PaySplits.Insert(positiveSplit);
            }
            SecurityLogs.MakeLogEntry(Permissions.PaymentCreate, transferPayment.PatNum, "Automatic transfer of funds for treatment plan procedure pre-payments.");
        }
Esempio n. 6
0
 ///<summary>This will soon be eliminated or changed to only allow deleting on same day as EntryDate.</summary>
 public static void Delete(Adjustment adj)
 {
     if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
     {
         Meth.GetVoid(MethodBase.GetCurrentMethod(), adj);
         return;
     }
     Crud.AdjustmentCrud.Delete(adj.AdjNum);
     CreateOrUpdateSalesTaxIfNeeded(adj);
     PaySplits.UnlinkForAdjust(adj);
 }
Esempio n. 7
0
        ///<summary>Returns the total amount of prepayments for the entire family.</summary>
        public static decimal GetUnearnedForFam(Family fam, List <PaySplit> listPrePayments = null)
        {
            //No need to check RemotingRole; no call to db.
            //Find all paysplits for this account with provnum=0
            //Foreach paysplit find all other paysplits with paysplitnum == provnum0 paysplit
            //Sum paysplit amounts, see if it covers provnum0 split.
            //Any money left over sum and show as "Unallocated" aka unearned
            decimal unearnedTotal = 0;

            listPrePayments = listPrePayments ?? PaySplits.GetPrepayForFam(fam);
            if (listPrePayments.Count > 0)
            {
                foreach (PaySplit split in listPrePayments)
                {
                    unearnedTotal += (decimal)split.SplitAmt;
                }
                List <PaySplit> listSplitsForPrePayment = PaySplits.GetSplitsForPrepay(listPrePayments);
                foreach (PaySplit split in listSplitsForPrePayment)
                {
                    unearnedTotal += (decimal)split.SplitAmt;                  //Splits for prepayments are generally negative.
                }
            }
            return(unearnedTotal);
        }
Esempio n. 8
0
        public static Statement CreateLimitedStatement(List <long> listPatNumsSelected, long patNum, List <long> listPayClaimNums, List <long> listAdjustments,
                                                       List <long> listPayNums, List <long> listProcedures)
        {
            Statement stmt = new Statement();

            if (listPatNumsSelected.Count == 1)
            {
                stmt.PatNum = listPatNumsSelected[0];
            }
            else
            {
                stmt.PatNum = patNum;
            }
            stmt.DateSent      = DateTimeOD.Today;
            stmt.IsSent        = false;
            stmt.Mode_         = StatementMode.InPerson;
            stmt.HidePayment   = false;
            stmt.SinglePatient = listPatNumsSelected.Count == 1;        //SinglePatient determined by the selected transactions
            stmt.Intermingled  = listPatNumsSelected.Count > 1 && PrefC.GetBool(PrefName.IntermingleFamilyDefault);
            stmt.IsReceipt     = false;
            stmt.IsInvoice     = false;
            stmt.StatementType = StmtType.LimitedStatement;
            stmt.DateRangeFrom = DateTime.MinValue;
            stmt.DateRangeTo   = DateTimeOD.Today;
            stmt.Note          = "";
            stmt.NoteBold      = "";
            stmt.IsBalValid    = true;
            stmt.BalTotal      = 0;
            stmt.InsEst        = 0;
            Statements.Insert(stmt);            //we need stmt.StatementNum for attaching procs, adjustments, and paysplits to the statement
            foreach (long adjNum in listAdjustments)
            {
                StmtLinks.Insert(new StmtLink()
                {
                    FKey = adjNum, StatementNum = stmt.StatementNum, StmtLinkType = StmtLinkTypes.Adj
                });
            }
            foreach (long payNum in listPayNums)
            {
                Payment payment = Payments.GetPayment(payNum);
                PaySplits.GetForPayment(payNum)
                .FindAll(x => x.PatNum == payment.PatNum && x.ClinicNum == payment.ClinicNum)
                .ForEach(x => StmtLinks.Insert(new StmtLink()
                {
                    FKey = x.SplitNum, StatementNum = stmt.StatementNum, StmtLinkType = StmtLinkTypes.PaySplit
                }));
            }
            foreach (long procNum in listProcedures)
            {
                StmtLinks.Insert(new StmtLink()
                {
                    FKey = procNum, StatementNum = stmt.StatementNum, StmtLinkType = StmtLinkTypes.Proc
                });
            }
            foreach (long claimNum in listPayClaimNums)
            {
                StmtLinks.Insert(new StmtLink()
                {
                    FKey = claimNum, StatementNum = stmt.StatementNum, StmtLinkType = StmtLinkTypes.ClaimPay
                });
            }
            //foreach(PayPlanCharge payPlanCharge in listPayPlanCharges) {
            //	StmtLinks.Insert(new OpenDentBusiness.StmtLink() {FKey=payPlanCharge.PayPlanChargeNum,StatementNum=stmt.StatementNum,StmtLinkType=StmtLinkTypes.PayPlanCharge});
            //}
            //set statement lists to null in order to force refresh the lists now that we've inserted all of the StmtAttaches
            stmt.ListAdjNums         = null;
            stmt.ListPaySplitNums    = null;
            stmt.ListProcNums        = null;
            stmt.ListInsPayClaimNums = null;
            if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
            {
                //Currently when using MiddleTier null lists inside an object like above causes the deserialized statement to incorrectly set the null lists
                //to empty lists.
                //In the case of a Statement, the public property associated to list in question does not run queries to populate the list as expected because
                //it checks for a null list, but instead sees an empty list.
                //We may fix the underlying MiddleTier bug later, but this is an immediate patch to address this symptom.
                stmt.ListAdjNums      = StmtLinks.GetForStatementAndType(stmt.StatementNum, StmtLinkTypes.Adj);
                stmt.ListPaySplitNums = StmtLinks.GetForStatementAndType(stmt.StatementNum, StmtLinkTypes.PaySplit);
                if (stmt.IsInvoice)
                {
                    stmt.ListProcNums = Procedures.GetForInvoice(stmt.StatementNum);
                }
                else
                {
                    stmt.ListProcNums = StmtLinks.GetForStatementAndType(stmt.StatementNum, StmtLinkTypes.Proc);
                }
                stmt.ListInsPayClaimNums = StmtLinks.GetForStatementAndType(stmt.StatementNum, StmtLinkTypes.ClaimPay);
            }
            return(stmt);
        }
Esempio n. 9
0
        private static Procedure AddRepeatingChargeHelper(RepeatCharge repeatCharge, DateTime billingDate, DateTime dateNow)
        {
            //No remoting role check; no call to db
            Procedure     procedure = new Procedure();
            ProcedureCode procCode  = ProcedureCodes.GetProcCode(repeatCharge.ProcCode);
            Patient       pat       = Patients.GetPat(repeatCharge.PatNum);

            procedure.CodeNum    = procCode.CodeNum;
            procedure.ClinicNum  = pat.ClinicNum;
            procedure.DateEntryC = dateNow;
            procedure.PatNum     = repeatCharge.PatNum;
            procedure.ProcDate   = billingDate;
            procedure.DateTP     = billingDate;
            procedure.ProcFee    = repeatCharge.ChargeAmt;
            procedure.ProcStatus = ProcStat.C;
            if (procCode.ProvNumDefault == 0)
            {
                procedure.ProvNum = pat.PriProv;
            }
            else
            {
                procedure.ProvNum = procCode.ProvNumDefault;
            }
            procedure.MedicalCode     = ProcedureCodes.GetProcCode(procedure.CodeNum).MedicalCode;
            procedure.BaseUnits       = ProcedureCodes.GetProcCode(procedure.CodeNum).BaseUnits;
            procedure.DiagnosticCode  = PrefC.GetString(PrefName.ICD9DefaultForNewProcs);
            procedure.RepeatChargeNum = repeatCharge.RepeatChargeNum;
            procedure.PlaceService    = (PlaceOfService)PrefC.GetInt(PrefName.DefaultProcedurePlaceService);       //Default Proc Place of Service for the Practice is used.
            //Check if the repeating charge has been flagged to copy it's note into the billing note of the procedure.
            if (repeatCharge.CopyNoteToProc)
            {
                procedure.BillingNote = repeatCharge.Note;
                if (repeatCharge.ErxAccountId != "")
                {
                    procedure.BillingNote =
                        "NPI=" + repeatCharge.Npi + "  " + "ErxAccountId=" + repeatCharge.ErxAccountId;
                    if (!string.IsNullOrEmpty(repeatCharge.ProviderName))                     //Provider name would be empty if older and no longer updated from eRx.
                    {
                        procedure.BillingNote += "\r\nProviderName=" + repeatCharge.ProviderName;
                    }
                    if (!string.IsNullOrEmpty(repeatCharge.Note))
                    {
                        procedure.BillingNote += "\r\n" + repeatCharge.Note;
                    }
                }
            }
            if (!PrefC.GetBool(PrefName.EasyHidePublicHealth))
            {
                procedure.SiteNum = pat.SiteNum;
            }
            Procedures.Insert(procedure);             //no recall synch needed because dental offices don't use this feature
            //Using Prepayments for this Procedure
            if (repeatCharge.UsePrepay)
            {
                //NOTE: ProvNum=0 on these splits, so I'm pretty sure they aren't allocated to anything.
                List <PaySplit> prePaySplits             = PaySplits.GetPrepayForFam(Patients.GetFamily(repeatCharge.PatNum));
                List <PaySplit> paySplitsForPrePaySplits = PaySplits.GetSplitsForPrepay(prePaySplits);
                Payment         payCur = new Payment();
                payCur.ClinicNum = procedure.ClinicNum;
                payCur.DateEntry = billingDate;
                payCur.IsSplit   = true;
                payCur.PatNum    = repeatCharge.PatNum;
                payCur.PayDate   = billingDate;
                payCur.PayType   = 0;           //Income transfer (will always be income transfer)
                payCur.PayAmt    = 0;           //Income transfer payment
                payCur.PayNum    = Payments.Insert(payCur);
                decimal payAmt   = 0;
                string  noteText = "";
                foreach (PaySplit prePaySplit in prePaySplits)
                {
                    prePaySplit.SplitAmt += paySplitsForPrePaySplits.Where(x => x.FSplitNum == prePaySplit.SplitNum).Sum(y => y.SplitAmt);                //Reduce prepay split amount.
                    PaySplit split  = new PaySplit();
                    PaySplit split2 = new PaySplit();
                    if (prePaySplit.SplitAmt > procedure.ProcFee - (double)payAmt)
                    {
                        //Split amount is more than the remainder of the procfee requires, use partial from split
                        split.SplitAmt  = procedure.ProcFee - (double)payAmt;
                        split2.SplitAmt = 0 - (procedure.ProcFee - (double)payAmt);
                        payAmt          = (decimal)procedure.ProcFee;
                    }
                    else
                    {
                        //Split amount is less than or equal to the remainder of the procfee
                        split.SplitAmt  = prePaySplit.SplitAmt;
                        split2.SplitAmt = 0 - prePaySplit.SplitAmt;
                        payAmt         += (decimal)prePaySplit.SplitAmt;
                    }
                    if (split.SplitAmt == 0)
                    {
                        continue;                        //Don't make splits for 0 amount.
                    }
                    //Positive split, attached to proc and for proc's prov and clinic
                    split.DateEntry = billingDate;
                    split.DatePay   = billingDate;
                    split.PatNum    = procedure.PatNum;
                    split.PayNum    = payCur.PayNum;
                    split.ProcNum   = procedure.ProcNum;
                    split.ProvNum   = procedure.ProvNum;
                    split.ClinicNum = procedure.ClinicNum;
                    if (noteText != "")
                    {
                        noteText += ", ";
                    }
                    noteText += split.SplitAmt.ToString("c");
                    PaySplits.Insert(split);
                    //Negative split, attached to prepay's prov and clinic, but not proc
                    split2.DateEntry = billingDate;
                    split2.DatePay   = billingDate;
                    split2.PatNum    = procedure.PatNum;
                    split2.PayNum    = payCur.PayNum;
                    split2.FSplitNum = prePaySplit.SplitNum;
                    split2.ProvNum   = prePaySplit.ProvNum;
                    split2.ClinicNum = prePaySplit.ClinicNum;
                    PaySplits.Insert(split2);
                    if (payAmt >= (decimal)procedure.ProcFee)
                    {
                        //Break out of loop
                        break;
                    }
                }
                payCur.PayNote = "Allocated " + noteText + " prepayments to repeating charge.";
                Payments.Update(payCur, false);
            }
            return(procedure);
        }