///<summary>Updates the splits on the journal entries whose indexes are passed in.</summary> ///<param name="listJournalEntries">All journal entries for a particular account.</param> ///<param name="listIndexesForTrans">The index of the journal entries in listJournalEntries. These are the ones that will be updated.</param> ///<param name="dictJournalEntryDescriptions">A dictionary where the key is the JournalEntryNum and the value is the journal entry's ///account description.</param> ///<param name="acct">The account that whose description is being updates.</param> private static void UpdateJournalEntrySplits(List <JournalEntry> listJournalEntries, List <int> listIndexesForTrans, Dictionary <long, string> dictJournalEntryDescriptions, Account acct) { //No need to check RemotingRole; no call to db. foreach (int index in listIndexesForTrans.Where(x => listJournalEntries[x].AccountNum != acct.AccountNum)) { JournalEntry journalEntry = listJournalEntries[index]; if (listIndexesForTrans.Count <= 2) { //When a transaction only has two splits, the Splits column will simply be the name of the account of the other split. journalEntry.Splits = acct.Description; } else { //When a transaction has three or more splits, the Splits column will be the names of the account and the amount of the other splits. //Ex.: //Patient Fee Income 85.00 //Supplies 110.00 journalEntry.Splits = string.Join("\r\n", listIndexesForTrans .Where(x => listJournalEntries[x].JournalEntryNum != journalEntry.JournalEntryNum) .Select(x => dictJournalEntryDescriptions[listJournalEntries[x].JournalEntryNum] + " " + (listJournalEntries[x].DebitAmt > 0 ? listJournalEntries[x].DebitAmt.ToString("n") : listJournalEntries[x].CreditAmt.ToString("n")))); } JournalEntries.Update(journalEntry); } }
///<summary>Only called once from FormPayment when trying to change an amount or an account on a payment that's already linked to the Accounting section or when trying to create a new link. This automates updating the Accounting section. Do not surround with try-catch, because it was already validated in ValidateLinkedEntries above. Use -1 for newAcct to indicate no changed. The name is required to give descriptions to new entries.</summary> public static void AlterLinkedEntries(double oldAmt, double newAmt, bool isNew, long payNum, long newAcct, DateTime payDate, string patName) { //No need to check RemotingRole; no call to db. if (!Accounts.PaymentsLinked()) { return; //user has not even set up accounting links. } bool amtChanged = false; if (oldAmt != newAmt) { amtChanged = true; } Transaction trans = Transactions.GetAttachedToPayment(payNum); //this gives us the oldAcctNum double absNew = newAmt; //absolute value of the new amount if (newAmt < 0) { absNew = -newAmt; } //if(trans==null && (newAcct==0 || newAcct==-1)) {//then this method will not even be called if (trans == null) //no previous link, but user is trying to create one. //this is the only case where a new trans is required. { trans = new Transaction(); trans.PayNum = payNum; trans.UserNum = Security.CurUser.UserNum; Transactions.Insert(trans); //sets entry date //first the deposit entry JournalEntry je = new JournalEntry(); je.AccountNum = newAcct; //DepositAccounts[comboDepositAccount.SelectedIndex]; je.CheckNumber = Lans.g("Payments", "DEP"); je.DateDisplayed = payDate; //it would be nice to add security here. if (absNew == newAmt) //amount is positive { je.DebitAmt = newAmt; } else { je.CreditAmt = absNew; } je.Memo = Lans.g("Payments", "Payment -") + " " + patName; je.Splits = Accounts.GetDescript(PrefC.GetLong(PrefName.AccountingCashIncomeAccount)); je.TransactionNum = trans.TransactionNum; JournalEntries.Insert(je); //then, the income entry je = new JournalEntry(); je.AccountNum = PrefC.GetLong(PrefName.AccountingCashIncomeAccount); //je.CheckNumber=; je.DateDisplayed = payDate; //it would be nice to add security here. if (absNew == newAmt) //amount is positive { je.CreditAmt = newAmt; } else { je.DebitAmt = absNew; } je.Memo = Lans.g("Payments", "Payment -") + " " + patName; je.Splits = Accounts.GetDescript(newAcct); je.TransactionNum = trans.TransactionNum; JournalEntries.Insert(je); return; } //at this point, we have established that there is a previous transaction. List <JournalEntry> jeL = JournalEntries.GetForTrans(trans.TransactionNum); long oldAcct = 0; JournalEntry jeDebit = null; JournalEntry jeCredit = null; bool signChanged = false; double absOld = oldAmt;//the absolute value of the old amount if (oldAmt < 0) { absOld = -oldAmt; } if (oldAmt < 0 && newAmt > 0) { signChanged = true; } if (oldAmt > 0 && newAmt < 0) { signChanged = true; } for (int i = 0; i < 2; i++) { if (Accounts.GetAccount(jeL[i].AccountNum).AcctType == AccountType.Asset) { oldAcct = jeL[i].AccountNum; } if (jeL[i].DebitAmt == absOld) { jeDebit = jeL[i]; } //old credit entry if (jeL[i].CreditAmt == absOld) { jeCredit = jeL[i]; } } //Already validated that both je's are not null, and that oldAcct is not 0. if (newAcct == 0) //detaching it from a linked transaction. We will delete the transaction //we don't care about the amount { Transactions.Delete(trans); //we need to make sure this doesn't throw any exceptions by carefully checking all //possibilities in the validation routine above. return; } //Either the amount or the account changed on an existing linked transaction. bool acctChanged = false; if (newAcct != -1 && oldAcct != newAcct) { acctChanged = true; //changing linked acctNum } if (amtChanged) { if (signChanged) { jeDebit.DebitAmt = 0; jeDebit.CreditAmt = absNew; jeCredit.DebitAmt = absNew; jeCredit.CreditAmt = 0; } else { jeDebit.DebitAmt = absNew; jeCredit.CreditAmt = absNew; } } if (acctChanged) { if (jeDebit.AccountNum == oldAcct) { jeDebit.AccountNum = newAcct; } if (jeCredit.AccountNum == oldAcct) { jeCredit.AccountNum = newAcct; } } JournalEntries.Update(jeDebit); JournalEntries.Update(jeCredit); }
///<summary>This does all the validation before calling AlterLinkedEntries. It had to be separated like this because of the complexity of saving a payment. Surround with try-catch. Will throw an exception if user is trying to change, but not allowed. Will return false if no synch with accounting is needed. Use -1 for newAcct to indicate no change.</summary> public static bool ValidateLinkedEntries(double oldAmt, double newAmt, bool isNew, long payNum, long newAcct) { //No need to check RemotingRole; no call to db. if (!Accounts.PaymentsLinked()) { return(false); //user has not even set up accounting links, so no need to check any of this. } bool amtChanged = false; if (oldAmt != newAmt) { amtChanged = true; } Transaction trans = Transactions.GetAttachedToPayment(payNum); //this gives us the oldAcctNum if (trans == null && (newAcct == 0 || newAcct == -1)) //if there was no previous link, and there is no attempt to create a link { return(false); //no synch needed } if (trans == null) //no previous link, but user is trying to create one. newAcct>0. { return(true); //new transaction will be required } //at this point, we have established that there is a previous transaction. //If payment is attached to a transaction which is more than 48 hours old, then not allowed to change. if (amtChanged && trans.DateTimeEntry < MiscData.GetNowDateTime().AddDays(-2)) { throw new ApplicationException(Lans.g("Payments", "Not allowed to change amount that is more than 48 hours old. This payment is already attached to an accounting transaction. You will need to detach it from within the accounting section of the program.")); } if (amtChanged && Transactions.IsReconciled(trans)) { throw new ApplicationException(Lans.g("Payments", "Not allowed to change amount. This payment is attached to an accounting transaction that has been reconciled. You will need to detach it from within the accounting section of the program.")); } List <JournalEntry> jeL = JournalEntries.GetForTrans(trans.TransactionNum); long oldAcct = 0; JournalEntry jeDebit = null; JournalEntry jeCredit = null; double absOld = oldAmt;//the absolute value of the old amount if (oldAmt < 0) { absOld = -oldAmt; } for (int i = 0; i < jeL.Count; i++) //we make sure down below that this count is exactly 2. { if (Accounts.GetAccount(jeL[i].AccountNum).AcctType == AccountType.Asset) { oldAcct = jeL[i].AccountNum; } if (jeL[i].DebitAmt == absOld) { jeDebit = jeL[i]; } //old credit entry if (jeL[i].CreditAmt == absOld) { jeCredit = jeL[i]; } } if (jeCredit == null || jeDebit == null) { throw new ApplicationException(Lans.g("Payments", "Not able to automatically make changes in the accounting section to match the change made here. You will need to detach it from within the accounting section.")); } if (oldAcct == 0) //something must have gone wrong. But this should never happen { throw new ApplicationException(Lans.g("Payments", "Could not locate linked transaction. You will need to detach it manually from within the accounting section of the program.")); } if (newAcct == 0) //detaching it from a linked transaction. //We will delete the transaction { return(true); } bool acctChanged = false; if (newAcct != -1 && oldAcct != newAcct) { acctChanged = true; //changing linked acctNum } if (!amtChanged && !acctChanged) { return(false); //no changes being made to amount or account, so no synch required. } if (jeL.Count != 2) { throw new ApplicationException(Lans.g("Payments", "Not able to automatically change the amount in the accounting section to match the change made here. You will need to detach it from within the accounting section.")); } //Amount or account changed on an existing linked transaction. return(true); }