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