Accounting Software
Small Business Software Estimating Software
Inventory SoftwareInventory Tracking SoftwareInventory Control SoftwareInventory Management SoftwareConstruction Management SoftwareProject Management SoftwareBusiness Management Software

Bank Transactions (Source Code 3)

Link to: header | source 1 | source 2 | transactions directory

Copyright Turtle Creek Software 1996-2006. All Rights Reserved.

Source Code

This class manages bank transactions for the Goldenseal accounting software,
small business management software, construction project management software and
construction accounting software.

/*********************************************************************************

GetIncomeAmount TCS 4/26/01

return the amount of net income.

*********************************************************************************/
CMoney CBankTransaction::GetIncomeAmount() const
{
if (HasVoidStatus()) // TCS 6/20/00
return 0;
else if (mTransactionType == id_BankDeposit || mTransactionType == id_BankTransferIn)
{
if (DB_ClassDescriptor::IsBankAccount(mMainAccountClass))
return 0; // we skip transfers rev TCS 12/16/03
else
return GetAmount();
}
else
return 0;
}
/*********************************************************************************

GetCostAmount TCS 12/16/03

return the amount of expense being paid.

*********************************************************************************/
CMoney CBankTransaction::GetCostAmount() const
{
if (HasVoidStatus())
return 0;
else if (mTransactionType != id_BankDeposit && mTransactionType != id_BankTransferIn)
{
if (DB_ClassDescriptor::IsBankAccount(mMainAccountClass))
return 0; // we skip transfers rev TCS 12/16/03
else
return GetAmount();
}
else
return 0;
}
/*********************************************************************************

GetTransferAmount TCS 12/16/03

return the amount of money for a transfer between accounts. This actually
includes all types of transactions as long as they're paid to a bank account.

*********************************************************************************/
CMoney CBankTransaction::GetTransferAmount() const
{
if (HasVoidStatus())
return 0;
else if (DB_ClassDescriptor::IsBankAccount(mMainAccountClass))
{
if (mTransactionType == id_BankDeposit || mTransactionType == id_BankTransferIn)
return GetAmount(); // transfer in
else
return -GetAmount(); // transfer out
}
else
return 0;
}
/*********************************************************************************

GetEnumMenuID TCS 6/11/00

return the id of the menu used for the given tag. We override since some
menus vary depending on the transaction type.

*********************************************************************************/
ResIDT CBankTransaction::GetEnumMenuID(const TagType tag, const Boolean importing) const
{
if (tag == tag_mainaccountclass)
{
switch (mTransactionType)
{
case id_BankCheck:
case id_BankPayment:
return MENU_BankCheckAccountTypes;
break;

case id_BankDeposit:
return MENU_BankDepositAccountTypes;
break;

case id_BankTransferIn:
return MENU_BankTransferInAccountTypes;
break;

case id_BankTransferOut:
return MENU_BankTransferOutAccountTypes;
break;

default:
if (importing) // we must not know the transaction type yet
return MENU_AllBankAccountTypes; // rev TCS 4/11/01
else
{
TCS_DebugAlert("Oops, bad value in CBankTransaction::GetEnumMenuID!");
return MENU_BankCheckAccountTypes;
}
break;
}
}
else if (tag == tag_transactionrefclass) // TCS 9/4/01
{
switch (mTransactionType)
{
case id_BankCheck:
case id_BankPayment:
return MENU_BankPaymentTransTypes;
break;

case id_BankDeposit:
return MENU_BankDepositTransTypes;
break;

case id_BankTransferIn:
case id_BankTransferOut:
return MENU_BankTransferTransTypes;
break;

default:
if (importing) // we must not know the transaction type yet
return MENU_IOTransactionTypes;
else
{
TCS_DebugAlert("Oops, bad value in CBankTransaction::GetEnumMenuID!");
return MENU_BankCheckAccountTypes;
}
break;
}
}
else // for other field tags we can just pass it along
return THE_SUPERCLASS::GetEnumMenuID(tag, importing);
}
/*********************************************************************************

GetAmountPaidOnAccount TCS 2/13/01

get the amount paid on account from this transaction.
*********************************************************************************/
CMoney CBankTransaction::GetAmountPaidOnAccount() const
{
if (mTransactionRefClass == condition_OnAccount)
return mAmount;
else if (GetVersion() > 1)
return mPaidOnAccount;
else
return 0;
}
/*********************************************************************************

GetBankAccountForTrans (static)

return the bank account class ID for a transaction class

*********************************************************************************/
DBid CBankTransaction::GetBankAccountForTrans(const DBid transactionClass)
{
switch (transactionClass)
{
case id_CheckingTransaction:
return id_CheckingAccount;
break;

case id_CashTransaction:
return id_CashAccount;
break;

case id_InvestmentTransaction:
return id_InvestmentAccount;
break;

case id_SavingsTransaction:
return id_SavingsAccount;
break;

case id_CreditCardTransaction:
return id_CreditCardAccount;
break;

case id_LoanTransaction:
return id_LoanAccount;
break;

case id_EscrowTransaction:
return id_EscrowAccount;
break;

default:
TCS_DebugAlert("Oops, invalid request to GetBankAccountClass!");
return 0;
break;
}
}
/*********************************************************************************

GetBankTransForAccount (static)

return the bank account class ID for a transaction class

*********************************************************************************/
DBid CBankTransaction::GetBankTransForAccount(const DBid accountClass)
{
switch (accountClass)
{
case id_CheckingAccount:
return id_CheckingTransaction;
break;

case id_CashAccount:
return id_CashTransaction;
break;

case id_InvestmentAccount:
return id_InvestmentTransaction;
break;

case id_SavingsAccount:
return id_SavingsTransaction;
break;

case id_CreditCardAccount:
return id_CreditCardTransaction;
break;

case id_LoanAccount:
return id_LoanTransaction;
break;

case id_EscrowAccount:
return id_EscrowTransaction;
break;

default:
TCS_DebugAlert("Oops, invalid request to CBankTransaction::GetBankTransForAccount!");
return 0;
break;
}
}
/*********************************************************************************

GetIncomeTaxID (static) TCS 10/21/02

return the income tax class for the given account class & trans type.

*********************************************************************************/
DBid CBankTransaction::GetIncomeTaxID(const UInt8 mainAccountClass, const DBid mainAccount,
const UInt8 transType, const UInt8 status)
{
UInt8 taxClass = 0;

if (status == status_Void || status == status_Planned)
{
taxClass = tax_void;
}
else if (transType == id_BankTransferIn) // TRANSFERS IN
{
if (DB_ClassDescriptor::IsBankAccount(mainAccountClass))
taxClass = tax_transfersin;
else if (mainAccountClass == condition_InterestIn) // rev TCS 11/12/02
taxClass = tax_interestincome;
else
taxClass = tax_bankincome;
}
else if (transType == id_BankTransferOut) // TRANSFERS OUT
{
if (mainAccountClass == id_LoanAccount) // TCS 4/9/04
taxClass = tax_loanpayments;
else if (mainAccountClass == id_CreditCardAccount)
taxClass = tax_creditcardpayments;
else if (DB_ClassDescriptor::IsBankAccount(mainAccountClass))
taxClass = tax_transfersout;
else if (mainAccountClass == condition_InterestOut)
taxClass = tax_interestexpense;
else
taxClass = tax_bankfees;
}
else if (transType == id_BankDeposit) // DEPOSITS
{
switch (mainAccountClass)
{
case id_MaterialAccount: // TCS 4/9/04
case id_SubcontractorAccount:
case id_OtherCostAccount:
{
DB_PersistentObject *account = gDBFile->GetOneObject(mainAccountClass, mainAccount);
if (account)
{
DB_ObjectWatcher watcher (account);
DBid taxCategory = account->GetTaxClass();

// if the account has a tax category, return it
if (taxCategory)
return taxCategory;
}

// if we get this far, we use the default value
taxClass = tax_vendorcredit;
}
break;

case id_EmployeeAccount:
taxClass = tax_vendorcredit;
break;

case id_CustomerAccount:
case filter_cashsalesbydate:
case filter_cashsalesbybranch:
case filter_billedsales:
taxClass = tax_salesincome;
break;

case id_ProjectAccount:
case filter_billedprojects:
taxClass = tax_projectincome;
break;

case id_Lease:
case filter_rentals:
taxClass = tax_rentalincome;
break;

case id_EscrowAccount:
taxClass = tax_escrowincome;
break;

case id_Owner:
taxClass = tax_ownerinvest;
break;

case filter_paymentsreceived:
default:
taxClass = tax_miscincome;
break;
}
}
else // CHECKS and PAYMENTS
{
switch (mainAccountClass)
{
case id_MaterialAccount:
case id_SubcontractorAccount:
case id_OtherCostAccount:
{
DB_PersistentObject *account = gDBFile->GetOneObject(mainAccountClass, mainAccount);
if (account)
{
DB_ObjectWatcher watcher (account);
DBid taxCategory = account->GetTaxClass();

// if the account has a tax category, return it
if (taxCategory)
return taxCategory;
}

// if we get this far, we use the default values
if (mainAccountClass == id_MaterialAccount)
taxClass = tax_materials;
else if (mainAccountClass == id_SubcontractorAccount)
taxClass = tax_subs;
else
taxClass = tax_othercost;
}
break;

case id_EmployeeAccount:
taxClass = tax_payroll;
break;

case id_CustomerAccount:
taxClass = tax_salesreturns;
break;

case id_ProjectAccount:
taxClass = tax_projectreturns;
break;

case id_Lease:
taxClass = tax_rentalreturns;
break;

case id_EscrowAccount:
taxClass = tax_escrowpayments;
break;

case id_Owner:
taxClass = tax_ownerdraw;
break;

case id_LoanAccount: // TCS 4/9/04
taxClass = tax_loanpayments;
break;

case id_CreditCardAccount:
taxClass = tax_creditcardpayments;
break;

case id_CheckingAccount: // TCS 4/9/04
case id_SavingsAccount:
case id_InvestmentAccount:
case id_CashAccount:
taxClass = tax_transfersout;
break;

default:
taxClass = tax_miscexpense;
break;
}
}

if (!taxClass)
taxClass = tax_nontaxable;

return -taxClass; // we return negative for non object ID's, so
// the report can distinguish values
}
/*********************************************************************************

GetIncomeTaxClass (static) TCS 10/21/02

return the income tax class for the given account class & trans type.
We make this static since the viewer also calls it.

*********************************************************************************/
CTextString CBankTransaction::GetIncomeTaxClass(const UInt8 mainAccountClass, const DBid mainAccount,
const UInt8 transType, const UInt8 status)
{
UInt8 taxClass = 0;

if ((transType == id_BankCheck || transType == id_BankPayment) &&
(mainAccountClass == id_MaterialAccount || mainAccountClass == id_SubcontractorAccount ||
mainAccountClass == id_OtherCostAccount ))
{
DB_PersistentObject *account = gDBFile->GetOneObject(mainAccountClass, mainAccount);
if (account)
{
DB_ObjectWatcher watcher (account);
DBid taxCategory = account->GetTaxClass();

// if the account has a tax category, return its name
if (taxCategory)
return gDBFile->GetObjectName(id_Category, taxCategory);
}

// if we get this far, we use the default values
if (mainAccountClass == id_MaterialAccount)
taxClass = tax_materials;
else if (mainAccountClass == id_SubcontractorAccount)
taxClass = tax_subs;
else
taxClass = tax_othercost;
}
else
{
SInt32 invertClass = GetIncomeTaxID(mainAccountClass, mainAccount, transType, status);
taxClass = -invertClass;
}

if (!taxClass)
taxClass = tax_nontaxable;

CTextString outString;
TCS_GetEnumItemName(MENU_TaxClasses, taxClass, &outString);
return outString;
}
/*********************************************************************************

GetMICRText TCS 10/1/03

return the MICR text to put at the bottom of the check. We fetch the
basics from the account, and then append the check number.

*********************************************************************************/
CTextString CBankTransaction::GetMICRText() const
{
CTextString outString;

DB_Account *account =
TCS_SAFE_CAST(gDBFile->GetOneObject(GetBankAccountClass(), mBankAccount),
DB_Account);
if (account)
{
DB_ObjectWatcher watcher (account);
outString = account->GetMICRText();
}

SInt32 checkNumber = GetRefNum();

if (outString.Length() && checkNumber)
{
CTextString numberString = CTextString(checkNumber);
outString.AppendWithSpace(numberString);
}

return outString;
}
/*********************************************************************************

GetCompanyDivision TCS 4/10/04

return the company division. We fetch it from the bank account.

*********************************************************************************/
DBid CBankTransaction::GetCompanyDivision() const
{
DB_Account *account = TCS_SAFE_CAST(gDBFile->GetOneObject(GetBankAccountClass(), mBankAccount),
DB_Account);
if (account)
{
// we just fetch these from the bank account
DB_ObjectWatcher bankWatcher (account);
return account->GetCompanyDivision();
}
else
return 0;
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

AddBreakdownsToCheck

add breakdowns from the given vendor info
*********************************************************************************/
void CBankTransaction::AddBreakdownsToCheck(const SVendorInfo &vendorInfo)
{
// sanity check
TCS_FailNILMsg(vendorInfo.purchaseArray, TCS_GetErrString(errID_BadArray));
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));

// remove this obj from database, since filelength may change
DB_ObjectTempRemover remover (this); // TCS 8/26/03

if (!remover.WasRemoved())
return;

CMoney amount = 0;

// if there are already breakdowns, remove them
TCS_TRY
{
if (GetBreakdownCount())
{
RemoveAllBreakdownEntries();
}

if (vendorInfo.purchaseArray->GetCount() > 0)
{
// fetch some basic info
DBid ownerID = GetDBID();
UInt8 ownerClass = GetDBClassID();
// UInt8 transactionClass = DB_ClassDescriptor::GetCostTransaction(vendorInfo.classID);

// walk through the items in the purchase item array
CTmplArrayIterator<SPurchaseInfo> iterator(*(vendorInfo.purchaseArray));
SPurchaseInfo itemInfo;
CPurchaseBreakdownEntry *entry = nil;

while (iterator.Next(itemInfo))
{
// we now skip items that are not checked TCS 10/24/01
if (!itemInfo.pay)
continue;

// create a breakdown entry rev TCS 10/14/99
entry = TCS_SAFE_CAST(gDBFile->CreateObjectFromID(id_PurchaseBreakdownEntry,
flag_dontautoname), CPurchaseBreakdownEntry);
TCS_FailNILMsg(entry, TCS_GetErrString(errID_BadObject));
DB_ObjectWatcher entryWatcher(entry);

// set some basic values
entry->SetMemberValue(tag_ownerobject, type_objectid, &ownerID);
entry->SetMemberValue(tag_ownerobjectclass, type_objclass, &ownerClass);
if (itemInfo.id == cPayOnAccountFlag) // TCS rev 12/13/99
entry->SetTransactionType(condition_OnAccount);
else if (itemInfo.id == cWCDeduction) // TCS bugfix 2/28/02
entry->SetTransactionType(condition_WCDeduct);
else if (itemInfo.id == cLiabilityDeduction) // TCS bugfix 2/28/02
entry->SetTransactionType(condition_LiabilityDeduct);
else
entry->SetTransactionType(itemInfo.classID); // rev TCS 3/13/02

entry->SetCreationType(record_fromprocess); // TCS 6/25/03

// now fill in data from the struct
Boolean payIt = itemInfo.pay;
entry->SetMemberValue(tag_pay, type_boolean, &payIt);
entry->SetMemberValue(tag_pending, type_money, &itemInfo.pendingAmount);
entry->SetMemberValue(tag_current, type_money, &itemInfo.currentAmount);
entry->SetMemberValue(tag_adjustment, type_money, &itemInfo.adjustAmount);
entry->SetMemberValue(tag_pastdue, type_money, &itemInfo.overdueAmount);
entry->SetMemberValue(tag_amount, type_money, &itemInfo.payingAmount);
entry->SetMemberValue(tag_transactid, type_objectid, &itemInfo.id);

// get running total TCS 6/3/02
amount += itemInfo.payingAmount;

// we now store info about the vendor TCS 3/29/00
entry->SetMemberValue(tag_mainaccountclass, type_objclass, &vendorInfo.classID);
entry->SetMemberValue(tag_mainaccount, type_objectid, &vendorInfo.id);

// allow the object to do any final setup. Not really needed
// but we have it here for consistency TCS 5/5/03
entry->FinishNonViewerCreate();
// finally, add the entry to the db...
gDBFile->AddObject(entry);

// ...and to the check
AddBreakdown(entry->GetDBID());

// we used to post breakdown creation here, but that should NOT be done-
// it is already handled later when the payment is posted TCS 3/9/00
//entry->PostNewRecord(record_fromprocess);
}
}
}
TCS_CATCH {}

SetAmount(amount); // TCS 6/3/02

MakeDirty();
}
/*********************************************************************************

WriteToPrintFormTable TCS 1/23/00

write breakdowns to a report table (in print forms). We override since
we fetch payroll info for some reports from a different place
*********************************************************************************/
Boolean CBankTransaction::WriteToPrintFormTable(CReportTable *table)
{
// sanity check
TCS_FailNILMsg(table, TCS_GetErrString(errID_BadTable));
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));

// the array we write depends on the table's display class
switch (table->GetReportClassID())
{
// we must fetch payroll tables from the pay transaction
case id_WagesBreakdownEntry:
case id_CommishBreakdownEntry:
case id_DeductBreakdownEntry:
case id_CatTaxBreakdownEntry:
case id_EmpTaxBreakdownEntry:
case id_BennyBreakdownEntry:
case id_VacBreakdownEntry:
if (mBreakdownType == breakdown_payrollrecord) // TCS 12/26/01
{
TObjectIDArrayIterator iterator(mBreakdownArray);
DBid breakdownID, recordID;
CTransactionBreakdownEntry *entry;

while (iterator.Next(breakdownID))
{
entry =
TCS_SAFE_CAST(gDBFile->GetOneObject(id_PayRecordBreakdownEntry, breakdownID),
CTransactionBreakdownEntry);

if (entry)
{
DB_ObjectWatcher entryWatcher(entry);

recordID = entry->GetTransactionID();

CPayrollRecord *record =
TCS_SAFE_CAST(gDBFile->GetOneObject(id_PayrollRecord, recordID),
CPayrollRecord);
if (record)
{
DB_ObjectWatcher watcher(record);
if (record->WriteToPrintFormTable(table))
return true;
}
}
}
}
else if (mTransactionRefClass == id_PayrollRecord && mTransactionRef)
{
CPayrollRecord *record =
TCS_SAFE_CAST(gDBFile->GetOneObject(id_PayrollRecord, mTransactionRef),
CPayrollRecord);
if (record)
{
DB_ObjectWatcher recordWatcher(record);
return record->WriteToPrintFormTable(table);
}
}
break;

// other breakdown tables are handled normally
default:
return THE_SUPERCLASS::WriteToPrintFormTable(table);
break;
}

// if we get this far, we didn't fill in a table
return false;
}
/*********************************************************************************

FinishBreakdownUpdate TCS 5/3/00

we override to fill in the main account if it's a purchase breakdown
*********************************************************************************/
void CBankTransaction::FinishBreakdownUpdate(CBreakdownEntry *breakdown, CBreakdownTable */*table*/)
{
TCS_FailNILMsg(breakdown, TCS_GetErrString(errID_BadBreakdown));

DBid entryClass = breakdown->GetDBClassID();

if (entryClass == id_PurchaseBreakdownEntry)
{
TCS_ASSERTMsg(breakdown->SetMemberValue(tag_mainaccount, type_objectid, &mMainAccount),
TCS_SetValueErrString(tag_mainaccount));
TCS_ASSERTMsg(breakdown->SetMemberValue(tag_mainaccountclass, type_objclass, &mMainAccountClass),
TCS_SetValueErrString(tag_mainaccountclass));
}
}
/*********************************************************************************

CanImportEnum TCS 6/13/99

is the given imported value OK?

*********************************************************************************/
Boolean CBankTransaction::CanImportEnum(const TagType tag, const SInt32 value) const
{
if (tag == tag_checkbook) // TCS rev 4/25/01
{
// checkbook field. we could possibly check the account, but we
// may not have enough info yet to find it.
return true;
}
else if (!mTransactionType) // TCS 4/25/01
{
// we're getting values that may depend on the transaction type, before we
// know what the transaction type is. We'll accept all values now since we don't
// know which menu to use for checking values. VerifyImport will catch any duds, later on.
switch (tag)
{
case tag_mainaccountclass:
case tag_transactionrefclass: // rev TCS 9/7/01
return true;
break;

default:
break;
}
}

// if we get this far, we pass it along for generic testing
return THE_SUPERCLASS::CanImportEnum(tag, value);
}
/*********************************************************************************

NeedsJobAccountValue TCS 10/24/00

return whether the job account must be filled in. We require it if
prefs say so

*********************************************************************************/
Boolean CBankTransaction::NeedsJobAccountValue() const
{
return GetPrefsBoolean(id_DataPrefs, tag_requirejobaccount);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
CreateOffsetTransaction TCS 7/9/99
create a bank transaction to offset a transfer between accounts
*********************************************************************************/
void CBankTransaction::CreateOffsetTransaction(const DBClass transferClass)
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));

// rev TCS 4/30/01. Removed call to UpdateOffsetTransaction since it adds
// potential for infinite loops.

if (mTransactionRef && WasJustImported())
{
// importing, so we'll trust that the offset transact will arrive later
}
else
{
// create an offsetting transaction
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
DBid bankTransClass = CBankTransaction::GetBankTransForAccount(mMainAccountClass);
TCS_ASSERTMsg(DB_ClassDescriptor::IsBankTransaction(bankTransClass),
TCS_GetErrString(errID_BadClass));

CBankTransaction *bankTrans = nil;

SInt32 flags = flag_dontautoname;
bankTrans= TCS_SAFE_CAST(gDBFile->CreateObjectFromID(bankTransClass,
flags), CBankTransaction);
TCS_FailNILMsg(bankTrans, TCS_GetErrString(errID_BadTransaction));
DB_ObjectWatcher checkWatcher(bankTrans);

// fill in values
bankTrans->SetBankAccountID(mMainAccount);
bankTrans->SetTransactionType(transferClass);

bankTrans->SetMainAccountID(mBankAccount);
bankTrans->SetMainAccountClass(GetBankAccountClass());

bankTrans->SetStatus(status_AutoTransfer); // TCS 4/17/01

bankTrans->SetAmount(mAmount);

bankTrans->SetCreationType(record_autotransfer); // TCS 2/14/01

// fill in misc values from here TCS 5/8/01
bankTrans->SetConditions(mConditions);
bankTrans->SetJob(mJob);
bankTrans->SetJobClass(mJobClass);
bankTrans->SetCategory(mCategory);

// set flags for transfer link, so we know which TCS 4/30/01
// is the creator and which is the linked item
bankTrans->SetIsAutoTransfer(true);
SetHasAutoTransfer(true);

// finish any other creation details TCS 10/21/99
bankTrans->FinishNonViewerCreate();

// set the date (must be after FinishNonViewerCreate!)
bankTrans->SetDate(mDate); // TCS 12/3/00 moved 3/26/03

// add the offsetting transaction to the database.
gDBFile->AddNewTransaction(bankTrans);

// store transaction cross references
mTransactionRef = bankTrans->GetDBID();
mTransactionRefClass = bankTrans->GetDBClassID();

bankTrans->SetTransactionRef(GetDBID());
bankTrans->SetTransactionRefClass(GetDBClassID()); // rev TCS 5/23/00, 6/21/00

// mark both objects as dirty
bankTrans->MakeDirty();
MakeDirty();

// let the list know its found records may be out of whack TCS 10/24/00
DB_ListManager::SetChangedRemotely(bankTransClass);

// post the object creation TCS 5/19/00
bankTrans->PostNewRecord(record_autotransfer);

// save everything so the viewer won't open as dirty TCS 10/25/00
gDBFile->SaveAllChanges();

if (bankTransClass != GetDBClassID()) // rev TCS 10/20/00
{
// transfer to another class, so update its remote display TCS 3/21/00
bankTrans->UpdateViewerDisplay(save_success, cUpdateRecordCount);

LWindow *frontWindow = DB_WindowManager::GetFrontWindow();

// show the bank transaction window TCS 10/25/00 rev 3/5/01
DB_Editor::ShowBankEditorWindow(bankTransClass, bankTrans, mMainAccount);

// we used to do a viewer update here, but TCS remove that 12/22/00

// put this class's editor window in front
if (frontWindow)
frontWindow->Select();
}

// update running total TCS 7/31/99
// removed 10/21/99 now handled by FinishNonViewerCreate
//bankTrans->UpdateRunningTotals(false);
}
}
/*********************************************************************************

CancelOffsetTransaction TCS 7/9/99 rewrite 12/7/99

void out an offsetting bank transaction
*********************************************************************************/
void CBankTransaction::CancelOffsetTransaction(const UInt8 cancelType)
{
if (mTransactionRef)
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
DBid bankTransClass = CBankTransaction::GetBankTransForAccount(mMainAccountClass);
TCS_ASSERTMsg(DB_ClassDescriptor::IsBankTransaction(bankTransClass),
TCS_GetErrString(errID_BadClass));

CBankTransaction *transfer =
TCS_SAFE_CAST(gDBFile->GetOneObject(bankTransClass, mTransactionRef),
CBankTransaction);
if (transfer)
{
DB_ObjectWatcher watcher(transfer);

// prepare to update TCS 8/22/00 rev TCS 10/23/00
UInt8 saveType = transfer->PrepareViewerDisplay();

if (cancelType == record_deleteactive || cancelType == record_deletejobcost ||
cancelType == record_deletevoid)
{
transfer->SetStatus(status_Cancelled);
transfer->SetAmount(0);

// clear the reference to this trans
transfer->SetTransactionRef(0);
}
else
{
transfer->SetStatus(status_Cancelled); // rev TCS 4/17/01
transfer->SetAmount(mAmount);
transfer->SetConditions(mConditions);
}

transfer->UpdateRunningTotals(); // TCS 4/30/01

transfer->MakeDirty();

// update the display TCS 3/21/00
transfer->UpdateViewerDisplay(saveType);
}
}
}
/*********************************************************************************

UpdateOffsetTransaction TCS 7/31/99

update values in an offsetting bank transfer
*********************************************************************************/
void CBankTransaction::UpdateOffsetTransaction(const DBClass transferClass, const CMoney &amount,
const UInt8 conditions)
{
// if this is the passive end of a transfer, don't do anything. TCS 4/30/01
UInt8 status = GetStatus();
if (status == status_AutoTransfer || status == status_Cancelled)
return;

// it's a transfer. Do we already have a compensating transaction?
if (mTransactionRef)
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
DBid bankTransClass = CBankTransaction::GetBankTransForAccount(mMainAccountClass);
TCS_ASSERTMsg(DB_ClassDescriptor::IsBankTransaction(bankTransClass),
TCS_GetErrString(errID_BadClass));

CBankTransaction *transfer =
TCS_SAFE_CAST(gDBFile->GetOneObject(bankTransClass, mTransactionRef),
CBankTransaction);
if (transfer)
{
DB_ObjectWatcher watcher(transfer);

// prepare to update TCS 8/22/00 rev TCS 10/23/00
UInt8 saveType = transfer->PrepareViewerDisplay();

transfer->SetStatus(status_AutoTransfer); // TCS 4/30/01

transfer->SetConditions(conditions);
transfer->SetAmount(amount);

transfer->UpdateRunningTotals(); // TCS 4/30/01

transfer->MakeDirty();

// update the display TCS 3/21/00
transfer->UpdateViewerDisplay(saveType);

return;
}
}

// if we got this far, we need to make an offset transfer TCS 4/30/01
CreateOffsetTransaction(transferClass);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

FillCheckbookNumber TCS 10/21/99 rev 10/13/00

fetch the next checkbook number and fill it in. We don't increment the
number here- that must be done during posting.

*********************************************************************************/
void CBankTransaction::FillCheckbookNumber()
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));

DB_Account *checkAccount = // rev TCS 12/17/00
TCS_SAFE_CAST(gDBFile->GetOneObject(GetBankAccountClass(), mBankAccount),
DB_Account);
if (checkAccount)
{
DB_ObjectWatcher watcher(checkAccount);
mReferenceNum = checkAccount->PeekNextCheckNumber(GetCheckbookNumber());
}
}
/*********************************************************************************

FillBankCostItemInfo

fill in an itemized list of transactions for detailed job costing or T&M bills.

This is called by FillBankCostItemsFromArray.

Note that we do NOT include deposits from here. Those are handled via
mIncomeArray instead.
*********************************************************************************/
void CBankTransaction::FillBankCostItemInfo(TJobCostItemArray &itemArray, const UInt8 costType,
const DBid accountID)
{
// we used to have independent code here, but it was essentially identical
// to the basic transaction method, so TCS reduced it 12/4/00

if (mTransactionType != id_BankDeposit) // TCS 4/19/01
FillCostItemInfo(itemArray, costType, accountID);
}
/*********************************************************************************

FillCostItemInfo TCS 4/17/01

fill in an item for detailed job costing. We need special handling for
payments breakdowns, since the deposit may include payments to more than
one account
*********************************************************************************/
void CBankTransaction::FillCostItemInfo(TJobCostItemArray &itemArray, const UInt8 costType,
const DBid accountID) const
{
UInt8 breakdownType = GetBreakdownType();

if (mTransactionType == id_BankDeposit) // rev TCS 8/7/02
{
if (costType != costtype_income && costType != costtype_all)
return;
}
else if (mTransactionType == id_BankPayment || mTransactionType == id_BankCheck)
{ // we only job cost detailed purchase breakdowns
if (breakdownType == breakdown_costitem || breakdownType == breakdown_costcategory)
THE_SUPERCLASS::FillCostItemInfo(itemArray, costType, accountID);
else if (mTransactionRefClass == condition_DirectExpense) // TCS 11/13/03
THE_SUPERCLASS::FillCostItemInfo(itemArray, costType, accountID);
return;
}
else if (costType == costtype_other && mTransactionType != id_BankTransferOut)
{
return; // not valid
}
else if (costType == costtype_income && mTransactionType != id_BankTransferIn)
{
return; // not valid
}

// if we got this far, list the item. First prep the info struct
SJobCostItemInfo itemInfo;
TCS_BufferFromText(itemInfo.supplier, GetMainAccountName()); // rev TCS 12/3/03
itemInfo.date = mDate;
if (mTransactionType == id_BankTransferIn)
itemInfo.type = costtype_income;
else
itemInfo.type = costtype_other; // bugfix TCS 4/27/01

itemInfo.billedAmount = 0;
itemInfo.costAmount = 0;

CTextString itemName;
TCS_BufferFromText(itemInfo.category, itemName);
itemName = GetBankAccountName();
TCS_BufferFromText(itemInfo.supplier, itemName);

if (breakdownType == breakdown_payment)
{
// Fetch income info from the breakdowns. The deposit may include payments
// for more than one account, so we need to check for a match
TObjectIDArrayIterator iterator(mBreakdownArray);
DBid id;

while (iterator.Next(id))
{
CPaymentBreakdownEntry *entry = TCS_SAFE_CAST(gDBFile->GetOneObject(id_PaymentBreakdownEntry, id),
CPaymentBreakdownEntry);

if (entry)
{
DB_ObjectWatcher watcher(entry);

if (accountID == entry->GetMainAccountID())
{
itemInfo.paidAmount = entry->GetAmount();
itemName = gDBFile->GetObjectName(id_PaymentMethod, entry->GetPaymentMethod());
TCS_BufferFromText(itemInfo.category, itemName);

itemArray.Append(itemInfo);
}
}
}
}
else if (mTransactionType == id_BankTransferOut) // rev TCS 4/19/01
{
itemName = DB_ClassDescriptor::GetClassName(id_BankTransferOut);
TCS_BufferFromText(itemInfo.item, itemName);

itemInfo.costAmount = GetAmount(); // rev TCS 8/10/02
itemInfo.paidAmount = GetAmount();
itemArray.Append(itemInfo);
}
else if (mTransactionType == id_BankTransferIn)
{
itemName = DB_ClassDescriptor::GetClassName(id_BankTransferIn);
TCS_BufferFromText(itemInfo.item, itemName);

itemInfo.costAmount = GetAmount();
itemInfo.paidAmount = GetAmount();
itemArray.Append(itemInfo);
}
else
{ // a simple deposit
itemName = TCS_GetStockString(stockID_Deposit);
TCS_BufferFromText(itemInfo.item, itemName);

itemInfo.costAmount = GetAmount(); // rev TCS 8/10/02
itemInfo.paidAmount = GetAmount();
itemArray.Append(itemInfo);
}
}
/*********************************************************************************

FillCategoryArray TCS 4/24/01

fill in category cost info. We override since income is handled differently
*********************************************************************************/
void CBankTransaction::FillCategoryArray(TJobCostCategoryArray &catArray,
const UInt8 breakdownType,
const DBid matchCategory,
const UInt8 restrictions)
{
// make sure this is the right transaction type rev TCS 5/3/01, 5/8/01, 8/10/02
if (restrictions != costtype_income && mTransactionType == id_BankDeposit)
return;
else if (restrictions == costtype_income && mTransactionType != id_BankDeposit)
return;

// if we got this far, the superclass can fill in the array
THE_SUPERCLASS::FillCategoryArray(catArray, breakdownType, matchCategory, restrictions);
}
/*********************************************************************************

FillDataReport TCS 9/5/02

fill in a diagnostic table that shows data field values.

*********************************************************************************/
void CBankTransaction::FillDataReport(CTCS_Table *table, CNeoStream *stream) const
{
TCS_FailNILMsg(table, TCS_GetErrString(errID_BadTable));
TCS_FailNILMsg(stream, TCS_GetErrString(errID_BadStream));

THE_SUPERCLASS::FillDataReport(table, stream);

FillFieldStringRow(table, stream, tag_onetimename, mOneTimePayeeName);

// write basic members
FillFieldObjectIDRow(table, stream, tag_reconcileperiod, mReconcilePeriod, id_ReconcilePeriod);
FillFieldObjectIDRow(table, stream, tag_bankaccount, mBankAccount, GetBankAccountClass());
FillFieldObjectIDRow(table, stream, tag_job, mJob, mJobClass);
FillFieldObjectIDRow(table, stream, tag_category, mCategory, id_Category);
FillFieldObjectIDRow(table, stream, tag_taxrate, mTaxRate, id_VendorSalesTax);
FillFieldObjectIDRow(table, stream, tag_cashaccount, mCashUtilityAccount, id_UtilityAccount);

FillFieldTagRow(table, stream, tag_grossprice, cMoneySize, mGrossAmount.GetCurrencyString());
FillFieldTagRow(table, stream, tag_taxamount, cMoneySize, mTaxAmount.GetCurrencyString());

FillFieldEnumRow(table, stream, tag_transactiontype, mTransactionType, MENU_CheckingTransactionTypes);
FillFieldEnumRow(table, stream, tag_status, mStatus, MENU_BankTransStatus);
FillFieldEnumRow(table, stream, tag_jobclass, mJobClass, MENU_ExpenseJobTypes);
FillFieldEnumRow(table, stream, tag_conditions, mConditions, MENU_BankTransConditions);

FillFieldTagRow(table, stream, tag_runningtotal, cMoneySize, mPriorRunningTotal.GetCurrencyString());
FillFieldTableRow(table, stream, "mPaidOnAccount", cMoneySize, mPaidOnAccount.GetCurrencyString());

FillFieldObjectIDRow(table, stream, tag_transactionref, mTransactionRef, mTransactionRefClass);

FillFieldEnumRow(table, stream, tag_transactionrefclass, mTransactionRefClass, MENU_BankPaymentTransTypes);

FillFieldBitRow(table, stream, "mUseOneTimeName", mUseOneTimeName, true);
FillFieldBitRow(table, stream, "mIsAutoTransfer", mIsAutoTransfer);
FillFieldBitRow(table, stream, "mHasAutoTransfer", mHasAutoTransfer);
FillFieldStockRow(table, stream, stockID_Padding, -5, SInt32(mBankTransPadding));

FillFieldObjectIDRow(table, stream, tag_message, mMessage, id_Message); // TCS 5/7/04
FillFieldStockRow(table, stream, stockID_Expansion, cMoneySize, mExpansionMoney.GetCurrencyString());
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

FetchJobCostItemInfo TCS 4/23/01

add job cost data to a category/location item. We need special handling
for income transactions
*********************************************************************************/
Boolean CBankTransaction::FetchJobCostItemInfo(TJobCostItemArray &itemArray,
CTextString &catName,
const UInt8 costType)
{
if (mTransactionType == id_BankDeposit || mTransactionType == id_BankTransferIn)
{
if (costType != costtype_income) // TCS 8/10/02
return true;

SJobCostItemInfo itemInfo;
itemInfo.id = GetDBID();
TCS_BufferFromText(itemInfo.category, catName);

if (mTransactionType == id_BankDeposit)
TCS_BufferFromText(itemInfo.item, DB_ClassDescriptor::GetClassName(id_BankDeposit));
else
TCS_BufferFromText(itemInfo.item, DB_ClassDescriptor::GetClassName(id_BankTransferIn));
TCS_BufferFromText(itemInfo.supplier, GetBankAccountName()); // rev TCS 5/4/01

itemInfo.type = GetJobCostClass();
itemInfo.date = GetDate();

itemInfo.costAmount = 0;
itemInfo.billedAmount = 0;
itemInfo.paidAmount = GetAmount();

return (itemArray.Append(itemInfo) != LArray::index_Bad);
}
else
return THE_SUPERCLASS::FetchJobCostItemInfo(itemArray, catName, costType);
}
/*********************************************************************************

AddBreakdownsToDeposit TCS 1/11/99 rev 11/17/99

add breakdowns from the given deposit info, and return the total
*********************************************************************************/
CMoney CBankTransaction::AddBreakdownsToDeposit(const SDepositInfo &depositInfo,
const UInt8 sourceFilter, const Boolean eraseFirst)
{
// sanity check
TCS_FailNILMsg(depositInfo.itemArray, TCS_GetErrString(errID_BadArray));
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));

CPaymentBreakdownEntry *entry = nil;
CMoney depositAmount;
DBid ownerID = GetDBID();
UInt8 ownerClass = GetDBClassID(); // rev TCS 6/21/00
Boolean deposit;

// remove this obj from database, since filelength may change
DB_ObjectTempRemover remover (this); // TCS 8/26/03

if (!remover.WasRemoved())
return depositAmount;

TCS_TRY // added TCS 12/18/01
{
mBreakdownType = breakdown_payment;

// if there are already breakdowns, remove them
if (eraseFirst && GetBreakdownCount())
{
RemoveAllBreakdownEntries();
}

if (sourceFilter == filter_paymentsreceived || sourceFilter == filter_cashsalesbydate) // TCS rev 11/17/99
{
if (!depositInfo.deposit) // TCS rev 10/24/01
return 0;

// we're getting the transaction from the deposit info itself
entry = TCS_SAFE_CAST(gDBFile->CreateObjectFromID(id_PaymentBreakdownEntry,
flag_dontautoname), CPaymentBreakdownEntry);
TCS_FailNILMsg(entry, TCS_GetErrString(errID_BadObject));
DB_ObjectWatcher entryWatcher(entry);
// set some basic values
entry->SetMemberValue(tag_ownerobjectclass, type_objclass, &ownerClass);
entry->SetMemberValue(tag_ownerobject, type_objectid, &ownerID);

entry->SetCreationType(record_fromprocess); // TCS 6/25/03
// now fill in data from the struct
entry->SetMemberValue(tag_transactid, type_long, &depositInfo.transactionID); // TCS rev 6/26/00
entry->SetMemberValue(tag_transactiontype, type_objclass, &depositInfo.transactionClassID);
entry->SetMemberValue(tag_paymentmethod, type_objectid, &depositInfo.paymentMethod);
entry->SetMemberValue(tag_amountdue, type_money, &depositInfo.dueAmount);
entry->SetMemberValue(tag_adjustment, type_money, &depositInfo.adjustAmount); // TCS 11/21/01
entry->SetMemberValue(tag_amount, type_money, &depositInfo.paidAmount);
deposit = depositInfo.deposit;
entry->SetMemberValue(tag_pay, type_boolean, &deposit);

entry->SetMemberValue(tag_mainaccount, type_objectid, &depositInfo.accountID); // TCS 3/27/00 rev 6/26/00
entry->SetMemberValue(tag_mainaccountclass, type_objclass, &depositInfo.accountClassID); // TCS 3/27/00 bugfix 5/10/00

depositAmount = depositInfo.paidAmount;

// allow the object to do any final setup. Not really needed
// but we have it here for consistency TCS 5/5/03
entry->FinishNonViewerCreate();
// finally, add the entry to the db...
gDBFile->AddObject(entry); // TCS rev 4/28/03

// ...and to the deposit
AddBreakdown(entry->GetDBID());

// we don't post here- that is done later, after all items are in
}
else if (depositInfo.itemArray->GetCount() > 0)
{ // we're getting transactions from the itemArray
// walk through the items in the deposit item array
TDepositItemArrayIterator iterator(*(depositInfo.itemArray));
SDepositItem itemInfo;
while (iterator.Next(itemInfo))
{
if (!itemInfo.deposit) // TCS 10/24/01
continue;

// create a breakdown entry TCS 10/14/99
entry = TCS_SAFE_CAST(gDBFile->CreateObjectFromID(id_PaymentBreakdownEntry,
flag_dontautoname), CPaymentBreakdownEntry);
TCS_FailNILMsg(entry, TCS_GetErrString(errID_BadObject));
DB_ObjectWatcher entryWatcher(entry);
// set some basic values
entry->SetMemberValue(tag_ownerobject, type_objectid, &ownerID);
entry->SetMemberValue(tag_ownerobjectclass, type_objclass, &ownerClass);
// now fill in data from the struct
entry->SetMemberValue(tag_transactid, type_long, &itemInfo.transactionID);
entry->SetMemberValue(tag_transactiontype, type_objclass, &itemInfo.transactionClassID);
entry->SetMemberValue(tag_paymentmethod, type_enum, &itemInfo.paymentMethod); // bugfix TCS 5/11/00 per BD
entry->SetMemberValue(tag_amountdue, type_money, &itemInfo.dueAmount);
entry->SetMemberValue(tag_adjustment, type_money, &itemInfo.adjustAmount); // TCS 11/21/01
entry->SetMemberValue(tag_amount, type_money, &itemInfo.paidAmount);
deposit = itemInfo.deposit;
entry->SetMemberValue(tag_pay, type_boolean, &deposit);

entry->SetMemberValue(tag_mainaccount, type_objectid, &itemInfo.accountID); // TCS 3/27/00 rev TCS 9/17/01
entry->SetMemberValue(tag_mainaccountclass, type_objclass, &itemInfo.accountClassID); // TCS 3/27/00 rev TCS 9/17/01

depositAmount += itemInfo.paidAmount; // bugfix TCS 3/27/00

entry->SetCreationType(record_fromprocess); // TCS 6/25/03
// allow the object to do any final setup. Not really needed
// but we have it here for consistency TCS 5/5/03
entry->FinishNonViewerCreate();

// finally, add the entry to the db...
gDBFile->AddObject(entry);

// ...and to the deposit
AddBreakdown(entry->GetDBID());

// and post its creation -- nope, don't post here,
// it is already done later when deposit is posted TCS 3/9/00
//entry->PostNewRecord(record_fromprocess);
}
}
}
TCS_CATCH {}

// we used to add to the dbase here, but DB_ObjectTempRemover now does it. Note that
// for a client we save changes on the server later on in CDepositFundsEncl::CreateDeposit

return depositAmount;
}