///<summary>Can handle CreditCard being null.</summary> public FormPayConnect(Payment payment,Patient pat,string amount,CreditCard creditCard) { InitializeComponent(); Lan.F(this); PaymentCur=payment; PatCur=pat; amountInit=amount; receiptStr=""; CreditCardCur=creditCard; }
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=CodeBase.MiscUtils.Decrypt(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"); try { File.Delete(resultfile);//delete the old result file. } catch { //Probably did not have permissions to delete the file. Don't do anything, because a message will show telling them that the cards left in the grid failed. //They will then go try and run the cards in the Account module and will then get a detailed message telling them what is wrong. continue; } 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"; try { 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"; } } catch { continue;//Cards will still be in the list if something went wrong. } #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."); }
private void butOK_Click(object sender, System.EventArgs e) { if(!ClaimIsValid()){ return; } //if status is received, all claimprocs must also be received. if(comboClaimStatus.SelectedIndex==5){ bool allReceived=true; for(int i=0;i<ClaimProcsForClaim.Count;i++){ if(((ClaimProc)ClaimProcsForClaim[i]).Status==ClaimProcStatus.NotReceived){ allReceived=false; } } if(!allReceived){ if(!MsgBox.Show(this,true,"All items will be marked received. Continue?")){ return; } for(int i=0;i<ClaimProcsForClaim.Count;i++){ if(ClaimProcsForClaim[i].Status==ClaimProcStatus.NotReceived){ //ClaimProcs.Cur=(ClaimProc)ClaimProcs.ForClaim[i]; ClaimProcsForClaim[i].Status=ClaimProcStatus.Received; ClaimProcsForClaim[i].DateEntry=DateTime.Now;//date it was set rec'd ClaimProcs.Update(ClaimProcsForClaim[i]); } } } } else{//claim is any status except received bool anyReceived=false; for(int i=0;i<ClaimProcsForClaim.Count;i++){ if(((ClaimProc)ClaimProcsForClaim[i]).Status==ClaimProcStatus.Received){ anyReceived=true; } } if(anyReceived){ //Too dangerous to automatically set items not received because I would have to check for attachments to checks, etc. //Also too annoying to block user. //So just warn user. if(!MsgBox.Show(this,true,"Some of the items are marked received. This is not a good idea since it will cause them to show in the Account as a 'payment'. Continue anyway?")){ return; } } } //if status is received and there is no received date if(comboClaimStatus.SelectedIndex==5 && textDateRec.Text==""){ textDateRec.Text=DateTime.Today.ToShortDateString(); } UpdateClaim(); if(comboClaimStatus.SelectedIndex==2){//waiting to send ClaimSendQueueItem[] listQueue=Claims.GetQueueList(ClaimCur.ClaimNum,ClaimCur.ClinicNum,0); if(listQueue[0].NoSendElect) { DialogResult=DialogResult.OK; return; } //string warnings; //string missingData= Eclaims.Eclaims.GetMissingData(listQueue[0]);//,out warnings); if(listQueue[0].MissingData!="") { if(MessageBox.Show(Lan.g(this,"Cannot send claim until missing data is fixed:")+"\r\n"+listQueue[0].MissingData+"\r\n\r\nContinue anyway?", "",MessageBoxButtons.OKCancel)==DialogResult.OK) { DialogResult=DialogResult.OK; } return; } //if(MsgBox.Show(this,true,"Send electronic claim immediately?")){ // List<ClaimSendQueueItem> queueItems=new List<ClaimSendQueueItem>(); // queueItems.Add(listQueue[0]); // Eclaims.Eclaims.SendBatches(queueItems);//this also calls SetClaimSentOrPrinted which creates the etrans entry. //} } if(comboClaimStatus.SelectedIndex==5){//Received if(PrefC.GetBool(PrefName.ProviderIncomeTransferShows)){ Payment PaymentCur=new Payment(); PaymentCur.PayDate=DateTimeOD.Today; PaymentCur.PatNum=PatCur.PatNum; PaymentCur.ClinicNum=PatCur.ClinicNum; PaymentCur.PayType=0;//txfr PaymentCur.DateEntry=DateTimeOD.Today;//So that it will show properly in the new window. Payments.Insert(PaymentCur); FormPayment Formp=new FormPayment(PatCur,FamCur,PaymentCur); Formp.IsNew=true; Formp.ShowDialog(); } } DialogResult=DialogResult.OK; }
/// <summary>Only Called only from FormPayment.butOK click. Only called if the user did not enter any splits. Usually just adds one split for the current patient. But if that would take the balance negative, then it loops through all other family members and creates splits for them. It might still take the current patient negative once all other family members are zeroed out.</summary> public static List<PaySplit> Allocate(Payment pay){//double amtTot,int patNum,Payment payNum){ if(RemotingClient.RemotingRole==RemotingRole.ClientWeb) { return Meth.GetObject<List<PaySplit>>(MethodBase.GetCurrentMethod(),pay); } string command= "SELECT Guarantor FROM patient " +"WHERE PatNum = "+POut.Long(pay.PatNum); DataTable table=Db.GetTable(command); if(table.Rows.Count==0){ return new List<PaySplit>(); } command= "SELECT patient.PatNum,EstBalance,PriProv,SUM(InsPayEst)+SUM(Writeoff) insEst_ " +"FROM patient " +"LEFT JOIN claimproc ON patient.PatNum=claimproc.PatNum " +"AND Status=0 "//NotReceived +"WHERE Guarantor = "+table.Rows[0][0].ToString()+" " +"GROUP BY patient.PatNum,EstBalance,PriProv"; //+" ORDER BY PatNum!="+POut.PInt(pay.PatNum);//puts current patient in position 0 //Oracle does not allow table=Db.GetTable(command); List<Patient> pats=new List<Patient>(); Patient pat; //first, put the current patient at position 0. for(int i=0;i<table.Rows.Count;i++) { if(table.Rows[i]["PatNum"].ToString()==pay.PatNum.ToString()){ pat=new Patient(); pat.PatNum = PIn.Long(table.Rows[i][0].ToString()); pat.EstBalance= PIn.Double(table.Rows[i][1].ToString()); if(!PrefC.GetBool(PrefName.BalancesDontSubtractIns)){ pat.EstBalance-=PIn.Double(table.Rows[i]["insEst_"].ToString()); } pat.PriProv = PIn.Long(table.Rows[i][2].ToString()); pats.Add(pat.Copy()); } } //then, do all the rest of the patients. for(int i=0;i<table.Rows.Count;i++){ if(table.Rows[i]["PatNum"].ToString()==pay.PatNum.ToString()){ continue; } pat=new Patient(); pat.PatNum = PIn.Long (table.Rows[i][0].ToString()); pat.EstBalance= PIn.Double(table.Rows[i][1].ToString()); if(!PrefC.GetBool(PrefName.BalancesDontSubtractIns)){ pat.EstBalance-=PIn.Double(table.Rows[i]["insEst_"].ToString()); } pat.PriProv = PIn.Long (table.Rows[i][2].ToString()); pats.Add(pat.Copy()); } //first calculate all the amounts double amtRemain=pay.PayAmt;//start off with the full amount double[] amtSplits=new double[pats.Count]; //loop through each family member, starting with current for(int i=0;i<pats.Count;i++){ if(pats[i].EstBalance==0 || pats[i].EstBalance<0){ continue;//don't apply paysplits to anyone with a negative balance } if(amtRemain<pats[i].EstBalance){//entire remainder can be allocated to this patient amtSplits[i]=amtRemain; amtRemain=0; break; } else{//amount remaining is more than or equal to the estBal for this family member amtSplits[i]=pats[i].EstBalance; amtRemain-=pats[i].EstBalance; } } //add any remainder to the split for this patient amtSplits[0]+=amtRemain; //now create a split for each non-zero amount PaySplit PaySplitCur; List<PaySplit> retVal=new List<PaySplit>(); for(int i=0;i<pats.Count;i++){ if(amtSplits[i]==0){ continue; } PaySplitCur=new PaySplit(); PaySplitCur.PatNum=pats[i].PatNum; PaySplitCur.PayNum=pay.PayNum; PaySplitCur.ProcDate=pay.PayDate; PaySplitCur.DatePay=pay.PayDate; PaySplitCur.ClinicNum=pay.ClinicNum; PaySplitCur.ProvNum=Patients.GetProvNum(pats[i]); PaySplitCur.SplitAmt=Math.Round(amtSplits[i],CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalDigits); //PaySplitCur.InsertOrUpdate(true); retVal.Add(PaySplitCur); } //finally, adjust each EstBalance, but no need to do current patient //This no longer works here. Must do it when closing payment window somehow /*for(int i=1;i<pats.Length;i++){ if(amtSplits[i]==0){ continue; } command="UPDATE patient SET EstBalance=EstBalance-"+POut.PDouble(amtSplits[i]) +" WHERE PatNum="+POut.PInt(pats[i].PatNum); Db.NonQ(command); }*/ return retVal; }
///<summary>Deletes the payment as well as all splits. Surround by try catch, because it will throw an exception if trying to delete a payment attached to a deposit.</summary> public static void Delete(Payment pay){ if(RemotingClient.RemotingRole==RemotingRole.ClientWeb) { Meth.GetVoid(MethodBase.GetCurrentMethod(),pay); return; } string command="SELECT DepositNum,PayAmt FROM payment WHERE PayNum="+POut.Long(pay.PayNum); DataTable table=Db.GetTable(command); if(table.Rows.Count==0){ return; } if(table.Rows[0]["DepositNum"].ToString()!="0"//if payment is already attached to a deposit && PIn.Double(table.Rows[0]["PayAmt"].ToString())!=0)//and it's not new { #if !DEBUG throw new ApplicationException(Lans.g("Payments","Not allowed to delete a payment attached to a deposit.")); #endif } command= "DELETE from payment WHERE payNum = '"+pay.PayNum.ToString()+"'"; Db.NonQ(command); //this needs to be improved to handle EstBal command= "DELETE from paysplit WHERE payNum = '"+pay.PayNum.ToString()+"'"; Db.NonQ(command); //PaySplit[] splitList=PaySplits.RefreshPaymentList(PayNum); //for(int i=0;i<splitList.Length;i++){ // splitList[i].Delete(); //} }
///<summary>There's only one place in the program where this is called from. Date is today, so no need to validate the date.</summary> public static long Insert(Payment pay,bool useExistingPK) { if(RemotingClient.RemotingRole==RemotingRole.ClientWeb) { pay.PayNum=Meth.GetLong(MethodBase.GetCurrentMethod(),pay,useExistingPK); return pay.PayNum; } return Crud.PaymentCrud.Insert(pay,useExistingPK); }
///<summary>Updates this payment. Must make sure to update the datePay of all attached paysplits so that they are always in synch. Also need to manually set IsSplit before here. Will throw an exception if bad date, so surround by try-catch. Set excludeDepositNum to true from FormPayment to prevent collision from another worksation that just deleted a deposit.</summary> public static void Update(Payment pay,bool excludeDepositNum){ if(RemotingClient.RemotingRole==RemotingRole.ClientWeb) { Meth.GetVoid(MethodBase.GetCurrentMethod(),pay,excludeDepositNum); return; } if(pay.PayDate.Date>DateTime.Today) { throw new ApplicationException(Lans.g("Payments","Date must not be a future date.")); } if(pay.PayDate.Year<1880) { throw new ApplicationException(Lans.g("Payments","Invalid date")); } //the functionality below needs to be taken care of before calling the function: /*string command="SELECT DepositNum,PayAmt FROM payment " +"WHERE PayNum="+POut.PInt(PayNum); DataConnection dcon=new DataConnection(); DataTable table=Db.GetTable(command); if(table.Rows.Count==0) { return; } if(table.Rows[0][0].ToString()!="0"//if payment is already attached to a deposit && PIn.PDouble(table.Rows[0][1].ToString())!=PayAmt) {//and PayAmt changes throw new ApplicationException(Lans.g("Payments","Not allowed to change the amount on payments attached to deposits.")); }*/ Crud.PaymentCrud.Update(pay); if(!excludeDepositNum) { string command="UPDATE payment SET DepositNum="+POut.Long(pay.DepositNum)+" WHERE payNum = "+POut.Long(pay.PayNum); Db.NonQ(command); } }
///<summary>PatCur and FamCur are not for the PatCur of the payment. They are for the patient and family from which this window was accessed.</summary> public FormPayment(Patient patCur,Family famCur,Payment paymentCur) { InitializeComponent();// Required for Windows Form Designer support PatCur=patCur; FamCur=famCur; PaymentCur=paymentCur; Lan.F(this); panelXcharge.ContextMenu=contextMenuXcharge; butPayConnect.ContextMenu=contextMenuPayConnect; }
private void butOK_Click(object sender,System.EventArgs e) { if(textDate.errorProvider1.GetError(textDate)!="" || textAmount.errorProvider1.GetError(textAmount)!="") { MessageBox.Show(Lan.g(this,"Please fix data entry errors first.")); return; } if(checkPayTypeNone.Checked) { if(PIn.Double(textAmount.Text)!=0) { MsgBox.Show(this,"Amount must be zero for a transfer."); return; } } else { if(textAmount.Text=="") { MessageBox.Show(Lan.g(this,"Please enter an amount.")); return; } if(PIn.Double(textAmount.Text)==0) { MessageBox.Show(Lan.g(this,"Amount must not be zero unless this is a transfer.")); return; } if(listPayType.SelectedIndex==-1) { MsgBox.Show(this,"A payment type must be selected."); return; } } if(IsNew) { //prevents backdating of initial payment if(!Security.IsAuthorized(Permissions.PaymentCreate,PIn.Date(textDate.Text))) { 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.PaymentEdit,PIn.Date(textDate.Text))) { return; } } bool accountingSynchRequired=false; double accountingOldAmt=PaymentCur.PayAmt; long accountingNewAcct=-1;//the old acctNum will be retrieved inside the validation code. if(textDepositAccount.Visible) { accountingNewAcct=-1;//indicates no change } else if(comboDepositAccount.Visible && comboDepositAccount.Items.Count>0 && comboDepositAccount.SelectedIndex!=-1) { accountingNewAcct=DepositAccounts[comboDepositAccount.SelectedIndex]; } else {//neither textbox nor combo visible. Or something's wrong with combobox accountingNewAcct=0; } try { accountingSynchRequired=Payments.ValidateLinkedEntries(accountingOldAmt,PIn.Double(textAmount.Text),IsNew, PaymentCur.PayNum,accountingNewAcct); } catch(ApplicationException ex) { MessageBox.Show(ex.Message);//not able to alter, so must not allow user to continue. return; } PaymentCur.PayAmt=PIn.Double(textAmount.Text);//handles blank PaymentCur.PayDate=PIn.Date(textDate.Text); #region Recurring charge logic //User chose to have a recurring payment so we need to know if the card has recurring setup and which month to apply the payment to. if(IsNew && checkRecurring.Checked && comboCreditCards.SelectedIndex!=creditCards.Count) { //Check if a recurring charge is setup for the selected card. if(creditCards[comboCreditCards.SelectedIndex].ChargeAmt==0 || creditCards[comboCreditCards.SelectedIndex].DateStart.Year < 1880) { MsgBox.Show(this,"The selected credit card has not been setup for recurring charges."); return; } //Check if a stop date was set and if that date falls in on today or in the past. if(creditCards[comboCreditCards.SelectedIndex].DateStop.Year > 1880 && creditCards[comboCreditCards.SelectedIndex].DateStop<=DateTime.Now) { MsgBox.Show(this,"This card is no longer accepting recurring charges based on the stop date."); return; } //Have the user decide what month to apply the recurring charge towards. FormCreditRecurringDateChoose formDateChoose=new FormCreditRecurringDateChoose(creditCards[comboCreditCards.SelectedIndex]); formDateChoose.ShowDialog(); if(formDateChoose.DialogResult!=DialogResult.OK) { MsgBox.Show(this,"Uncheck the \"Apply to Recurring Charge\" box."); return; } //This will change the PayDate to work better with the recurring charge automation. User was notified in previous window. PaymentCur.PayDate=formDateChoose.PayDate; } else if(IsNew && checkRecurring.Checked && comboCreditCards.SelectedIndex==creditCards.Count) { MsgBox.Show(this,"Cannot apply a recurring charge to a new card."); return; } #endregion PaymentCur.CheckNum=textCheckNum.Text; PaymentCur.BankBranch=textBankBranch.Text; PaymentCur.PayNote=textNote.Text; PaymentCur.IsRecurringCC=checkRecurring.Checked; if(checkPayTypeNone.Checked) { PaymentCur.PayType=0; } else { PaymentCur.PayType=DefC.Short[(int)DefCat.PaymentTypes][listPayType.SelectedIndex].DefNum; } //PaymentCur.PatNum=PatCur.PatNum;//this is already done before opening this window. //PaymentCur.ClinicNum already handled if(IsNew && SplitList.Count==0) { //The user has no splits and is trying to submit a payment. //We need to ask if they want to autosplit the payment to start getting procedures associated to splits. if(MsgBox.Show(this,MsgBoxButtons.YesNo,"Would you like to autosplit the payment to outstanding family balances?")) { FormPaySplitManage FormPSM=new FormPaySplitManage(); FormPSM.PaymentAmt=PIn.Double(textAmount.Text); FormPSM.FamCur=Patients.GetFamily(PatCur.PatNum); FormPSM.PatCur=PatCur; FormPSM.PaymentCur=PaymentCur; FormPSM.PayDate=PIn.DateT(textDate.Text); FormPSM.IsNew=IsNew; FormPSM.ListSplitsCur=SplitList; if(FormPSM.ShowDialog()==DialogResult.OK) { SplitList=FormPSM.ListSplitsCur; PaymentCur=FormPSM.PaymentCur; if(SplitList.Count==0) {//If they clicked OK without any splits being added, add one split. AddOneSplit(); } } else {//Cancel AddOneSplit(); } } else {//Either no allocation required, or user does not want to allocate. Just add one split. AddOneSplit(); } } else {//Existing payment and/or has splits. if(SplitList.Count==0) {//Existing payment with no splits. if(Payments.AllocationRequired(PaymentCur.PayAmt,PaymentCur.PatNum) && MsgBox.Show(this,MsgBoxButtons.YesNo,"Apply part of payment to other family members?")) { SplitList=Payments.Allocate(PaymentCur);//PayAmt needs to be set first } else {//Either no allocation required, or user does not want to allocate. Just add one split. AddOneSplit(); } } else {//A new or existing payment with splits. if(SplitList.Count==1//if one split && PIn.Double(textAmount.Text) != SplitList[0].SplitAmt)//and amount doesn't match payment { SplitList[0].SplitAmt=PIn.Double(textAmount.Text);//make amounts match } if(SplitList.Count==1//if one split && PaymentCur.PayDate != SplitList[0].ProcDate && SplitList[0].ProcNum==0)//not attached to procedure { if(MsgBox.Show(this,MsgBoxButtons.YesNo,"Change split date to match payment date?")) { SplitList[0].ProcDate=PaymentCur.PayDate; } } if(SplitList.Count!=1 && PaymentCur.PayAmt!=PIn.Double(textTotal.Text)) { MsgBox.Show(this,"Split totals must equal payment amount."); //work on reallocation schemes here later return; } } } if(SplitList.Count>1) { PaymentCur.IsSplit=true; } else { PaymentCur.IsSplit=false; } try { Payments.Update(PaymentCur,true); } catch(ApplicationException ex) {//this catches bad dates. MessageBox.Show(ex.Message); return; } //Set all DatePays the same. for(int i=0;i<SplitList.Count;i++) { SplitList[i].DatePay=PaymentCur.PayDate; } PaySplits.UpdateList(SplitListOld,SplitList); //Accounting synch is done here. All validation was done further up //If user is trying to change the amount or linked account of an entry that was already copied and linked to accounting section if(accountingSynchRequired) { Payments.AlterLinkedEntries(accountingOldAmt,PaymentCur.PayAmt,IsNew, PaymentCur.PayNum,accountingNewAcct,PaymentCur.PayDate,FamCur.GetNameInFamFL(PaymentCur.PatNum)); } if(IsNew) { SecurityLogs.MakeLogEntry(Permissions.PaymentCreate,PaymentCur.PatNum, Patients.GetLim(PaymentCur.PatNum).GetNameLF()+", " +PaymentCur.PayAmt.ToString("c")); } else { SecurityLogs.MakeLogEntry(Permissions.PaymentEdit,PaymentCur.PatNum, Patients.GetLim(PaymentCur.PatNum).GetNameLF()+", " +PaymentCur.PayAmt.ToString("c")); } DialogResult=DialogResult.OK; }
private void butSplitManage_Click(object sender,EventArgs e) { FormPaySplitManage FormPSM=new FormPaySplitManage(); FormPSM.PaymentAmt=PIn.Double(textAmount.Text); FormPSM.FamCur=Patients.GetFamily(PatCur.PatNum); FormPSM.PatCur=PatCur; FormPSM.PaymentCur=PaymentCur; FormPSM.PayDate=PIn.DateT(textDate.Text); FormPSM.IsNew=IsNew; FormPSM.ListSplitsCur=SplitList; FormPSM.ShowDialog(); if(FormPSM.DialogResult==DialogResult.OK) { SplitList=FormPSM.ListSplitsCur; PaymentCur=FormPSM.PaymentCur; textAmount.Text=POut.Double(PaymentCur.PayAmt); } FillMain(); }
public static string PaySplitWithInvalidPayNum(bool verbose,bool isCheck) { if(RemotingClient.RemotingRole==RemotingRole.ClientWeb) { return Meth.GetString(MethodBase.GetCurrentMethod(),verbose,isCheck); } string log=""; if(isCheck) { command="SELECT COUNT(*) FROM paysplit WHERE NOT EXISTS(SELECT * FROM payment WHERE paysplit.PayNum=payment.PayNum)"; int numFound=PIn.Int(Db.GetCount(command)); if(numFound>0 || verbose) { log+=Lans.g("FormDatabaseMaintenance","Paysplits found with invalid PayNum: ")+numFound+"\r\n"; } } else { if(DataConnection.DBtype==DatabaseType.Oracle) { return ""; } command="SELECT *,SUM(SplitAmt) SplitAmt_ FROM paysplit WHERE NOT EXISTS(SELECT * FROM payment WHERE paysplit.PayNum=payment.PayNum) GROUP BY PayNum"; DataTable table=Db.GetTable(command); if(table.Rows.Count>0 || verbose) { for(int i=0;i<table.Rows.Count;i++) { ///<summary>There's only one place in the program where this is called from. Date is today, so no need to validate the date.</summary> Payment payment=new Payment(); payment.PayType=DefC.Short[(int)DefCat.PaymentTypes][0].DefNum; payment.DateEntry=PIn.Date(table.Rows[i]["DateEntry"].ToString()); payment.PatNum=PIn.Long(table.Rows[i]["PatNum"].ToString()); payment.PayDate=PIn.Date(table.Rows[i]["DatePay"].ToString()); payment.PayAmt=PIn.Double(table.Rows[i]["SplitAmt_"].ToString()); payment.PayNote="Dummy payment. Original payment entry missing from the database."; payment.PayNum=PIn.Long(table.Rows[i]["PayNum"].ToString()); Payments.Insert(payment,true); } log+=Lans.g("FormDatabaseMaintenance","Paysplits found with invalid PayNum fixed: ")+table.Rows.Count+"\r\n"; } } return log; }
private void toolBarButPay_Click() { Payment PaymentCur=new Payment(); PaymentCur.PayDate=DateTimeOD.Today; PaymentCur.PatNum=PatCur.PatNum; PaymentCur.ClinicNum=PatCur.ClinicNum; PaymentCur.DateEntry=DateTimeOD.Today;//So that it will show properly in the new window. if(DefC.Short[(int)DefCat.PaymentTypes].Length>0){ PaymentCur.PayType=DefC.Short[(int)DefCat.PaymentTypes][0].DefNum; } Payments.Insert(PaymentCur); FormPayment FormPayment2=new FormPayment(PatCur,FamCur,PaymentCur); FormPayment2.IsNew=true; FormPayment2.ShowDialog(); ModuleSelected(PatCur.PatNum); }
///<summary>Helper method that shows the payment window if the user has the "Show provider income transfer window after entering insurance payment" preference enabled. ///This method should always be called after an insurance payment has been made.</summary> private void ShowProviderTransferWindow() { if(!PrefC.GetBool(PrefName.ProviderIncomeTransferShows)) { return; } Payment PaymentCur=new Payment(); PaymentCur.PayDate=DateTimeOD.Today; PaymentCur.PatNum=PatCur.PatNum; PaymentCur.ClinicNum=PatCur.ClinicNum; PaymentCur.PayType=0;//txfr PaymentCur.DateEntry=DateTimeOD.Today;//So that it will show properly in the new window. Payments.Insert(PaymentCur); FormPayment Formp=new FormPayment(PatCur,FamCur,PaymentCur); Formp.IsNew=true; Formp.ShowDialog(); }
/// <summary>Only Called only from FormPayment.butOK click. Only called if the user did not enter any splits. Usually just adds one split for the current patient. But if that would take the balance negative, then it loops through all other family members and creates splits for them. It might still take the current patient negative once all other family members are zeroed out.</summary> public static List <PaySplit> Allocate(Payment pay) //double amtTot,int patNum,Payment payNum){ { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { return(Meth.GetObject <List <PaySplit> >(MethodBase.GetCurrentMethod(), pay)); } string command = "SELECT Guarantor FROM patient " + "WHERE PatNum = " + POut.Long(pay.PatNum); DataTable table = Db.GetTable(command); if (table.Rows.Count == 0) { return(new List <PaySplit>()); } command = "SELECT patient.PatNum,EstBalance,PriProv,SUM(InsPayEst)+SUM(Writeoff) insEst_ " + "FROM patient " + "LEFT JOIN claimproc ON patient.PatNum=claimproc.PatNum " + "AND Status=0 " //NotReceived + "WHERE Guarantor = " + table.Rows[0][0].ToString() + " " + "GROUP BY patient.PatNum,EstBalance,PriProv"; //+" ORDER BY PatNum!="+POut.PInt(pay.PatNum);//puts current patient in position 0 //Oracle does not allow table = Db.GetTable(command); List <Patient> pats = new List <Patient>(); Patient pat; //first, put the current patient at position 0. for (int i = 0; i < table.Rows.Count; i++) { if (table.Rows[i]["PatNum"].ToString() == pay.PatNum.ToString()) { pat = new Patient(); pat.PatNum = PIn.Long(table.Rows[i][0].ToString()); pat.EstBalance = PIn.Double(table.Rows[i][1].ToString()); if (!PrefC.GetBool(PrefName.BalancesDontSubtractIns)) { pat.EstBalance -= PIn.Double(table.Rows[i]["insEst_"].ToString()); } pat.PriProv = PIn.Long(table.Rows[i][2].ToString()); pats.Add(pat.Copy()); } } //then, do all the rest of the patients. for (int i = 0; i < table.Rows.Count; i++) { if (table.Rows[i]["PatNum"].ToString() == pay.PatNum.ToString()) { continue; } pat = new Patient(); pat.PatNum = PIn.Long(table.Rows[i][0].ToString()); pat.EstBalance = PIn.Double(table.Rows[i][1].ToString()); if (!PrefC.GetBool(PrefName.BalancesDontSubtractIns)) { pat.EstBalance -= PIn.Double(table.Rows[i]["insEst_"].ToString()); } pat.PriProv = PIn.Long(table.Rows[i][2].ToString()); pats.Add(pat.Copy()); } //first calculate all the amounts double amtRemain = pay.PayAmt; //start off with the full amount double[] amtSplits = new double[pats.Count]; //loop through each family member, starting with current for (int i = 0; i < pats.Count; i++) { if (pats[i].EstBalance == 0 || pats[i].EstBalance < 0) { continue; //don't apply paysplits to anyone with a negative balance } if (amtRemain < pats[i].EstBalance) //entire remainder can be allocated to this patient { amtSplits[i] = amtRemain; amtRemain = 0; break; } else //amount remaining is more than or equal to the estBal for this family member { amtSplits[i] = pats[i].EstBalance; amtRemain -= pats[i].EstBalance; } } //add any remainder to the split for this patient amtSplits[0] += amtRemain; //now create a split for each non-zero amount PaySplit PaySplitCur; List <PaySplit> retVal = new List <PaySplit>(); for (int i = 0; i < pats.Count; i++) { if (amtSplits[i] == 0) { continue; } PaySplitCur = new PaySplit(); PaySplitCur.PatNum = pats[i].PatNum; PaySplitCur.PayNum = pay.PayNum; PaySplitCur.DatePay = pay.PayDate; PaySplitCur.ClinicNum = pay.ClinicNum; PaySplitCur.ProvNum = Patients.GetProvNum(pats[i]); PaySplitCur.SplitAmt = Math.Round(amtSplits[i], CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalDigits); //PaySplitCur.InsertOrUpdate(true); retVal.Add(PaySplitCur); } //finally, adjust each EstBalance, but no need to do current patient //This no longer works here. Must do it when closing payment window somehow /*for(int i=1;i<pats.Length;i++){ * if(amtSplits[i]==0){ * continue; * } * command="UPDATE patient SET EstBalance=EstBalance-"+POut.PDouble(amtSplits[i]) +" WHERE PatNum="+POut.PInt(pats[i].PatNum); * Db.NonQ(command); * }*/ return(retVal); }