Link to: header | transactions
directory
Copyright Turtle Creek Software 1996-2006. All Rights Reserved.
Comments
CChangeOrder
This class manages change orders for the Goldenseal accounting software,
small business management software, construction
project management software and
construction
accounting software.
This is the data class
for a change order. This is a record of a project change, which
is also used for separate billing for changes.
SUPERCLASS = CBreakdownTransaction
Constructor
/*********************************************************************************
constructor
*********************************************************************************/
CChangeOrder::CChangeOrder()
{
mStatus = mApprovalStatus = status_Entered;
mConditions = condition_FirmPrice;
mMainAccountClass = id_ProjectAccount;
mMaximum = mAmountBilled = 0;
mPaymentTerm = mTaxRate = 0;
mGrossAmount = mTaxAmount = 0;
mLocation = 0;
mCategory = mSubcat = 0;
mMaterialsToDate = mOtherCostsToDate = 0;
mAmountPaid = mSalesTaxToDate = 0;
mChangeOrderPadding = 0;
mLaborHours = 0;
mCrewSize = 1;
mStartDate.SetToToday();
mFinishDate = mStartDate;
mCOEndSafetyTag = tag_endsafetytag; // TCS 9/8/02
}
Source Code
/*********************************************************************************
CopyFrom
copy the data members from the passed object. This is used to implement
duplicate. source should be an object of the same class as this object
*********************************************************************************/
void CChangeOrder::CopyFrom(DB_PersistentObject *source, const UInt8 copyFlags)
{
THE_SUPERCLASS::CopyFrom(source, copyFlags);
CChangeOrder *src = TCS_SAFE_CAST(source, CChangeOrder);
TCS_FailNILMsg(src, TCS_GetErrString(errID_BadRecord));
// copy the name and add 'copy' to it TCS rev 9/18/01
mName = src->mName;
mName.AppendCopyString();
mContractText = src->mContractText; // TCS 9/26/02
mDetails = src->mDetails; // TCS 1/30/03
TCS_BlockMove(&src->mStatus, &mStatus, cCopyFileLength);
if (HasLockedStatus()) // TCS 2/2/99
mStatus = GetStarterStatus(); // rev TCS 3/8/00
}/*********************************************************************************
GetFileLength
return the file length used by this object
*********************************************************************************/
NeoSize CChangeOrder::GetFileLength(const CNeoFormat *aFormat) const
{
NeoVersion version = GetVersion();
NeoSize baseLength = THE_SUPERCLASS::GetFileLength(aFormat) +
mName.FileLength(cMenuTextLen) + // rev TCS 3/14/00
mContractText.LongFileLength(cMaximumTextLen) +
ARRAY_FILE_SIZE(mExpenseArray);
if (version > 1) // TCS 1/30/03
baseLength += mDetails.LongFileLength(cMaximumTextLen);
if (GetDBClassID() == id_ChangeOrder) // TCS rev 9/9/02
return baseLength + cFileLength;
else
return baseLength + cParentFileLength;
}/*********************************************************************************
GetMemberValue
return the value of the member with the given tag
*********************************************************************************/
Boolean CChangeOrder::GetMemberValue(const TagType aTag, const TagType aType,
void *aValue) const
{
CMoney amount;
switch (aTag)
{
case tag_taxrate:
return ConvertObjectIDMember(mTaxRate, id_JobSalesTax, aValue, aType);
break;
case tag_location:
return ConvertObjectIDMember(mLocation, id_Location, aValue, aType);
break;
case tag_category:
return ConvertObjectIDMember(mCategory, id_Category, aValue, aType);
break;
case tag_subcategory:
return ConvertObjectIDMember(mSubcat, id_Category, aValue, aType);
break;
case tag_paymentterm:
return ConvertObjectIDMember(mPaymentTerm, id_ProjectPaymentTerm, aValue, aType);
break;
case tag_conditions:
return ConvertEnumMember(mConditions, MENU_ChangeOrderConditions, aValue, aType);
break;
case tag_status:
return ConvertEnumMember(mStatus, MENU_ChangeOrderStatus, aValue, aType);
break;
case tag_approvalstatus:
return ConvertEnumMember(mApprovalStatus, MENU_ChangeOrderStatus, aValue, aType);
break;
case tag_breakdown:
return ConvertEnumMember(mBreakdownType, MENU_CostCatItemBreakdown, aValue, aType);
break;
case tag_grossprice:
return ConvertMember(&mGrossAmount, type_money, aValue, aType);
break;
case tag_maximum:
return ConvertMember(&mMaximum, type_money, aValue, aType);
break;
/* case tag_valuecompleted:
return ConvertMember(&mValueCompleted, type_money, aValue, aType);
break;*/
case tag_othertodate:
return ConvertMember(&mOtherCostsToDate, type_money, aValue, aType);
break;
case tag_mattodate:
return ConvertMember(&mMaterialsToDate, type_money, aValue, aType);
break;
case tag_salestaxtodate: // TCS 10/31/00
return ConvertMember(&mSalesTaxToDate, type_money, aValue, aType);
break;
case tag_amountbilled:
return ConvertMember(&mAmountBilled, type_money, aValue, aType);
break;
case tag_amountpaid:
return ConvertMember(&mAmountPaid, type_money, aValue, aType);
break;
case tag_taxamount: // TCS 1/12/00
return ConvertMember(&mTaxAmount, type_money, aValue, aType);
break;
case tag_laborhours: // TCS 5/16/02
return ConvertMember(&mLaborHours, type_number, aValue, aType);
break;
case tag_crewsize: // TCS 5/16/02
return ConvertMember(&mCrewSize, type_number, aValue, aType);
break;
case tag_startdate: // TCS 5/18/02
return ConvertMember(&mStartDate, type_date, aValue, aType);
break;
case tag_finishdate:
case tag_enddate:
return ConvertMember(&mFinishDate, type_date, aValue, aType);
break;
case tag_name:
return ConvertMember(&mName, type_cstring, aValue, aType);
break;
case tag_details: // TCS 1/30/03
return ConvertMember(&mDetails, type_longcstring, aValue, aType);
break;
case tag_contracttext:
return ConvertMember(&mContractText, type_longcstring, aValue, aType);
break;
case tag_paymenttermtext: // TCS 11/13/00
{
CTextString termText = GetPaymentTermText(id_ProjectPaymentTerm, mPaymentTerm);
return ConvertMember(&termText, type_cstring, aValue, aType);
}
break;
case tag_projectaccount: // project is the same as the main account TCS 2/14/00
case tag_job: // TCS 7/26/01
return ConvertObjectIDMember(mMainAccount, id_ProjectAccount, aValue, aType);
break;
case tag_jobclass: // TCS 7/26/01
{
UInt8 jobClass = id_ProjectAccount;
return ConvertEnumMember(jobClass, MENU_AccountClasses, aValue, aType);
}
break;
case tag_menuname: // for menus, we make sure to return a valid name
{
if (mName.Length())
return ConvertMember(&mName, type_cstring, aValue, aType);
else // if no name, the superclass will build one
return THE_SUPERCLASS::GetMemberValue(aTag, aType, aValue);
}
break;
case tag_catsystem: // we override since cat system is based on the job
{
DBid catSystem = DB_Account::GetJobCatSystem(id_ProjectAccount, mMainAccount);
return ConvertObjectIDMember(catSystem, id_CategorySystem, aValue, aType);
}
break;
case tag_amountdue:
amount = mAmountBilled - mAmountPaid;
return ConvertMember(&amount, type_money, aValue, aType);
break;
/* case tag_percentcompleted:
return ConvertMember(&mPercentCompleted, type_percent, aValue, aType);
break;*/
case tag_costarea: // we calculate this for item cv's TCS 3/20/99
{
UInt8 costArea = costtype_changeorder;
return ConvertMember(&costArea, type_enum, aValue, aType);
}
break;
case tag_prevbilled: // TCS 4/1/03
amount = GetPreviousOrdersTotal();
return ConvertMember(&amount, type_money, aValue, aType);
break;
case tag_totaltodate: // TCS 4/1/03
amount = GetPreviousOrdersTotal() + GetAmount();
return ConvertMember(&amount, type_money, aValue, aType);
break;
case tag_contractamount: // TCS 4/1/03
amount = GetContractAmount();
return ConvertMember(&amount, type_money, aValue, aType);
break;
default:
return THE_SUPERCLASS::GetMemberValue(aTag, aType, aValue);
break;
}
}/*********************************************************************************
SetMemberValue
set the value of the member with the given tag
*********************************************************************************/
Boolean CChangeOrder::SetMemberValue(const TagType aTag, const TagType aType,
const void *aValue)
{
switch (aTag)
{
case tag_location:
return ConvertDataToObjectID(aValue, aType, &mLocation, id_Location);
break;
case tag_category:
return ConvertDataToObjectID(aValue, aType, &mCategory, id_Category);
break;
case tag_subcategory:
return ConvertDataToObjectID(aValue, aType, &mSubcat, id_Category);
break;
case tag_paymentterm:
return ConvertDataToObjectID(aValue, aType, &mPaymentTerm, id_ProjectPaymentTerm);
break;
case tag_taxrate:
return ConvertDataToObjectID(aValue, aType, &mTaxRate, id_JobSalesTax);
break;
case tag_conditions:
return ConvertMember(aValue, aType, &mConditions, type_enum);
break;
case tag_status: // we also may update the approval status TCS 11/18/99
if (ConvertMember(aValue, aType, &mStatus, type_enum))
{
if (mStatus == status_Entered || mStatus == status_Submitted ||
mStatus == status_Approved || mStatus == status_Completed ||
mStatus == status_Void)
{
mApprovalStatus = mStatus;
}
return true;
}
else
return false;
break;
case tag_approvalstatus: // TCS 12/12/99
return ConvertMember(aValue, aType, &mApprovalStatus, type_enum);
break;
case tag_maximum:
return ConvertMember(aValue, aType, &mMaximum, type_money);
break;
/* case tag_valuecompleted:
return ConvertMember(aValue, aType, &mValueCompleted, type_money);
break;*/
case tag_othertodate:
return ConvertMember(aValue, aType, &mOtherCostsToDate, type_money);
break;
case tag_mattodate:
return ConvertMember(aValue, aType, &mMaterialsToDate, type_money);
break;
case tag_salestaxtodate: // TCS 10/31/00
return ConvertMember(aValue, aType, &mSalesTaxToDate, type_money);
break;
case tag_amountbilled:
return ConvertMember(aValue, aType, &mAmountBilled, type_money);
break;
case tag_taxamount: // rev TCS 1/12/00
return ConvertMember(aValue, aType, &mTaxAmount, type_money);
break;
case tag_amountpaid:
return ConvertMember(aValue, aType, &mAmountPaid, type_money);
break;
case tag_grossprice:
return ConvertMember(aValue, aType, &mGrossAmount, type_money);
break;
case tag_laborhours: // TCS 5/16/02
return ConvertMember(aValue, aType, &mLaborHours, type_number);
break;
case tag_crewsize: // TCS 5/16/02
return ConvertMember(aValue, aType, &mCrewSize, type_number);
break;
case tag_startdate:
return ConvertMember(aValue, aType, &mStartDate, type_date);
break;
case tag_finishdate:
return ConvertMember(aValue, aType, &mFinishDate, type_date);
break;
case tag_name:
return SafeConvertString(aValue, aType, &mName);
break;
case tag_contracttext: // TCS 9/26/02
return SafeConvertString(aValue, aType, &mContractText, type_longcstring);
break;
case tag_details: // TCS 1/30/03
return SafeConvertString(aValue, aType, &mDetails, type_longcstring);
break;
case tag_amountdue: // we don't ever need to set these
case tag_prevbilled: // TCS 4/1/03
case tag_totaltodate:
case tag_contractamount:
return true;
break;
/* case tag_percentcompleted:
return ConvertMember(aValue, aType, &mPercentCompleted, type_percent);
break;*/
default:
return THE_SUPERCLASS::SetMemberValue(aTag, aType, aValue);
break;
}
}/*********************************************************************************
ReadObject
read the persistent object's data in from a stream
*********************************************************************************/
void CChangeOrder::ReadObject(CNeoStream *aStream, const TagType aTag)
{
TCS_FailNILMsg(aStream, TCS_GetErrString(errID_BadStream));
Boolean isCO = (GetDBClassID() == id_ChangeOrder);
CNeoDebugImport checker(aStream, this, isCO); // TCS 2/24/00
THE_SUPERCLASS::ReadObject(aStream, aTag);
if (!IsIOValid()) // TCS 2/5/02
return;
NeoVersion version = GetVersion();
ReadInfoArrayFromStream(aStream, mExpenseArray, cHasSafetyTag);
ReadTextFromStream(aStream, &mName);
ReadLongTextFromStream(aStream, &mContractText);
if (version > 1) // TCS 1/30/03
ReadLongTextFromStream(aStream, &mDetails);
// --Start: Binary Compatibility Changes // mfs_sa 20feb2k3
/// if (isCO) // TCS 9/9/02
/// aStream->ReadChunk(&mStatus, cFileLength);
/// else
/// aStream->ReadChunk(&mStatus, cParentFileLength);
mStatus = aStream->ReadChar();
mConditions = aStream->ReadChar();
mPaymentTerm = aStream->ReadID();
mTaxRate = aStream->ReadID();
mLocation = aStream->ReadID();
mCategory = aStream->ReadID();
mSubcat = aStream->ReadID();
mStartDate.ReadFromStream(aStream); // TCS 5/18/02
mFinishDate.ReadFromStream(aStream);
mGrossAmount.ReadFromStream(aStream);
mMaximum.ReadFromStream(aStream);
mTaxAmount.ReadFromStream(aStream);
mLaborHours.ReadFromStream(aStream); // TCS 5/16/02
mCrewSize.ReadFromStream(aStream);
mAmountBilled.ReadFromStream(aStream);
mMaterialsToDate.ReadFromStream(aStream);
mOtherCostsToDate.ReadFromStream(aStream);
mSalesTaxToDate.ReadFromStream(aStream);
mAmountPaid.ReadFromStream(aStream);
mApprovalStatus = aStream->ReadChar();
mChangeOrderPadding = aStream->ReadChar();
if (isCO)
mCOEndSafetyTag = aStream->ReadEndSafetyTag(this);
if (!IsValidEndTag(mCOEndSafetyTag)) // TCS 9/8/02
ReportDamagedObject(GetDBClassID(), GetDBID());
}/*********************************************************************************
WriteObject
write the persistent object's data to a stream
*********************************************************************************/
void CChangeOrder::WriteObject(CNeoStream *aStream, const TagType aTag)
{
TCS_FailNILMsg(aStream, TCS_GetErrString(errID_BadStream));
// make sure we have valid data to write TCS 9/8/02
if (!IsValidEndTag(mCOEndSafetyTag))
{
ReportDamagedObject(GetDBClassID(), GetDBID());
mCOEndSafetyTag = tag_endsafetytag; // TCS 11/26/02
}
Boolean isCO = (GetDBClassID() == id_ChangeOrder);
NeoVersion version = GetVersion(); // TCS 1/30/03
CNeoDebugExport checker(aStream, this, isCO);
THE_SUPERCLASS::WriteObject(aStream, aTag);
WriteInfoArrayToStream(aStream, mExpenseArray, cHasSafetyTag);
WriteTextToStream(aStream, mName, cMenuTextLen); // removed -1 TCS 2/28/00
WriteLongTextToStream(aStream, mContractText, cMaximumTextLen);
if (version > 1) // TCS 1/30/03
WriteLongTextToStream(aStream, mDetails, cMaximumTextLen);
/// if (isCO) // TCS 9/9/02
/// aStream->WriteChunk(&mStatus, cFileLength);
/// else
/// aStream->WriteChunk(&mStatus, cParentFileLength);
aStream->WriteChar(mStatus);
aStream->WriteChar(mConditions);
aStream->WriteID(mPaymentTerm);
aStream->WriteID(mTaxRate);
aStream->WriteID(mLocation);
aStream->WriteID(mCategory);
aStream->WriteID(mSubcat);
mStartDate.WriteToStream(aStream); // TCS 5/18/02
mFinishDate.WriteToStream(aStream);
mGrossAmount.WriteToStream(aStream);
mMaximum.WriteToStream(aStream);
mTaxAmount.WriteToStream(aStream);
mLaborHours.WriteToStream(aStream); // TCS 5/16/02
mCrewSize.WriteToStream(aStream);
mAmountBilled.WriteToStream(aStream);
mMaterialsToDate.WriteToStream(aStream);
mOtherCostsToDate.WriteToStream(aStream);
mSalesTaxToDate.WriteToStream(aStream);
mAmountPaid.WriteToStream(aStream);
aStream->WriteChar(mApprovalStatus);
aStream->WriteChar(mChangeOrderPadding);
if (isCO)
aStream->WriteEndSafetyTag(mCOEndSafetyTag, this);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
PostNewRecord TCS 11/21/03
post info for a new record
*********************************************************************************/
void CChangeOrder::PostNewRecord(const UInt8 creationType)
{
PostUseCount(id_ProjectPaymentTerm, mPaymentTerm);
PostUseCount(id_JobSalesTax, mTaxRate);
PostUseCount(id_Location, mLocation);
PostUseCount(id_Category, mCategory);
PostUseCount(id_Category, mSubcat);
// let the superclass do any posting
THE_SUPERCLASS::PostNewRecord(creationType);
}
/*********************************************************************************
PostDeletion TCS 11/21/03
post info from a deleted record
*********************************************************************************/
void CChangeOrder::PostDeletion(const Boolean postAudit)
{
PostUseCount(id_ProjectPaymentTerm, mPaymentTerm, cRemoveItem);
PostUseCount(id_JobSalesTax, mTaxRate, cRemoveItem);
PostUseCount(id_Location, mLocation, cRemoveItem);
PostUseCount(id_Category, mCategory, cRemoveItem);
PostUseCount(id_Category, mSubcat, cRemoveItem);
// let the superclass do any posting
THE_SUPERCLASS::PostDeletion(postAudit);
}
/*********************************************************************************
PostRecordActivated
post info from a newly created or activated transaction
*********************************************************************************/
void CChangeOrder::PostRecordActivated(const UInt8 creationType)
{
PostToProjectAccount();
// let the superclass do any posting
THE_SUPERCLASS::PostRecordActivated(creationType);
}
/*********************************************************************************
PostRecordCancelled
post info from a deleted or voided transaction TCS 9/24/98
*********************************************************************************/
void CChangeOrder::PostRecordCancelled(const UInt8 cancelType)
{
PostToProjectAccount(cRemoveItem);
// let the superclass do any posting
THE_SUPERCLASS::PostRecordCancelled(cancelType);
}
/*********************************************************************************
PostRecordChanging
a record will be changing. Post the change.
*********************************************************************************/
void CChangeOrder::PostRecordChanging(const Boolean accountChanging, const Boolean jobChanging)
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
// account is changing, so adjust arrays
// note that if we ever add numeric posting,
// action should be taken even if account hasn't changed
if (accountChanging)
{
PostToProjectAccount(cRemoveItem);
}
PostUseCount(id_ProjectPaymentTerm, mPaymentTerm, cRemoveItem); // TCS 11/21/03
PostUseCount(id_JobSalesTax, mTaxRate, cRemoveItem);
PostUseCount(id_Location, mLocation, cRemoveItem);
PostUseCount(id_Category, mCategory, cRemoveItem);
PostUseCount(id_Category, mSubcat, cRemoveItem);
THE_SUPERCLASS::PostRecordChanging(accountChanging, jobChanging);
}
/*********************************************************************************
PostRecordChanged
a record has changed. Post it.
*********************************************************************************/
void CChangeOrder::PostRecordChanged(const CMoney &oldAmount, const Boolean accountChanged,
const Boolean jobChanged)
{
// account has changed, so adjust arrays
// note that if we ever add numeric posting,
// action should be taken even if account hasn't changed
if (accountChanged)
{
PostToProjectAccount();
}
PostUseCount(id_ProjectPaymentTerm, mPaymentTerm); // TCS 11/21/03
PostUseCount(id_JobSalesTax, mTaxRate);
PostUseCount(id_Location, mLocation);
PostUseCount(id_Category, mCategory);
PostUseCount(id_Category, mSubcat);
THE_SUPERCLASS::PostRecordChanged(oldAmount, accountChanged, jobChanged);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
PostToProjectAccount TCS moved 12/17/99
post info in a project account
*********************************************************************************/
void CChangeOrder::PostToProjectAccount(const Boolean removeItem)
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
CProjectAccount *project = nil;
// start by finding the project account
if (mMainAccount)
{
project = TCS_SAFE_CAST(gDBFile->GetOneObject(id_ProjectAccount,
mMainAccount), CProjectAccount);
}
if (project)
{
DB_ObjectWatcher watcher(project);
// add this transaction to the project's array.
if (removeItem)
project->AddToChangeOrderArray(GetDBID(), cRemoveItem);
else
project->AddToChangeOrderArray(GetDBID());
}
}
/*********************************************************************************
SetPaidStatus TCS 6/29/00 rev 8/7/01
set the payment status. We override since we never completely pay off
time and materials items
*********************************************************************************/
void CChangeOrder::SetPaidStatus(const UInt8 inValue)
{
if (inValue == status_Overpaid || inValue == status_Paid)
{
if (!CanBeFullyPaid())
{
SetStatus(status_PartPaid);
return;
}
}
// if we get this far, just pass it along
THE_SUPERCLASS::SetPaidStatus(inValue);
}
/*********************************************************************************
SetCompletedStatus TCS 11/5/01
mark this change order or allowance when a project is marked as completed
*********************************************************************************/
void CChangeOrder::SetCompletedStatus(const Boolean removeItem)
{
UInt8 saveType = PrepareViewerDisplay();
if (removeItem)
{
if (mAmountPaid.IsPositive())
SetStatus(status_PartPaid);
else if (HasBeenReceivableBilled())
SetStatus(status_ReceivableBilled);
else
SetStatus(status_Started);
}
else
SetStatus(status_Completed);
UpdateViewerDisplay(saveType);
}
/*********************************************************************************
HasRecordLock TCS 12/24/03
return whether this record should be locked. We overide since started status
should lock the status popup but not the data fields.
*********************************************************************************/
Boolean CChangeOrder::HasRecordLock() const
{
if (mStatus == status_Started)
return false;
else
return THE_SUPERCLASS::HasRecordLock();
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
HandlePaymentReceived TCS 2/28/02
deal with a payment that has been received for this item.
We override completely, since we need to handle negative amounts
*********************************************************************************/
void CChangeOrder::HandlePaymentReceived(const CMoney &inAmount, const UInt8 sourceClass,
const DBid sourceID, const UInt8 transactionType,
const Boolean removeItem, const Boolean fromDeposit,
const Boolean /*fromBillRecord*/)
{
if (HasVoidStatus())
{
return;
}
Boolean isReduction = mAmount.IsNegative();
// update payment amount
CMoney prevPaidAmount = GetAmountPaid();
CMoney amountPaid = inAmount + prevPaidAmount;
SetAmountPaid(amountPaid);
Boolean fullyPaid;
UInt8 saveSuccess = save_notvisible;
// we don't ever pay on account
// if we are currently in a viewer, prepare to update it TCS 8/22/00
if (!fromDeposit)
saveSuccess = PrepareViewerDisplay();
if (!removeItem && ((isReduction && amountPaid > GetAmount()) ||
(!isReduction && amountPaid < GetAmount()))) // OVERPAYMENT
{
// set payment details
fullyPaid = true;
// update the status
SetPaidStatus(status_Overpaid);
// now we are definitely overpaid
SetBeenOverpaid(true);
}
else if (amountPaid == GetAmount()) // EXACT PAYMENT
{
if (CanBeFullyPaid())
fullyPaid = true;
else
fullyPaid = false;
SetBeenOverpaid(false);
SetPaidStatus(status_Paid);
}
else if (amountPaid.IsNonZero()) // PARTIAL PAYMENT
{
fullyPaid = false;
SetBeenOverpaid(false);
SetPaidStatus(status_PartPaid);
}
else // NOT PAID AT ALL
{
fullyPaid = false;
SetBeenOverpaid(false);
// update the status
SetPaidStatus(status_Unpaid);
}
// mark the flag bit
SetPaidInFull(fullyPaid);
// we've changed
MakeDirty();
// update the payment transaction array TCS 6/6/00 rev 5/4/01
AddToObjectInfoArray(mPaymentArray, sourceClass, sourceID, transactionType, removeItem, true);
// if we are currently in a viewer, need to update it TCS 3/21/00
UpdateViewerDisplay(saveSuccess);
// no need to pass it along from here
}
/*********************************************************************************
HandleExpenseTrans TCS 12/21/98 rev 1/18/00
add a cost item to our cost total and array
*********************************************************************************/
void CChangeOrder::HandleExpenseTrans(const CMoney &amount, const CMoney &taxAmount,
const UInt8 classID, const DBid costID,
const Boolean removeIt)
{
UInt8 saveType = PrepareViewerDisplay(); // TCS 9/10/00 rev TCS 10/23/00
AddToExpenseArray(classID, costID, 0, removeIt);
if (!removeIt)
{
SetStatus(status_Started); // TCS 9/10/00
mSalesTaxToDate += taxAmount; // TCS 10/31/00
if (classID == id_MaterialPurchase)
mMaterialsToDate += amount;
else
mOtherCostsToDate += amount;
}
else
{
mSalesTaxToDate -= taxAmount; // TCS 10/31/00
if (classID == id_MaterialPurchase) // TCS 5/29/00
mMaterialsToDate -= amount;
else
mOtherCostsToDate -= amount;
}
MakeDirty();
UpdateViewerDisplay(saveType); // this may make a visible change
}
/*********************************************************************************
HandleBilling TCS 1/25/01
this item has been billed. Mark it.
*********************************************************************************/
void CChangeOrder::HandleBilling(const DBid billID, const CMoney &amount, const Boolean removeItem)
{
UInt8 saveType = PrepareViewerDisplay(); // TCS 9/10/00 rev TCS 10/23/00
if (!removeItem)
SetStatus(status_ReceivableBilled);
else if (removeItem && mStatus == status_ReceivableBilled)
SetStatus(status_Started);
CMoney amountBilled = GetBilledAmount(); // TCS 3/11/01
if (removeItem)
amountBilled -= amount;
else
amountBilled += amount;
SetBilledAmount(amountBilled);
// if this CO uses t&m billing, we also pass it along
// to the source transactions TCS 3/11/01
if (mConditions != condition_NoCharge && mConditions != condition_FirmPrice &&
mConditions != condition_Credit)
{
TObjectInfoArrayIterator iterator(mExpenseArray);
SObjectInfo info;
DB_PersistentObject *source = nil;
while (iterator.Next(info))
{
source = gDBFile->GetOneObject(info.classID, info.itemID);
if (source)
{
DB_ObjectWatcher watcher(source);
source->HandleTandMBilling(billID, removeItem);
}
else
ReportMissingObject(info.classID, info.itemID);
}
}
UpdateViewerDisplay(saveType);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
GetContractAmount TCS 4/1/03
return the original project amount
*********************************************************************************/
CMoney CChangeOrder::GetContractAmount() const
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
DB_PersistentObject *project = gDBFile->GetOneObject(id_ProjectAccount, mMainAccount);
if (project)
{
DB_ObjectWatcher watcher(project);
return project->GetContractAmount();
}
else
return 0;
}
/*********************************************************************************
GetPreviousOrdersTotal TCS 4/1/03
return the total of change orders prior to this one.
*********************************************************************************/
CMoney CChangeOrder::GetPreviousOrdersTotal() const
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
CProjectAccount *project =
TCS_SAFE_CAST(gDBFile->GetOneObject(id_ProjectAccount, mMainAccount),
CProjectAccount);
if (project)
{
DB_ObjectWatcher watcher(project);
return project->GetChangeOrderTotal(GetDBID());
}
else
return 0;
}
/*********************************************************************************
CalculateAmountDue TCS moved & rev 8/8/02
calculate the actual billing amount. We have to adjust for minimum and
maximum limits, and also subtract previous billed amount.
*********************************************************************************/
CMoney CChangeOrder::CalculateAmountDue(const CMoney materialAmount, const CMoney otherCostAmount)
{
CMoney totalCost = materialAmount + otherCostAmount;
CMoney zeroAmount = 0;
CMoney outAmount = 0;
// calculate the due amount for this order, which depends on calc method
switch (mConditions)
{
case condition_NoCharge:
outAmount = 0;
break;
case condition_Credit: // TCS 10/31/01
outAmount = mGrossAmount - GetBilledAmount();
break;
case condition_FirmPrice: // bugfix TCS 8/15/01
outAmount = mGrossAmount - GetBilledAmount();
break;
case condition_TotalCost:
outAmount = totalCost;
break;
case condition_CostWithMin: // TCS 8/9/02
outAmount = TCS_MIN(totalCost, TCS_MAX(zeroAmount, GetMinMaxAmount() - GetBilledAmount()));
break;
case condition_CostWithMax:
outAmount = TCS_MAX(zeroAmount, TCS_MIN(totalCost, GetMinMaxAmount() - GetBilledAmount()));
break;
case condition_CostMinusBase: // TCS 2/4/02
if (GetBilledAmount().IsPositive())
outAmount = TCS_MAX(zeroAmount, totalCost);
else
outAmount = TCS_MAX(zeroAmount, totalCost - GetMinMaxAmount());
break;
case condition_Materialonly:
outAmount = materialAmount;
break;
case condition_MaterialWithMin:
outAmount = TCS_MIN(materialAmount, TCS_MAX(zeroAmount, GetMinMaxAmount() - GetBilledAmount()));
break;
case condition_MaterialWithMax:
outAmount = TCS_MAX(zeroAmount, TCS_MIN(materialAmount, GetMinMaxAmount() - GetBilledAmount()));
break;
case condition_MaterialMinusBase: // TCS 2/4/02
if (GetBilledAmount().IsPositive())
outAmount = TCS_MAX(zeroAmount, materialAmount);
else
outAmount = TCS_MAX(zeroAmount, materialAmount - GetMinMaxAmount());
break;
default:
TCS_DebugAlert("Oops, bad case in CChangeOrder::CalculateAmountDue!");
outAmount = 0;
break;
}
return outAmount;
}
/*********************************************************************************
FillContractInfo TCS 5/3/00
add this change order to the proper category amount in the cost array
*********************************************************************************/
Boolean CChangeOrder::FillContractInfo(TJobCostCategoryArray &costArray,
const UInt8 breakdownType)
{
SInt32 defaultIndex = costArray.GetCount();
TCS_FailNILMsg(defaultIndex, TCS_GetErrString(errID_BadArray));
SJobCostCategoryInfo catItem,
searchItem;
TJobCostCategoryArrayIterator catIterator(costArray);
SInt32 catIndex = 0;
DBid catID;
if (breakdownType == breakdown_location)
catID = GetLocation();
else
catID = GetCategory();
while (catIterator.Next(searchItem))
{
if (searchItem.id == catID)
{
catIndex = catIterator.GetCurrentIndex();
break;
}
}
if (!catIndex)
catIndex = defaultIndex;
costArray.FetchItemAt(catIndex, catItem);
catItem.changeAmount += GetAmount();
// assign the value
costArray.AssignItemAt(catIndex, catItem);
return true;
}
/*********************************************************************************
FillBillingInfo TCS moved 8/8/02
fill in details for change order billing. Also inherited for allowance billing.
*********************************************************************************/
Boolean CChangeOrder::FillBillingInfo(SAllowanceItemInfo &itemInfo)
{
Boolean success = false;
TCS_FailNILMsg(itemInfo.itemArray, TCS_GetErrString(errID_BadArray));
itemInfo.calcMethod = mConditions;
TCS_BufferFromText(itemInfo.itemName, mName);
itemInfo.baseAmount = GetGrossAmount() * GetQuantity(); // bugfix TCS 10/23/01, rev 8/9/02
itemInfo.previousBilledAmount = GetBilledAmount();
itemInfo.previousPaidAmount = GetAmountPaid();
// initialize amounts. We'll update them from the items
itemInfo.materialAmount = 0;
itemInfo.otherCostAmount = 0;
// prepare to loop thru expenses, and fill in detailed T&M info
// initialize info values
CMoney feePercent = 0, baseAmount = 0, markupAmount = 0,
laborMarkup = 0, materialMarkup = 0, subMarkup = 0,
equipmentMarkup = 0, otherMarkup = 0, costAmount = 0;
Boolean includeSalesTax = true, includeAdjustments = false,
materialsOnly = false;
// fetch the markup percentage rev TCS 8/8/02
CProjectPaymentTerm *terms =
TCS_SAFE_CAST(gDBFile->GetOneObject(id_ProjectPaymentTerm, mPaymentTerm),
CProjectPaymentTerm);
if (terms) // TCS 10/22/01
{
DB_ObjectWatcher termWatcher(terms);
laborMarkup = terms->GetManagementPercent(costtype_labor);
materialMarkup = terms->GetManagementPercent(costtype_material);
subMarkup = terms->GetManagementPercent(costtype_subcontractor);
equipmentMarkup = terms->GetManagementPercent(costtype_equipment);
otherMarkup = terms->GetManagementPercent(costtype_other);
includeSalesTax = terms->IncludeSalesTax();
includeAdjustments = terms->IncludeAdjustments();
materialsOnly = terms->MaterialsOnly(); // TCS 10/31/01
}
// iterate thru expenses
CTransaction *costTransaction = nil;
SObjectInfo objectInfo;
TObjectInfoArrayIterator iterator(mExpenseArray);
STandMItemInfo info;
info.bill = true;
while (iterator.Next(objectInfo))
{
costTransaction =
TCS_SAFE_CAST(gDBFile->GetOneObject(objectInfo.classID, objectInfo.itemID),
CTransaction);
if (costTransaction)
{
DB_ObjectWatcher costWatcher(costTransaction);
if (costTransaction->HasBeenTandMBilled()) // TCS 3/11/01 rev 8/8/02
{ // already billed, so we can skip it
continue;
}
else
{ // not yet billed, so fetch info from the transaction
// and then add it to the array
baseAmount = costTransaction->GetTandMAmount(includeSalesTax, includeAdjustments);
if (objectInfo.classID == id_MaterialPurchase ||
objectInfo.classID == id_InventoryUsed) // rev TCS 10/31/01
markupAmount = baseAmount * materialMarkup.GetPercentDecimal(); // bugfix TCS 8/7/02
else if (materialsOnly)
markupAmount = 0;
else if (objectInfo.classID == id_LaborHours) // TCS 10/16/02
markupAmount = baseAmount * laborMarkup.GetPercentDecimal();
else if (objectInfo.classID == id_EquipmentHours) // TCS 10/16/02
markupAmount = baseAmount * equipmentMarkup.GetPercentDecimal();
else if (objectInfo.classID == id_SubcontractorLog) // TCS 10/16/02
markupAmount = baseAmount * subMarkup.GetPercentDecimal();
else if (objectInfo.classID == id_OtherCost) // TCS 10/16/02
markupAmount = baseAmount * otherMarkup.GetPercentDecimal();
else
markupAmount = 0;
costAmount = baseAmount + markupAmount;
info.id = objectInfo.itemID;
info.costType = objectInfo.classID;
info.costAmount = baseAmount;
info.markupAmount = markupAmount;
info.totalDueAmount = costAmount;
if (objectInfo.classID == id_MaterialPurchase)
itemInfo.materialAmount += costAmount;
else
itemInfo.otherCostAmount += costAmount;
itemInfo.currentAmount += costAmount;
itemInfo.totalDueAmount += costAmount;
// add it to the array
itemInfo.itemArray->Append(info);
success = true;
}
}
}
if (IsAllowance())
{
// we always include allowances even if there are no expenses listed.
success = true;
}
else if (mConditions == condition_FirmPrice || mConditions == condition_Credit) // rev TCS 11/5/02
{
// we always include fixed cost change orders that are not completely billed
CMoney grossAmount = GetGrossAmount();
if (grossAmount.IsZero())
success = false;
else if (grossAmount == GetBilledAmount())
success = false;
else
success = true;
}
// get the adjusted total rev TCS 8/8/02
itemInfo.currentAmount = CalculateAmountDue(itemInfo.materialAmount, itemInfo.otherCostAmount);
// we start out not due, since we rely on user to mark
// when the change order has been completed
itemInfo.totalDueAmount = 0;
// we now give the option to show all items. We could also do this
// via preferences, but right now it's just a command key option
if (TCS_ModifierKeyDown(true)) // TCS 11/3/03
return true;
else
return success;
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
FillDataReport TCS 9/6/02
fill in a diagnostic table that shows data field values.
*********************************************************************************/
void CChangeOrder::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);
FillFieldArrayRow(table, stream, "mExpenseArray", mExpenseArray);
FillFieldStringRow(table, stream, tag_name, mName);
FillFieldStringRow(table, stream, tag_contracttext, mContractText, true);
NeoVersion version = GetVersion(); // TCS 1/30/03
if (version > 1)
FillFieldStringRow(table, stream, tag_details, mDetails, true);
FillFieldEnumRow(table, stream, tag_status, mStatus, MENU_ChangeOrderStatus);
FillFieldEnumRow(table, stream, tag_conditions, mConditions, MENU_ChangeOrderConditions);
FillFieldObjectIDRow(table, stream, tag_paymentterm, mPaymentTerm, id_ProjectPaymentTerm);
FillFieldObjectIDRow(table, stream, tag_taxrate, mTaxRate, id_JobSalesTax);
FillFieldObjectIDRow(table, stream, tag_location, mLocation, id_Location);
FillFieldObjectIDRow(table, stream, tag_category, mCategory, id_Category);
FillFieldObjectIDRow(table, stream, tag_subcategory, mSubcat, id_Category);
FillFieldTagRow(table, stream, tag_startdate, cDateSize, mStartDate.GetCString());
FillFieldTagRow(table, stream, tag_finishdate, cDateSize, mFinishDate.GetCString());
FillFieldTagRow(table, stream, tag_grossprice, cMoneySize, mGrossAmount.GetCurrencyString());
FillFieldTagRow(table, stream, tag_maximum, cMoneySize, mMaximum.GetCurrencyString());
FillFieldTagRow(table, stream, tag_taxamount, cMoneySize, mTaxAmount.GetCurrencyString());
FillFieldTagRow(table, stream, tag_laborhours, cMoneySize, mLaborHours.GetNumberString());
FillFieldTagRow(table, stream, tag_crewsize, cMoneySize, mCrewSize.GetNumberString());
FillFieldTagRow(table, stream, tag_amountbilled, cMoneySize, mAmountBilled.GetCurrencyString());
FillFieldTagRow(table, stream, tag_mattodate, cMoneySize, mMaterialsToDate.GetCurrencyString());
FillFieldTagRow(table, stream, tag_othertodate, cMoneySize, mOtherCostsToDate.GetCurrencyString());
FillFieldTagRow(table, stream, tag_salestaxtodate, cMoneySize, mSalesTaxToDate.GetNumberString());
FillFieldTagRow(table, stream, tag_amountpaid, cMoneySize, mAmountPaid.GetNumberString());
FillFieldEnumRow(table, stream, tag_approvalstatus, mApprovalStatus, MENU_ChangeOrderStatus);
FillFieldStockRow(table, stream, stockID_Padding, cCharSize, SInt32(mChangeOrderPadding));
if (GetDBClassID() == id_ChangeOrder)
{
FillEndSafetyTag(table, stream, mCOEndSafetyTag);
}
}
|