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;
}
|