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

Estimates (Source Code 3)

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

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

Source Code

This class manages estimating for the Goldenseal estimating software,
project estimating software and construction estimating software.

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

FillCatSubcatArray TCS 7/11/02

fill in a report with categories, subcategories and items
*********************************************************************************/
void CEstimate::FillCatSubcatArray(const DBid reportID, TTwoLevelArray *twoLevelArray,
const Boolean hideSoftCosts, CMoney &softCostAmount,
CMoney &hardCostAmount) const
{
if (reportID != id_EstCatSubcatReport)
return;

// loop thru breakdown items and have them fill the array
if (mBreakdownArray.GetCount() > 0)
{
// fill in an array of categories and subcategories
CCategorySystem *catSystem =
TCS_SAFE_CAST(gDBFile->GetOneObject(id_CategorySystem, GetCategorySystem()),
CCategorySystem);

if (catSystem)
{
DB_ObjectWatcher watcher (catSystem);
catSystem->FillCatSubcatArray(reportID, twoLevelArray,
hideSoftCosts, softCostAmount, hardCostAmount);
}
else
CCategorySystem::FillDefaultCatSubcatArray(twoLevelArray);

// loop thru est breakdown items and fill in amounts
TObjectIDArrayIterator iter(mBreakdownArray);
DBid breakdownID;
CCostBreakdownEntry *estBreakdownItem;

while (iter.Next(breakdownID))
{
estBreakdownItem =
TCS_SAFE_CAST(gDBFile->GetOneObject(mBreakdownClassID, breakdownID),
CCostBreakdownEntry);
if (estBreakdownItem)
{
DB_ObjectWatcher watcher(estBreakdownItem);
estBreakdownItem->FillEstCatSubcatInfo(twoLevelArray, hideSoftCosts,
softCostAmount, hardCostAmount);
}
}
}
}
/*********************************************************************************

FillCatItemArray TCS 1/25/03

fill in an array of categories and items
*********************************************************************************/
void CEstimate::FillCatItemArray(const DBid reportID, TReportGroupArray *catArray) const
{
if (reportID != id_EstCatSubcatReport && reportID != id_EstCatReport &&
reportID != id_EstLocationReport)
return;

// loop thru breakdown items and have them fill the array
if (mBreakdownArray.GetCount() > 0)
{
if (reportID == id_EstLocationReport) // TCS 3/10/03
{
CLocationPackage::FillLocationItemArray(catArray);
}
else
{
// fill in an array of categories and subcategories
CCategorySystem *catSystem =
TCS_SAFE_CAST(gDBFile->GetOneObject(id_CategorySystem, GetCategorySystem()),
CCategorySystem);

if (catSystem)
{
DB_ObjectWatcher watcher (catSystem);
catSystem->FillCatItemArray(reportID, catArray);
}
else
CCategorySystem::FillDefaultCatItemArray(catArray);
}

// loop thru est breakdown items and fill in amounts
TObjectIDArrayIterator iterator(mBreakdownArray);
DBid breakdownID;
CBreakdownEntry *breakdownItem;

while (iterator.Next(breakdownID))
{
breakdownItem =
TCS_SAFE_CAST(gDBFile->GetOneObject(mBreakdownClassID, breakdownID),
CBreakdownEntry);
if (breakdownItem)
{
DB_ObjectWatcher watcher(breakdownItem);
breakdownItem->FillCatItemInfo(catArray, 0, false, reportID == id_EstLocationReport);
}
}
}
}
/*********************************************************************************

FillDataReport TCS 9/6/02

fill in a diagnostic table that shows data field values.

*********************************************************************************/
void CEstimate::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);

NeoVersion version = GetVersion();

FillFieldArrayRow(table, stream, "mLocationArray", mLocationArray);
FillFieldArrayRow(table, stream, "mDimensionArray", mDimensionArray);
FillFieldArrayRow(table, stream, "mLocationDimensionArray", mLocationDimensionArray);

FillFieldStringRow(table, stream, tag_name, mName);
FillFieldStringRow(table, stream, tag_address, mAddress);
FillFieldStringRow(table, stream, tag_details, mDetails);

if (version > 1)
FillFieldStringRow(table, stream, tag_scopeofwork, mScopeOfWork, true);

FillFieldObjectIDRow(table, stream, tag_jobtype, mProjectType, id_JobType);
FillFieldObjectIDRow(table, stream, tag_message, mMessage, id_Message);
FillFieldObjectIDRow(table, stream, tag_salesrep, mSalesRep, id_EmployeeAccount);
FillFieldObjectIDRow(table, stream, tag_paymentterm, mPaymentTerm, id_ProjectPaymentTerm);
FillFieldObjectIDRow(table, stream, tag_taxrate, mTaxRate, id_JobSalesTax);
FillFieldObjectIDRow(table, stream, tag_catsystem, mCatSystem, id_CategorySystem);
FillFieldObjectIDRow(table, stream, tag_locationpackage, mLocationPackage, id_LocationPackage);
FillFieldObjectIDRow(table, stream, tag_job, mProject, id_ProjectAccount);
FillFieldObjectIDRow(table, stream, tag_contractid, mContract, id_Contract);
FillFieldObjectIDRow(table, stream, tag_workinghours, mWorkingHours, id_WorkingHours);
FillFieldObjectIDRow(table, stream, tag_workcrew, mWorkCrew, id_WorkCrew);

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_projectsize, cMoneySize, mProjectSize.GetNumberString());
FillFieldTagRow(table, stream, tag_taxamount, cMoneySize, mTaxAmount.GetCurrencyString());

FillFieldTagRow(table, stream, tag_adjustpercent, cMoneySize, mAdjustPercent.GetPercentString());
FillFieldObjectIDRow(table, stream, tag_picture, mPictureID, id_Picture); // TCS 7/17/03

FillFieldEnumRow(table, stream, tag_timeperiod, mTimePeriod, MENU_BudgetPeriods);
FillFieldStockRow(table, stream, stockID_Expansion, cCharSize, SInt32(mSpareEnum));

FillFieldObjectIDRow(table, stream, tag_preparedby, mPreparedBy, id_EmployeeAccount);
FillFieldObjectIDRow(table, stream, tag_supervisor, mSupervisor, id_EmployeeAccount);

FillFieldEnumRow(table, stream, tag_status, mStatus, MENU_EstimateStatus);

FillFieldBitRow(table, stream, "mLocationsFromDims" , mLocationsFromDims, true);
FillFieldStockRow(table, stream, stockID_Padding, -7, SInt32(mPadding));

FillEndSafetyTag(table, stream, mEndSafetyTag);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

CanCopyBreakdown TCS 3/12/02

return whether we can copy a specific breakdown. We don't copy allowances,
bids or purchase orders.
*********************************************************************************/
Boolean CEstimate::CanCopyBreakdown(DB_PersistentObject *breakdown)
{
TCS_FailNILMsg(breakdown, TCS_GetErrString(errID_BadBreakdown));

UInt8 costArea = breakdown->GetCostArea();

switch (costArea)
{
case costtype_allowance:
case costtype_bid:
case costtype_powo:
return false;

default:
return true;
}
}
/*********************************************************************************

CanIncludeCostClass (static) TCS 9/14/98 rev 7/30/01

return whether the given class can be included in a report with the given params
*********************************************************************************/
Boolean CEstimate::CanIncludeCostClass(const UInt8 costClass, const Boolean includeSoft,
const Boolean includeAllowances)
{
switch (costClass)
{
case costtype_assembly:
case costtype_assmlabor: // TCS 11/26/03
case costtype_assmmaterial:
case costtype_bid:
case costtype_subcontractor:
case costtype_labor:
case costtype_material:
case costtype_equipment:
case costtype_unlistedlabor: // TCS 11/4/99
case costtype_unlistedmaterial:
case costtype_unlistedequip:
case costtype_unlistedsub:
case costtype_unlistedother:
case costtype_other:
case costtype_powo:
case costtype_contingencies:
case costtype_tool:
case costtype_obligation:
case costtype_salestax:
case costtype_delivery:
case costtype_changeorder:
return true;
break;

case costtype_allowance: // rev TCS 7/30/01
return includeAllowances;
break;

case costtype_overhead:
case costtype_softcost:
case costtype_profit:
case costtype_commission:
case costtype_percenthard:
case costtype_percenttotal:
case costtype_percentlabor: // TCS 11/8/02
case costtype_percentmaterial:
case costtype_percentsubs:
return includeSoft;
break;

case costtype_reminder:
case costtype_delay:
return false;
break;

default:
TCS_DebugAlert("Oops, bad case in CEstimate::CanIncludeCostClass!");
return false;
break;
}
}
/*********************************************************************************

SetAwardedStatus TCS 2/14/00 rev 12/20/00

award an estimate to a project. We change the status, store a ref to the job,
and also update any allowances, bids, or PO/WO's in our breakdowns.
*********************************************************************************/
DBid CEstimate::SetAwardedStatus(const UInt8 jobClass, const DBid jobID,
const Boolean removeItem, const DBid /*estimateID*/)
{
UInt8 saveType = PrepareViewerDisplay(); // TCS 8/22/00

if (removeItem)
SetToStarterStatus();
else
SetStatus(status_Awarded);

// remember the job TCS 2/29/00 rev 1/4/01
if (removeItem)
{
SetJob(0);
SetJobClass(0);
}
else
{
SetJob(jobID);
SetJobClass(jobClass);
}

// loop thru breakdowns and update any allowances, bids, purchase orders
if (mBreakdownArray.GetCount() > 0)
{

TObjectIDArrayIterator iterator(mBreakdownArray);
DBid breakdownID;

CCostBreakdownEntry *breakdownItem;

while (iterator.Next(breakdownID))
{
breakdownItem =
TCS_SAFE_CAST(gDBFile->GetOneObject(mBreakdownClassID, breakdownID),
CCostBreakdownEntry);
if (breakdownItem)
{
DB_ObjectWatcher watcher(breakdownItem);
breakdownItem->SetAwardedStatus(jobClass, jobID, removeItem, GetDBID());
}
}
}

MakeDirty();

// update the display TCS 3/21/00 rev TCS 10/23/00
UpdateViewerDisplay(saveType);

return 0; // return value is not important (it's there only for bids)
}
/*********************************************************************************

SetCompletedStatus TCS 12/22/00

the project has been completed. Deal with the change.

*********************************************************************************/
void CEstimate::SetCompletedStatus(const Boolean removeItem)
{
UInt8 saveType = PrepareViewerDisplay(); // TCS 8/22/00

if (removeItem)
SetStatus(status_Awarded);
else
SetStatus(status_Completed);

// loop thru breakdowns and update any allowances, bids, purchase orders
if (mBreakdownArray.GetCount() > 0)
{

TObjectIDArrayIterator iterator(mBreakdownArray);
DBid breakdownID;

CCostBreakdownEntry *breakdownItem;

while (iterator.Next(breakdownID))
{
breakdownItem =
TCS_SAFE_CAST(gDBFile->GetOneObject(mBreakdownClassID, breakdownID),
CCostBreakdownEntry);
if (breakdownItem)
{
DB_ObjectWatcher watcher(breakdownItem);
breakdownItem->SetCompletedStatus(removeItem);
}
}
}

MakeDirty();

// update the display TCS 3/21/00 rev TCS 10/23/00
UpdateViewerDisplay(saveType);
}
/*********************************************************************************

UpdateNetPrice TCS 12/13/00

recalculate the net amount after a change in gross price. Use this when
the gross price is changed remotely, while this object is not in a viewer.

This is the object-based equivalent to RecalcAmountWithTax in the viewers.

*********************************************************************************/
void CEstimate::UpdateNetAmount()
{
mTaxAmount = CJobSalesTax::CalculateSalesTaxAmount(mTaxRate, mGrossAmount); // rev TCS 7/23/01
mAmount = mGrossAmount + mTaxAmount;

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

UpdateLineItem TCS 9/6/00 rev 2/11/03

a bid, allowance or PO has changed. Need to change the breakdown and totals
*********************************************************************************/
void CEstimate::UpdateLineItem(const UInt8 costType, const DBid bidID, const CMoney &inAmount,
const CMoney &laborHours, const CMoney &crewSize, const Boolean perUnit)
{
TObjectIDArrayIterator iterator(mBreakdownArray);
DBid breakdownID,
breakdownBidID;
CCostBreakdownEntry *breakdown;
UInt8 costArea;
CMoney oldCost,
oldQuantity;

UInt8 saveSuccess = PrepareViewerDisplay(); // TCS 12/13/00

TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));

while (iterator.Next(breakdownID))
{
// fetch the breakdown object
breakdown = TCS_SAFE_CAST(gDBFile->GetOneObject(mBreakdownClassID, breakdownID),
CCostBreakdownEntry);
if (breakdown)
{
DB_ObjectWatcher watcher(breakdown);

costArea = breakdown->GetCostArea();

if (costArea == costType)
{
breakdownBidID = breakdown->GetCostItemID();
if (breakdownBidID == bidID)
{
// we found the bid
oldQuantity = breakdown->GetQuantity();
oldCost = breakdown->GetAmount();

if (perUnit)
{ // it's a per unit finished TCS 12/13/00
breakdown->SetUnitCost(inAmount);
breakdown->SetAmount(oldQuantity * inAmount);

mGrossAmount += (oldQuantity * inAmount - oldCost);
}
else
{
breakdown->SetUnitCost(inAmount);
breakdown->SetQuantity(1);
breakdown->SetAmount(inAmount);

mGrossAmount += (inAmount - oldCost);

UpdateNetAmount();
}

breakdown->SetHoursPerUnit(laborHours); // TCS 2/11/03
breakdown->SetCrewSize(crewSize);

MakeDirty();
}
}
}
}

UpdateViewerDisplay(saveSuccess); // TCS 12/13/00
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

DimensionIsLocked (static) TCS split 10/18/01

return whether the given dimension is locked in the given array. We make
this static so it can be used by calculators.
*********************************************************************************/
Boolean CEstimate::DimensionIsLocked(const TagType tag, TDimensionArray dimensionArray)
{
TDimensionArrayIterator iterator(dimensionArray);
SDimensionInfo info;

while (iterator.Next(info))
{
if (info.tag == tag)
return info.locked;
}

// if the dimension is not stored yet, it must be locked
return true;
}
/*********************************************************************************

DimensionIsLocked TCS 1/31/01

return whether the given dimension is locked here
*********************************************************************************/
Boolean CEstimate::DimensionIsLocked(const TagType tag) const
{
return DimensionIsLocked(tag, mDimensionArray);
}
/*********************************************************************************

GetDimensionInfo (static) TCS 10/18/01

return the dimension info for the given tag from the given dimension array.
We make this static so it can be used by calculators.
*********************************************************************************/
SDimensionInfo CEstimate::GetDimensionInfo(const TagType tag, TDimensionArray &dimensionArray)
{
TDimensionArrayIterator iterator(dimensionArray);
SDimensionInfo info;

// loop thru the data in the array, and fetch a struct if it's there
while (iterator.Next(info))
{
if (info.tag == tag)
return info;
}

// if we got this far, the item is not in the array yet, so let's fill in
// a value for it
info.tag = tag;
info.value = 0;
info.location = 0;
info.locked = true;
info.dirty = true;
info.spareByte = 0;

dimensionArray.Append(info); // TCS 1/1/02

return info;
}
/*********************************************************************************

LocationDimensionIsLocked (static) TCS split 11/5/01

return whether the given dimension is locked here
*********************************************************************************/
Boolean CEstimate::LocationDimensionIsLocked(const TagType tag, const UInt8 locationIndex,
TDimensionArray locDimensionArray)
{
TDimensionArrayIterator iterator(locDimensionArray);
SDimensionInfo info;

while (iterator.Next(info))
{
if (info.tag == tag && info.location == locationIndex)
return info.locked;
}

// if we got this far, it must be locked
return true;
}
/*********************************************************************************

LocationDimensionIsLocked TCS 8/24/01

return whether the given dimension is locked here
*********************************************************************************/
Boolean CEstimate::LocationDimensionIsLocked(const TagType tag, const UInt8 locationIndex) const
{
return LocationDimensionIsLocked(tag, locationIndex, mLocationDimensionArray);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

GetDimensionValue (static) TCS 10/18/01

return the dimension amount for the given tag from the given dimension array.
We make this static so it can be used by calculators.
*********************************************************************************/
CMoney CEstimate::GetDimensionValue(const TagType tag, const TDimensionArray &dimensionArray)
{
TDimensionArrayIterator iterator(dimensionArray);
SDimensionInfo info;

while (iterator.Next(info))
{
if (info.tag == tag)
return info.value;
}

// if we got this far, the value is not stored in the array, so
// we fetch the suggested amount from the dimension object
return CDimension::GetSuggestedAmount(tag);
}
/*********************************************************************************

GetDimensionValue TCS 1/31/01 rev 10/18/01

return the dimension amount for the given tag
*********************************************************************************/
CMoney CEstimate::GetDimensionValue(const TagType tag) const
{
return GetDimensionValue(tag, mDimensionArray);
}
/*********************************************************************************

GetLocationDimensionValue (static) TCS 11/3/01

return the dimension amount for the given tag and location from the given location
dimension array
*********************************************************************************/
CMoney CEstimate::GetLocationDimensionValue(const TagType tag, const TDimensionArray &dimensionArray,
const UInt8 locationID)
{
TDimensionArrayIterator iterator(dimensionArray);
SDimensionInfo info;

while (iterator.Next(info))
{
if (info.tag == tag && info.location == locationID)
return info.value;
}

// if we got this far, the value is not stored in the array, so
// we fetch the suggested amount from the dimension object
return CDimension::GetSuggestedAmount(tag);
}
/*********************************************************************************

GetLocationDimensionValue TCS 5/11/01

return the dimension amount for the given tag
*********************************************************************************/
CMoney CEstimate::GetLocationDimensionValue(const TagType tag, const UInt8 locationID) const
{
return GetLocationDimensionValue(tag, mLocationDimensionArray, locationID);
}
/*********************************************************************************

GetLocationDimensionInfo (static) TCS 10/18/01

return the dimension info for the given tag from the given location dimension
array and location id. We make this static so it can be used by calculators.
*********************************************************************************/
SDimensionInfo CEstimate::GetLocationDimensionInfo(const TagType tag, TDimensionArray &dimensionArray,
const UInt8 locationID)
{
TDimensionArrayIterator iterator(dimensionArray);
SDimensionInfo info;

// loop thru the data in the array, and fetch a struct if it's there
while (iterator.Next(info))
{
if (info.tag == tag && info.location == locationID)
return info;
}

// if we got this far, the item is not stored in the array yet. We'd better add it
info.tag = tag;
info.value = 0;
info.location = locationID;
info.locked = true; // bugfix TCS 1/1/02
info.dirty = true;
info.spareByte = 0;

dimensionArray.Append(info); // TCS 1/1/02

return info;
}
/*********************************************************************************

GetModifierAmount TCS 9/3/02

get the modifier amount for an assembly. We need to fetch the modifier ID
from the assembly and then retrieve that dimension amount
*********************************************************************************/
CMoney CEstimate::GetModifierAmount(const DBid assemblyID) const
{
if (assemblyID)
{
CAssembly *assembly = TCS_SAFE_CAST(gDBFile->GetOneObject(id_Assembly, assemblyID),
CAssembly);

if (assembly)
{
DB_ObjectWatcher watcher(assembly);

DBClass modifierClass = assembly->GetMaterialModifierClass();
DBid modifierID = assembly->GetMaterialModifierID();

if (modifierID && modifierClass)
{
TagType modifierTag = CCalculatorList::GetCalculatorTag(modifierClass, modifierID);
return GetDimensionValue(modifierTag);
}
}
}

// if we get this far there is no modifier
return 0;
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

SetDimensionValue (static) TCS split 10/18/01

set the dimension amount for the given tag in the given array. We make
this static so it can be easily used by calculators.
*********************************************************************************/
void CEstimate::SetDimensionValue(const TagType tag, const CMoney &inAmount,
const Boolean locked, TDimensionArray &dimensionArray)
{
TDimensionArrayIterator iterator(dimensionArray);
SDimensionInfo info;

while (iterator.Next(info))
{
if (info.tag == tag)
{
info.value = inAmount;
info.locked = locked; // bugfix TCS 8/24/01
info.dirty = false; // TCS 1/1/02
info.location = 0;
info.spareByte = 0;
dimensionArray.AssignItemAt(iterator.GetCurrentIndex(), info);
return;
}
}

// item is not in the array yet, so append it
info.tag = tag;
info.value = inAmount;
info.locked = locked;

dimensionArray.Append(info);
}
/*********************************************************************************

SetDimensionValue TCS 1/31/01

set the dimension amount for the given tag
*********************************************************************************/
void CEstimate::SetDimensionValue(const TagType tag, const CMoney &inAmount, const Boolean locked)
{
if (IsInDatabase())
TCS_TokenErrorAlert(errID_BadLengthChange, DB_ClassDescriptor::GetClassName(GetDBClassID()));
else
{
SetDimensionValue(tag, inAmount, locked, mDimensionArray);
MakeDirty(); // TCS 4/8/04
}
}
/*********************************************************************************

SetDimensionsDirty TCS 1/1/02

turn on the dirty bit for all stored dimensions.
*********************************************************************************/
void CEstimate::SetDimensionsDirty(const Boolean inValue)
{
TCS_ASSERTMsg(!IsInDatabase(), "Oops, SetDimensionsDirty called while in database!");

TDimensionArrayIterator iterator(mDimensionArray);
SDimensionInfo info;

while (iterator.Next(info))
{
info.dirty = inValue;
mDimensionArray.AssignItemAt(iterator.GetCurrentIndex(), info);
}

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

SetLocationsDirty TCS 1/1/02

turn on the dirty bit for all stored dimensions in the given location
*********************************************************************************/
void CEstimate::SetLocationsDirty(const UInt8 locationID, const Boolean inValue)
{
TCS_ASSERTMsg(!IsInDatabase(), "Oops, SetLocationDirty called while in database!");

TDimensionArrayIterator iterator(mLocationDimensionArray);
SDimensionInfo info;

while (iterator.Next(info))
{
if (info.location == locationID)
{
info.dirty = inValue;
mLocationDimensionArray.AssignItemAt(iterator.GetCurrentIndex(), info);
}
}

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

SetLocationDimensionValue (static) TCS split 11/5/01

set the location dimension amount for the given tag in the given array
*********************************************************************************/
void CEstimate::SetLocationDimensionValue(const TagType tag, const UInt8 locationID,
const CMoney &inAmount, const Boolean locked,
TDimensionArray &dimensionArray)
{
TDimensionArrayIterator iterator(dimensionArray);
SDimensionInfo info;

while (iterator.Next(info))
{
if (info.tag == tag && info.location == locationID)
{
info.value = inAmount;
info.locked = locked;
info.dirty = false;
dimensionArray.AssignItemAt(iterator.GetCurrentIndex(), info);
return;
}
}

// item is not in the array yet, so fill in a struct and append it
info.location = locationID;
info.spareByte = 0;
info.locked = locked;
info.tag = tag;
info.value = inAmount;

dimensionArray.Append(info);
}
/*********************************************************************************

SetLocationDimensionValue TCS 5/11/01

set the location dimension amount for the given tag
*********************************************************************************/
void CEstimate::SetLocationDimensionValue(const TagType tag, const UInt8 locationID,
const CMoney &inAmount, const Boolean locked)
{
if (IsInDatabase())
{
TCS_TokenErrorAlert(errID_BadLengthChange, DB_ClassDescriptor::GetClassName(GetDBClassID()));
}
else
{
DBClass calcClass = CCalculatorList::GetCalculatorClassID(tag);

if (calcClass == id_LocationDimension || calcClass == id_CalcLocation)
{
SetLocationDimensionValue(tag, locationID, inAmount, locked, mLocationDimensionArray);
}
else
{
SetDimensionValue(tag, inAmount, locked, mDimensionArray); // rev TCS 1/1/02
}

MakeDirty(); // TCS 4/8/04
}
}
/*********************************************************************************

SetDimensionArray TCS 6/7/03

replace the dimension array. This should happen only when the estimate
is not in the database
*********************************************************************************/
void CEstimate::SetDimensionArray(const TDimensionArray &inArray)
{
if (IsInDatabase() && !gIsClient)
{
TCS_TokenErrorAlert(errID_BadLengthChange, DB_ClassDescriptor::GetClassName(GetDBClassID()));
}
else
{
mDimensionArray = inArray;
}
}
/*********************************************************************************

SetLocationDimensionArray TCS 6/7/03

replace the location dimension array. This should happen only when the estimate
is not in the database
*********************************************************************************/
void CEstimate::SetLocationDimensionArray(const TDimensionArray &inArray)
{
if (IsInDatabase() && !gIsClient)
{
TCS_TokenErrorAlert(errID_BadLengthChange, DB_ClassDescriptor::GetClassName(GetDBClassID()));
}
else
{
mLocationDimensionArray = inArray;
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

GetNthLocationName TCS 4/13/01

return the Nth location name.
*********************************************************************************/
CTextString CEstimate::GetNthLocationName(const UInt8 index, const Boolean isSorted) const
{
SNameIDInfo info;
CTextString outName;

if (isSorted)
{
TNameIDArray nameArray = mLocationArray;
nameArray.SortWithComparator(NEW CListNameComparator);
if (nameArray.FetchItemAt(index, info) != LArray::index_Bad)
outName = CTextString(info.itemName);
else
outName = TCS_GetStockString(stockID_MissingItem);
}
else if (mLocationArray.FetchItemAt(index, info) != LArray::index_Bad)
outName = CTextString(info.itemName);
else
outName = TCS_GetStockString(stockID_MissingItem);

return outName;
}
/*********************************************************************************

GetNthLocationID TCS 4/13/01

return the Nth location id.
*********************************************************************************/
DBid CEstimate::GetNthLocationID(const UInt8 index, const Boolean isSorted) const
{
SNameIDInfo info;

if (isSorted)
{
TNameIDArray nameArray = mLocationArray;
nameArray.SortWithComparator(NEW CListNameComparator);
if (nameArray.FetchItemAt(index, info) != LArray::index_Bad)
return info.id;
}
else if (mLocationArray.FetchItemAt(index, info) != LArray::index_Bad)
return info.id;

return 0;
}
/*********************************************************************************

GetLocationIndex TCS 4/13/01

return the index position of the location with the given name.
*********************************************************************************/
UInt8 CEstimate::GetLocationIndex(const CTextString inName, const Boolean isSorted) const
{
TNameIDArray nameArray = mLocationArray;

if (isSorted)
nameArray.SortWithComparator(NEW CListNameComparator);

TNameIDArrayIterator iterator(nameArray);
SNameIDInfo info;
CTextString arrayName;

while (iterator.Next(info))
{
arrayName = CTextString(info.itemName);
if (arrayName == inName)
return iterator.GetCurrentIndex();
}

return 0;
}
/*********************************************************************************

GetLocationIndex TCS 4/13/01

return the index position of the location with the given id.
*********************************************************************************/
UInt8 CEstimate::GetLocationIndex(const DBid inID, const Boolean isSorted) const
{
TNameIDArray nameArray = mLocationArray;

if (isSorted)
nameArray.SortWithComparator(NEW CListNameComparator);

TNameIDArrayIterator iterator(nameArray);
SNameIDInfo info;

while (iterator.Next(info))
{
if (inID == info.id)
return iterator.GetCurrentIndex();
}

return 0;
}
/*********************************************************************************

GetLocationName TCS 7/10/01

return the name of the location with the given id.
*********************************************************************************/
CTextString CEstimate::GetLocationName(const DBid inID) const
{
TNameIDArrayIterator iterator(mLocationArray);
SNameIDInfo info;

while (iterator.Next(info))
{
if (inID == info.id)
return CTextString(info.itemName);
}

// if we got this far, the dimension doesn't exist
return TCS_GetStockString(stockID_MissingItem);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

AddLocation TCS 4/11/01 rev TCS 8/21/03

add a location
*********************************************************************************/
void CEstimate::AddLocation(const CTextString locationName, const DBid locationID)
{
// this method changes the object length, so it would be a serious
// error to call it on an object that is still in the database
if (IsInDatabase())
TCS_TokenErrorAlert(errID_BadLengthChange, DB_ClassDescriptor::GetClassName(GetDBClassID()));

SNameIDInfo info;
DBid nextID = locationID;
Boolean canAdd = true;

// check existing locations for duplicates, and for the next
// available ID number
TNameIDArrayIterator iterator(mLocationArray);

while (iterator.Next(info))
{
// is this location already there? TCS 8/21/03
if (locationName == CTextString(info.itemName))
{
canAdd = false;
break;
}

// check the ID
if (locationID)
{
// importing, check for duplicate ID's TCS 8/21/03
if (info.id == locationID)
{
canAdd = false;
break;
}
}
else if (info.id > nextID)
{
// new item, fetch the highest existing number
nextID = info.id;
}
}

// fill in values
if (canAdd)
{
TCS_BufferFromText(info.itemName, locationName);

if (locationID)
info.id = locationID;
else
info.id = nextID + 1;

// add to the location array
mLocationArray.Append(info);
}
}
/*********************************************************************************

RenameLocation TCS 4/11/01

rename a location
*********************************************************************************/
void CEstimate::RenameLocation(const UInt8 index, const CTextString locationName)
{
// this method changes the object length, so it would be a serious
// error to call it on an object that is still in the database
if (IsInDatabase())
TCS_TokenErrorAlert(errID_BadLengthChange, DB_ClassDescriptor::GetClassName(GetDBClassID()));

SNameIDInfo info;

// sort the location array rev TCS 11/28/01
CListNameComparator *comparator = NEW CListNameComparator;
TCS_FailNILMsg(comparator, TCS_GetErrString(errID_BadComparator));

TCS_TRY
{
mLocationArray.SetComparator(comparator, cDontDeleteComparator);
mLocationArray.Sort();

if (mLocationArray.FetchItemAt(index, info))
{
TCS_BufferFromText(info.itemName, locationName);
mLocationArray.AssignItemAt(index, info);
}
else
TCS_DebugAlert("Oops, bad index in CEstimate::RenameLocation!");


mLocationArray.Sort();
}
TCS_CATCH {}

mLocationArray.ClearComparator(comparator);
}
/*********************************************************************************

DeleteLocation TCS 4/13/01

delete the location at the given menu index
*********************************************************************************/
void CEstimate::DeleteLocation(const UInt8 index)
{
// this method changes the object length, so it would be a serious
// error to call it on an object that is still in the database
if (IsInDatabase())
TCS_TokenErrorAlert(errID_BadLengthChange, DB_ClassDescriptor::GetClassName(GetDBClassID()));

mLocationArray.SortWithComparator(NEW CListNameComparator); // rev TCS 11/28/01

SNameIDInfo info;

if (mLocationArray.FetchItemAt(index, info))
{
mLocationArray.RemoveItemAt(index);

// we should also remove any stored dimension values for this location
TDimensionArrayIterator iterator(mLocationDimensionArray);
SDimensionInfo dimInfo;

while (iterator.Next(dimInfo))
{
if (dimInfo.location == info.id)
mLocationDimensionArray.RemoveItemAt(iterator.GetCurrentIndex());
}

CalculateLocationDimensions();
}
else
TCS_DebugAlert("Oops, bad index in CEstimate::DeleteLocation!");
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

HandleDimensionChanged TCS 10/17/01

a dimension has changed- we need to reset its value in the stored array,
and update any other values that depend on it
*********************************************************************************/
CMoney CEstimate::HandleDimensionChanged(const TagType fieldTag, const CMoney &inValue,
const MessageT source)
{
// sanity check
TCS_ASSERTMsg(!IsInDatabase(), TCS_GetErrString(errID_BadLengthChange));

// first update the stored value
if (source == msg_PadlockOpened)
{
SetDimensionValue(fieldTag, inValue, false);
return inValue; // no need for further action
}
else if (source == msg_PadlockClosed)
{
SetDimensionValue(fieldTag, inValue, true);
}
else if (source == msg_EditFieldChanged || source == msg_PopupClicked ||
source == msg_CheckboxChanged)
{
SetDimensionValue(fieldTag, inValue, false);
}
else
{
TCS_DebugAlert("Oops, bad source in CEstimate::HandleDimensionChange!");
return inValue;
}

CMoney outValue = inValue;

// before we update calculators, set the dirty bit in all stored
// calculator values (since we don't know which ones will be affected
// by this change) TCS 1/1/02
SetDimensionsDirty();

// spin the cursor once
CCursorSpinner spinner; // TCS 1/1/02

// now pass it along to the calculator, so it can update
// any calculated values that depend on this value
DBClass calcClass = CCalculatorList::GetCalculatorClassID(fieldTag);
DBid calcID = CCalculatorList::GetCalculatorItemID(fieldTag);

DB_PersistentObject *calculator = gDBFile->GetOneObject(calcClass, calcID);

if (calculator)
{
DB_ObjectWatcher watcher(calculator);

if (source == msg_PadlockClosed)
outValue = calculator->GetCalcDimensionValue(mDimensionArray, mLocationDimensionArray);

calculator->UpdateDependentDimensions(mDimensionArray, mLocationDimensionArray);
}
else
ReportMissingObject(calcClass, calcID);

return outValue;
}
/*********************************************************************************

HandleLocationDimensionChanged TCS 10/29/01

a location dimension has changed- we need to reset its value in the stored array,
and update any other values that depend on it
*********************************************************************************/
CMoney CEstimate::HandleLocationDimensionChanged(const TagType fieldTag, const UInt8 locationID,
const CMoney &inValue, const MessageT source)
{
// sanity check
TCS_ASSERTMsg(!IsInDatabase(), TCS_GetErrString(errID_BadLengthChange));

if (source == msg_PadlockOpened)
{
// if a padlock was opened, all we need to do is reset the locked bit
SetDimensionValue(fieldTag, inValue, false);

// no need for any further action
return inValue;
}
else if (source == msg_PadlockClosed)
{
SetLocationDimensionValue(fieldTag, locationID, inValue, true);
}
else if (source == msg_EditFieldChanged || source == msg_PopupClicked ||
source == msg_CheckboxChanged)
{
SetLocationDimensionValue(fieldTag, locationID, inValue, false);
}
else
{
TCS_DebugAlert("Oops, bad source in CEstimate::HandleLocationDimensionChanged!");
return inValue;
}

CMoney outValue = inValue;

// before we update calculators, set the dirty bit in all stored
// calculator values for this location. We also mark regular calculators
// for an update TCS 1/1/02
SetLocationsDirty(locationID);
SetDimensionsDirty();

// spin the cursor once
CCursorSpinner spinner; // TCS 1/1/02

// now pass it along to the calculator, so it can update
// any calculated values that depend on this value
DBClass calcClass = CCalculatorList::GetCalculatorClassID(fieldTag);
DBid calcID = CCalculatorList::GetCalculatorItemID(fieldTag);

DB_PersistentObject *calculator = gDBFile->GetOneObject(calcClass, calcID);

if (calculator)
{
DB_ObjectWatcher watcher(calculator);

if (source == msg_PadlockClosed)
outValue = calculator->GetCalcLocationValue(mDimensionArray, mLocationDimensionArray, locationID);

calculator->UpdateDependentLocations(mDimensionArray, mLocationDimensionArray, locationID);
}
else
ReportMissingObject(calcClass, calcID);

return outValue;
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

CalculateLocationDimensions TCS 4/13/01

recalculate all dimensions that depend on locations
*********************************************************************************/
void CEstimate::CalculateLocationDimensions()
{
TCS_SysBeep();
}