Accounting Software
Small Business Software Estimating Software
Unit Cost SoftwareConstruction Estimating SoftwareProject Estimating SoftwareCost Estimation SoftwareCost Estimating SoftwareConstruction Management SoftwareBusiness Management Software

Category Systems (Source Code)

Link to: header | source 1 | source 3 | unit cost directory

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

This class manages category systems in the Goldenseal accounting software,
estimating software, unit cost software, job costing software and construction estimating software.

Source Code

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

GetCatInfo

return the information for the given category from its index

*********************************************************************************/
Boolean CCategorySystem::GetCatInfo(SInt32 catIndex, SCatInfo *outInfo) const
{
return mCategories.FetchItemAt(catIndex, *outInfo);
}/*********************************************************************************

GetSubcatInfo

return the information for the given subcategory from the index of cat & subcat

*********************************************************************************/
Boolean CCategorySystem::GetSubcatInfo(DBid catIndex,
SInt32 subcatIndex,
SSubcatInfo *outInfo) const
{
// first get the category info
SCatInfo catInfo;
if (GetCatInfo(catIndex, &catInfo))
{ // got the cat info, now let's get the subcat array
TSubCatArray *subArray = catInfo.subcatArray;
TCS_FailNILMsg(subArray,TCS_GetErrString(errID_BadArray));
return subArray->FetchItemAt(subcatIndex, *outInfo);
}
else
return false;
}
/*********************************************************************************

GetSubcatCount

return the number of subcategories for the given cat

*********************************************************************************/
SInt32 CCategorySystem::GetSubcatCount(const SInt32 catIndex)
{
// first get the category info
SCatInfo catInfo;
if (GetCatInfo(catIndex, &catInfo))
{ // got the cat info, now let's get the subcat array's count
TSubCatArray *subArray = catInfo.subcatArray;
if (subArray)
return subArray->GetCount();
else
return 0;
}
else
return 0;
}
/*********************************************************************************

GetCatInfoFromRef

return the information for the category with the given ref number

*********************************************************************************/
Boolean CCategorySystem::GetCatInfoFromRef(DBid ref, SCatInfo *outInfo) const
{
// sanity check
TCS_FailNILMsg(outInfo, TCS_GetErrString(errID_BadCatSystem));
// do a linear search for the ref
TCatArrayIterator iterator(mCategories);
while (iterator.Next(*outInfo))
{
if (outInfo->catID == ref)
return true;
}
// if we got here, means we didn't find the ref
return false;
}
/*********************************************************************************

GetSubcatInfoFromRef

return the information for the subcat with the given cat and subcat ref numbers

*********************************************************************************/
Boolean CCategorySystem::GetSubcatInfoFromRef(DBid catRef, DBid subcatRef,
SSubcatInfo *info) const
{
// sanity check
TCS_FailNILMsg(info, TCS_GetErrString(errID_BadCatSystem));
// first get the category
SCatInfo catInfo;
if (!GetCatInfoFromRef(catRef, &catInfo))
return nil;
// got the cat info, let's iterate the subcat array
CTmplArrayIterator<SSubcatInfo> iterator(*catInfo.subcatArray);
while (iterator.Next(*info))
{
if (info->subcatID == subcatRef)
return true;
}
// if we got here, means we didn't find the ref
return false;
}
/*********************************************************************************

GetCategoryCode TCS 3/28/01

return the code text for the given category

*********************************************************************************/
CTextString CCategorySystem::GetCategoryCode(const DBid category) const
{
SCatInfo info;
CTextString outString;

if (!category)
return outString;

// do a linear search for the ref
TCatArrayIterator iterator(mCategories);
while (iterator.Next(info))
{
if (info.catID == category)
{
outString = CTextString(info.code);
break;
}
}

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

GetCategoryClass TCS 3/28/01

return the category class for the given category

*********************************************************************************/
DBid CCategorySystem::GetCategoryClass(const DBid category) const
{
SCatInfo info;

if (!category)
return 0;

// do a linear search for the ref
TCatArrayIterator iterator(mCategories);
while (iterator.Next(info))
{
if (info.catID == category)
{
return info.costClass;
}
}

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

GetSubcatArray

return the subcat array for the given category

*********************************************************************************/
TSubCatArray *CCategorySystem::GetSubcatArray(const SInt32 catIndex) const
{
SCatInfo catInfo;
if (GetCatInfo(catIndex, &catInfo))
return catInfo.subcatArray;
else
return nil;
}
/*********************************************************************************

GetSubcatArrayFromRef

return the subcat array for the given category by ref. This is used
for building menu arrays

*********************************************************************************/
TSubCatArray *CCategorySystem::GetSubcatArrayFromRef(DBid catRef) const
{
SCatInfo catInfo;
if (GetCatInfoFromRef(catRef, &catInfo))
return catInfo.subcatArray;
else
return nil;
}
/*********************************************************************************

GetCategoriesInClass TCS 8/6/01

get a list of categories that belong to the given category class

*********************************************************************************/
TObjectIDArray CCategorySystem::GetCategoriesInClass(const DBid catClassID) const
{
TObjectIDArray outArray;
TCatArrayIterator iterator(mCategories);
SCatInfo info;

while (iterator.Next(info))
{
if (info.costClass == catClassID)
outArray.Append(info.catID);
}

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

AddCategory

add a newly created category. TCS removed params since not actually used 12/14/98

*********************************************************************************/
void CCategorySystem::AddCategory()
{
SCatInfo catInfo;
InitializeCatInfo(catInfo);

mCategories.Append(catInfo);
}/*********************************************************************************

AddSubcatToCatByRef

add a subcategory to the cat with the given ref

*********************************************************************************/
DBid CCategorySystem::AddSubcatToCatByRef(DBid catID, DBid subcatID,
CMoney taxRate, CMoney compRate)
{
// first get the cat info
SCatInfo catInfo;
TCS_ASSERTMsg(GetCatInfoFromRef(catID, &catInfo), TCS_GetErrString(errID_BadCatSystem));
// got it, now append the subcat
return AddSubcatToCat(catInfo, subcatID, taxRate, compRate);
}/*********************************************************************************

AddSubcatToCatByIndex

add a subcategory to the cat with the given index

*********************************************************************************/
DBid CCategorySystem::AddSubcatToCatByIndex(const SInt32 catIndex, DBid subcatID,
CMoney taxRate, CMoney compRate)
{
// first get the cat info
SCatInfo catInfo;
TCS_ASSERTMsg(GetCatInfo(catIndex, &catInfo), TCS_GetErrString(errID_BadCatSystem));
// got it, now append the subcat
return AddSubcatToCat(catInfo, subcatID, taxRate, compRate);
}/*********************************************************************************

AddSubcatToCat

add a subcategory to the cat

*********************************************************************************/
DBid CCategorySystem::AddSubcatToCat(const SCatInfo &catInfo, DBid subcatID,
CMoney taxRate, CMoney compRate)
{
// sanity check
TCS_FailNILMsg(catInfo.subcatArray, TCS_GetErrString(errID_BadArray));

// fill in the subcat information and append it
// to the cat's subcat array
SSubcatInfo subInfo;
subInfo.subcatID = subcatID;
subInfo.taxRate = taxRate;
subInfo.compRate = compRate;
catInfo.subcatArray->Append(subInfo);
return subcatID;
}
#if CAN_USE_MARK
#pragma mark -
#endif/*********************************************************************************

DeleteNamelessCats

delete categories with empty names

*********************************************************************************/
void CCategorySystem::DeleteNamelessCats()
{
SCatInfo catInfo;
SSubcatInfo subcatInfo;
TCatArrayIterator iterator(mCategories);

while (iterator.Next(catInfo))
{
if (catInfo.catID == 0)
{ // the category is empty
mCategories.Remove(catInfo);
TCS_Forget(catInfo.subcatArray); // TCS rev 11/5/00
}
else // remove nameless subcats TCS 7/5/00
{
TSubCatArrayIterator iterator(*catInfo.subcatArray);

while (iterator.Next(subcatInfo))
{
if (subcatInfo.subcatID == 0)
{
catInfo.subcatArray->Remove(subcatInfo);
}
}
}
}
}/*********************************************************************************

DeleteAllCats

kill all the current categories

*********************************************************************************/
void CCategorySystem::DeleteAllCats()
{
// must kill the subcat arrays. We place this in its own
// block so that the iterator will be disposed of
// before RemoveAllItems is called on the main array
{
TCatArrayIterator iterator(mCategories);
SCatInfo catInfo;
while (iterator.Next(catInfo))
{
TCS_Forget(catInfo.subcatArray); // TCS rev 11/5/00
}
}
// remove all the items in the category array
mCategories.RemoveAllItems();
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

IncludesCategory TCS 12/14/98

return whether the given category id is included in this system
*********************************************************************************/
Boolean CCategorySystem::IncludesCategory(const DBid catID, const Boolean subcatsAlso)
{
TCatArrayIterator iterator(mCategories);
SCatInfo catInfo;
while (iterator.Next(catInfo))
{
// first check the category itself
if (catInfo.catID == catID)
return true;

if (subcatsAlso)
{
// then check all subcategories
TSubCatArrayIterator subIterator(*catInfo.subcatArray);
SSubcatInfo subcatInfo;
while (subIterator.Next(subcatInfo))
{
if (subcatInfo.subcatID == catID)
return true;
}
}
}
// if we got this far, it's not included
return false;
}
/*********************************************************************************

HasSubcategories TCS 7/30/01

return whether this cat system has any subcategories
*********************************************************************************/
Boolean CCategorySystem::HasSubcategories() const
{
TCatArrayIterator iterator(mCategories);
SCatInfo info;

// loop thru each category and see if it has subcategories
while (iterator.Next(info))
{
if (info.subcatArray->GetCount() > 0)
return true;
}

// if we get this far, there are no subcategories
return false;
}
/*********************************************************************************

HandleCategoryMove TCS 11/27/01 rev 8/13/02

deal with a category that has been re-ordered
*********************************************************************************/
void CCategorySystem::HandleCategoryMove(const SMoveInfo moveInfo)
{
SInt32 sourceRow = ROW(moveInfo.source),
targetRow = ROW(moveInfo.target);

if (sourceRow == targetRow)
return;

SCatInfo sourceCat,
targetCat;

if (sourceRow < targetRow)
{
// moving down
for (SInt32 row = sourceRow; row < targetRow; row++)
{
mCategories.FetchItemAt(row, sourceCat);
mCategories.FetchItemAt(row + 1, targetCat);

mCategories.AssignItemAt(row + 1, sourceCat);
mCategories.AssignItemAt(row, targetCat);
}
}
else
{
// moving up
for (SInt32 row = sourceRow; row > targetRow; row--)
{
mCategories.FetchItemAt(row, sourceCat);
mCategories.FetchItemAt(row - 1, targetCat);

mCategories.AssignItemAt(row - 1, sourceCat);
mCategories.AssignItemAt(row, targetCat);
}
}
}
/*********************************************************************************

HandleCategoryInsertion TCS 7/1/03

deal with a category that has been added in the middle of a table. We
just add a blank item. It will be filled in later when we read data from
the table.
*********************************************************************************/
void CCategorySystem::HandleCategoryInsertion(const TableIndexT row)
{
SCatInfo catInfo;
InitializeCatInfo(catInfo);

mCategories.InsertItemAt(row, catInfo);
}
/*********************************************************************************

HandleCategoryDeleted TCS 7/1/03

deal with a category that has been deleted in the middle of a table
*********************************************************************************/
void CCategorySystem::HandleCategoryDeleted(const TableIndexT row)
{
mCategories.RemoveItemAt(row);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

InitializeCatInfo (static) split TCS 7/1/03

fill in default values for a SCatInfo struct, and allocate a subcategory
array. Caller is responsible for deleting the array.

*********************************************************************************/
void CCategorySystem::InitializeCatInfo(SCatInfo &catInfo)
{
catInfo.costClass = 0;
catInfo.catID = 0;
catInfo.code[0] = nil;
catInfo.filler = 0; // TCS 6/17/03
catInfo.taxRate = 0;
catInfo.compRate = 0;

catInfo.subcatArray = NEW TSubCatArray;
TCS_FailNILMsg(catInfo.subcatArray, TCS_GetErrString(errID_BadArray));
}
/*********************************************************************************

InitializeJobCostReportInfo (static) TCS 12/22/99

initialize a job cost report info struct
*********************************************************************************/
void CCategorySystem::InitializeJobCostReportInfo(SJobCostReportInfo &costInfo)
{
costInfo.id = 0;
costInfo.equipmentAmount = 0;
costInfo.laborAmount = 0;
costInfo.materialAmount = 0;
costInfo.subcontractorAmount = 0;
costInfo.otherAmount = 0;
costInfo.softAmount = 0; // TCS 8/1/01
costInfo.overheadAmount = 0;
costInfo.contractAmount = 0;
costInfo.incomeAmount = 0;
costInfo.percentCompleted = 0;
}
/*********************************************************************************

InitializeJobCostCategoryInfo TCS 7/30/01

initialize a job cost category info struct
*********************************************************************************/
void CCategorySystem::InitializeJobCostCategoryInfo(SJobCostCategoryInfo &costInfo)
{
costInfo.equipmentAmount = 0;
costInfo.laborAmount = 0;
costInfo.materialAmount = 0;
costInfo.subcontractorAmount = 0;
costInfo.otherAmount = 0;
costInfo.contractAmount = 0;
costInfo.incomeAmount = 0;
costInfo.changeAmount = 0;
}
/*********************************************************************************

InitializeJobCostCompareInfo TCS 8/1/01

initialize a job cost comparison info struct
*********************************************************************************/
void CCategorySystem::InitializeJobCostCompareInfo(SJobCostCompareInfo &costInfo)
{
costInfo.estEquipment = 0;
costInfo.estLabor = 0;
costInfo.estMaterials = 0;
costInfo.estSubcontractors = 0;
costInfo.estOther = 0;
costInfo.estSoft = 0;

costInfo.actualEquipment = 0;
costInfo.actualLabor = 0;
costInfo.actualMaterials = 0;
costInfo.actualSubcontractors = 0;
costInfo.actualOther = 0;
costInfo.actualSoft = 0;

costInfo.percentDone = 0;
costInfo.valueCompleted = 0;

// start with a nil array.
costInfo.itemArray = nil; // TCS 1/29/02
}
/*********************************************************************************

InitializeJobCostClassInfo TCS 8/1/01

initialize a job cost comparison info struct
*********************************************************************************/
/*void CCategorySystem::InitializeJobCostClassInfo(SJobCostClassInfo &costInfo)
{
InitializeJobCostCompareInfo(costInfo.totalInfo);
costInfo.subcatArray = nil;
}*/
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

FillCostReportArray

fill a cost array with categories. This struct is used for progress billing
*********************************************************************************/
Boolean CCategorySystem::FillCostReportArray(TJobCostReportArray &costArray) const
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
// initialize a struct
SJobCostReportInfo costInfo;

InitializeJobCostReportInfo(costInfo);

// prepare to iterate
SCatInfo catInfo;
CTextString catName;
TCatArrayIterator iterator(mCategories);


// loop thru categories and add them to the array
while (iterator.Next(catInfo))
{
costInfo.id = catInfo.catID;

// fetch the category name
if (!gDBFile->GetObjectName(id_Category, catInfo.catID, catName))
{
catName = TCS_GetStockString(stockID_MissingItem);
}
TCS_BufferFromText(costInfo.catName, catName);

costArray.Append(costInfo);
}

return true;
}
/*********************************************************************************

FillCostCategoryArray TCS 9/9/98

fill a cost array with categories. This struct is used for job costs.
*********************************************************************************/
Boolean CCategorySystem::FillCostCategoryArray(TJobCostCategoryArray &costArray) const
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));

// initialize a cat info struct
SJobCostCategoryInfo costInfo;
InitializeJobCostCategoryInfo(costInfo);

// prepare to iterate
SCatInfo catInfo;
CTextString catName;

TCatArrayIterator iterator(mCategories);

// loop thru categories and add them to the array
while (iterator.Next(catInfo))
{
costInfo.id = catInfo.catID;

// fetch the category name
if (!gDBFile->GetObjectName(id_Category, catInfo.catID, catName))
{
catName = TCS_GetStockString(stockID_MissingItem);
}
TCS_BufferFromText(costInfo.catName, catName);

// create an item array
costInfo.itemArray = NEW TObjectInfoArray;
TCS_FailNILMsg(costInfo.itemArray, TCS_GetErrString(errID_BadArray));

// add it to the array
costArray.Append(costInfo);
}
// finish with 'unallocated' category
costInfo.id = cUnallocatedItem; // rev TCS 2/22/00
TCS_BufferFromText(costInfo.catName, TCS_GetStockString(stockID_Unallocated));
costInfo.itemArray = NEW TObjectInfoArray;
TCS_FailNILMsg(costInfo.itemArray, TCS_GetErrString(errID_BadArray));

// add it to the array
costArray.Append(costInfo);

return true;
}
/*********************************************************************************

FillCostSubcategoryArray TCS 7/30/01

fill a cost array with subcategories in the given category. This struct
is used for job costs.
*********************************************************************************/
Boolean CCategorySystem::FillCostSubcategoryArray(TJobCostCategoryArray &costArray,
const DBid matchCategory) const
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));

// initialize a cat info struct
SJobCostCategoryInfo costInfo;
InitializeJobCostCategoryInfo(costInfo);

// prepare to iterate
SCatInfo catInfo;
CTextString catName;

TCatArrayIterator iterator(mCategories);

// loop thru categories and add them to the array
while (iterator.Next(catInfo))
{
if (catInfo.catID == matchCategory)
{
TCS_FailNILMsg(catInfo.subcatArray, TCS_GetErrString(errID_BadArray));

TSubCatArrayIterator subIterator(*catInfo.subcatArray);
SSubcatInfo subcatInfo;

while (subIterator.Next(subcatInfo))
{
costInfo.id = subcatInfo.subcatID;

// fetch the subcategory name
if (!gDBFile->GetObjectName(id_Category, subcatInfo.subcatID, catName))
{
catName = TCS_GetStockString(stockID_MissingItem);
}
TCS_BufferFromText(costInfo.catName, catName);

// create an item array
costInfo.itemArray = NEW TObjectInfoArray;
TCS_FailNILMsg(costInfo.itemArray, TCS_GetErrString(errID_BadArray));

// add it to the array
costArray.Append(costInfo);
}
}
}
// finish with 'unallocated' category
costInfo.id = cUnallocatedItem; // rev TCS 2/22/00
TCS_BufferFromText(costInfo.catName, TCS_GetStockString(stockID_Unallocated));
costInfo.itemArray = NEW TObjectInfoArray;
TCS_FailNILMsg(costInfo.itemArray, TCS_GetErrString(errID_BadArray));

// add it to the array
costArray.Append(costInfo);

return true;
}
/*********************************************************************************

FillAllCategoryArray TCS 3/8/00

fill a cost array with all locations. This struct is used for progress billing
when category systems are not being used.
*********************************************************************************/
Boolean CCategorySystem::FillAllCategoryArray(TJobCostReportArray &costArray,
const Boolean includeUnallocated)
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
// initialize a struct
SJobCostReportInfo costInfo;
CCategorySystem::InitializeJobCostReportInfo(costInfo);

// fetch an array of all categories
TNameIDArray nameArray;
DB_ListManager::GetNameIDArray(id_Category, &nameArray);

// prepare to iterate
SNameIDInfo info;
TNameIDArrayIterator iterator(nameArray);

// loop thru items and add them to the array
while (iterator.Next(info))
{
costInfo.id = info.id;

// fetch the location name. We can do a direct string
// copy since both buffers are the same length
TCS_StringCopy(costInfo.catName, info.itemName);

costArray.Append(costInfo);
}

// finish with 'unallocated' location
if (includeUnallocated)
{
costInfo.id = cUnallocatedItem; // TCS rev 2/22/00
TCS_BufferFromText(costInfo.catName, TCS_GetStockString(stockID_Unallocated));
costArray.Append(costInfo);
}

return true;
}
/*********************************************************************************

FillProgressArray TCS 9/15/99

fill a progress array with categories. This struct is used for job costs variance
report
*********************************************************************************/
Boolean CCategorySystem::FillProgressArray(TJobCostProgressArray &costArray) const
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));

// initialize a cat info struct
SJobCostProgressInfo costInfo;
costInfo.contractAmount = 0;
costInfo.percentCompleted = 0;
costInfo.costAmount = 0;
costInfo.valueCompleted = 0;

// prepare to iterate
SCatInfo catInfo;
CTextString catName;

TCatArrayIterator iterator(mCategories);

// loop thru categories and add them to the array
while (iterator.Next(catInfo))
{
costInfo.id = catInfo.catID;

// fetch the category name
if (!gDBFile->GetObjectName(id_Category, catInfo.catID, catName))
{
catName = TCS_GetStockString(stockID_MissingItem);
}
TCS_BufferFromText(costInfo.catName, catName);

costArray.Append(costInfo);
}
// finish with 'unallocated' category
costInfo.id = cUnallocatedItem; // TCS rev 2/22/00
TCS_BufferFromText(costInfo.catName, TCS_GetStockString(stockID_Unallocated));
costArray.Append(costInfo);

return true;
}
/*********************************************************************************

FillDefaultCostArray TCS 9/12/98

fill in a category array when there is no category system
*********************************************************************************/
Boolean CCategorySystem::FillDefaultCostArray(TJobCostCategoryArray &costArray,
const Boolean includeAllCats)
{
// fill in an empty struct
SJobCostCategoryInfo costInfo;

costInfo.equipmentAmount = 0;
costInfo.laborAmount = 0;
costInfo.materialAmount = 0;
costInfo.subcontractorAmount = 0;
costInfo.otherAmount = 0;
costInfo.contractAmount = 0;
costInfo.incomeAmount = 0;
costInfo.changeAmount = 0;

costInfo.itemArray = nil;

if (includeAllCats) // TCS 9/2/00s
{
TNameIDArray allCatArray;
DB_ListManager::GetNameIDArray(id_Category, &allCatArray);
TNameIDArrayIterator iterator(allCatArray);
SNameIDInfo info;

while (iterator.Next(info))
{
costInfo.id = info.id;

// copy the name. We can do a direct string copy
// since both buffers are the same length
TCS_StringCopy(costInfo.catName, info.itemName);

costInfo.itemArray = NEW TObjectInfoArray; // moved TCS 10/31/01
TCS_FailNILMsg(costInfo.itemArray, TCS_GetErrString(errID_BadArray));

// add it to the array
costArray.Append(costInfo);
}
}
else
{
// all we do is an 'unallocated' category
costInfo.id = cUnallocatedItem; // TCS rev 2/22/00
TCS_BufferFromText(costInfo.catName, TCS_GetStockString(stockID_Unallocated));

costInfo.itemArray = NEW TObjectInfoArray; // moved TCS 10/31/01
TCS_FailNILMsg(costInfo.itemArray, TCS_GetErrString(errID_BadArray));

// add it to the array
costArray.Append(costInfo);
}

return true;
}
/*********************************************************************************

FillDefaultProgressArray (static) TCS 9/15/99

fill in a category array when there is no category system
*********************************************************************************/
Boolean CCategorySystem::FillDefaultProgressArray(TJobCostProgressArray &costArray)
{
// prepare to iterate
SJobCostProgressInfo costInfo;

costInfo.contractAmount = 0;
costInfo.costAmount = 0;
costInfo.percentCompleted = 0;
costInfo.valueCompleted = 0;

// all we do is an 'unallocated' category
costInfo.id = cUnallocatedItem; // TCS rev 2/22/00
TCS_BufferFromText(costInfo.catName, TCS_GetStockString(stockID_Unallocated));
costArray.Append(costInfo);

return true;
}