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 2 | source 3 | unit cost directory

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

Comments

CCategorySystem

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

It's a cost category system, containing categories and subcategories.

Users will generally set up 2 or more category systems so they can
job cost overhead and project expenses.

The category system also sets up cost classes and category taxes

SUPERCLASS = DB_DescribedPersistent

Constructor

/*********************************************************************************
constructor
*********************************************************************************/
CCategorySystem::CCategorySystem()
{
mTaxAsPercent = mCompAsPercent = true;
mRequireSubcats = false;
mDefaultCompRate = mDefaultTaxRate = 0;
mPadding = 0; // TCS 3/27/02

mIncludeInStarterFile = true; // TCS 12/5/02

mEndSafetyTag = tag_endsafetytag; // TCS 9/8/02
}/*********************************************************************************
destructor
*********************************************************************************/
CCategorySystem::~CCategorySystem()
{
DeleteAllCats();
}

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 CCategorySystem::CopyFrom(DB_PersistentObject *source, const UInt8 copyFlags)
{
THE_SUPERCLASS::CopyFrom(source, copyFlags);

CCategorySystem *src = TCS_SAFE_CAST(source, CCategorySystem);
TCS_FailNILMsg(src, TCS_GetErrString(errID_BadRecord));

TCS_BlockMove(&src->mDefaultCompRate, &mDefaultCompRate, cCopyFileLength);

// we need to copy over the contents of the arrays. First
// get rid of anything we've got
DeleteAllCats();

// now walk the source cate system's arrays and
// copy them over
TCatArrayIterator iterator(src->mCategories);
SCatInfo catInfo;
while (iterator.Next(catInfo))
{
catInfo.subcatArray = NEW TSubCatArray(*catInfo.subcatArray);
mCategories.Append(catInfo);
}
}
/*********************************************************************************

GetFileLength rev TCS 3/28/02

return the file length used by this object

*********************************************************************************/
NeoSize CCategorySystem::GetFileLength(const CNeoFormat *aFormat) const
{
// start with the size of the category count. We don't get the
// category array size, since we don't read/write it directly.
NeoSize size = sizeof(SInt32); // bugfix TCS 3/28/02

// now we must add the size of each subcategory array
TCatArrayIterator iterator(mCategories);
SCatInfo catInfo;

while (iterator.Next(catInfo))
{
size += cCatStructLength;
TCS_FailNILMsg(catInfo.subcatArray, TCS_GetErrString(errID_BadArray));
size += ARRAY_FILE_SIZE(*catInfo.subcatArray);
}

return DB_DescribedPersistent::GetFileLength(aFormat) + size + cFileLength;
}

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

CopyArrayFrom

copy arrays from one cat system to another. Used when updating from a temp
object. Formerly called SimpleCopyFrom

*********************************************************************************/
void CCategorySystem::CopyArrayFrom(DB_PersistentObject *source)
{
CCategorySystem *src = TCS_SAFE_CAST(source, CCategorySystem);
TCS_FailNILMsg(src, TCS_GetErrString(errID_BadRecord));

// First get rid of anything we've got
DeleteAllCats();
// now walk the sourc cat system's arrays and copy them over
TCatArrayIterator iterator(src->mCategories);
SCatInfo catInfo;
while (iterator.Next(catInfo))
{
catInfo.subcatArray = NEW TSubCatArray(*catInfo.subcatArray);
mCategories.Append(catInfo);
}
}/*********************************************************************************

GetMemberValue

get the value of the member with the given tag

*********************************************************************************/
Boolean CCategorySystem::GetMemberValue(const TagType aTag,
const TagType aType,
void *aValue) const
{
switch (aTag)
{
case tag_taxaspercent:
return ConvertBitFieldMember(mTaxAsPercent, aValue, aType);
break;

case tag_compaspercent:
return ConvertBitFieldMember(mCompAsPercent, aValue, aType);
break;

case tag_requiresubcats:
return ConvertBitFieldMember(mRequireSubcats, aValue, aType);
break;

case tag_defaultcomprate:
return ConvertMember(&mDefaultCompRate, type_emoney, aValue, aType);
break;

case tag_defaulttaxrate:
return ConvertMember(&mDefaultTaxRate, type_emoney, aValue, aType);
break;

case tag_includeinstarter: // TCS 12/5/02
return ConvertBitFieldMember(mIncludeInStarterFile, aValue, aType);
break;

default:
return THE_SUPERCLASS::GetMemberValue(aTag, aType, aValue);
break;
}
}/*********************************************************************************

SetMemberValue

set the value of the member with the given tag

*********************************************************************************/
Boolean CCategorySystem::SetMemberValue(const TagType aTag,
const TagType aType,
const void *aValue)
{
switch (aTag)
{
case tag_taxaspercent:
mTaxAsPercent = ConvertDataToBitField(aValue, aType);
return true;
break;

case tag_compaspercent:
mCompAsPercent = ConvertDataToBitField(aValue, aType);
return true;
break;

case tag_requiresubcats:
mRequireSubcats = ConvertDataToBitField(aValue, aType);
return true;
break;

case tag_defaultcomprate:
return ConvertMember(aValue, aType, &mDefaultCompRate, type_emoney);
break;

case tag_defaulttaxrate:
return ConvertMember(aValue, aType, &mDefaultTaxRate, type_emoney);
break;

case tag_includeinstarter: // TCS 12/5/02
mIncludeInStarterFile = ConvertDataToBitField(aValue, aType);
return true;
break;

default:
return THE_SUPERCLASS::SetMemberValue(aTag, aType, aValue);
break;
}
}/*********************************************************************************

ReadObject

read the persistent object's data in from a stream

*********************************************************************************/
void CCategorySystem::ReadObject(CNeoStream *aStream, const TagType aTag)
{
TCS_FailNILMsg(aStream, TCS_GetErrString(errID_BadStream));

CNeoDebugImport checker(aStream, this, cCheckTooSmall); // TCS 2/24/00

THE_SUPERCLASS::ReadObject(aStream, aTag);

if (!IsIOValid()) // TCS 2/5/02
return;

// kill any existing cats and subcats, as we will
// be totally reloading them
DeleteAllCats();

// read in how many categories there are
SInt32 catCount = aStream->ReadLong(GetReadFormat()); // rev TCS 6/15/03

// read each category, including the subcat array
SCatInfo catInfo;
for (SInt32 i = 1; i <= catCount; i++)
{
//aStream->ReadChunk(&catInfo, cCatStructLength); // TCS rev 3/28/02

catInfo.catID = aStream->ReadLong(); // TCS bugfix 6/17/03
catInfo.costClass = aStream->ReadLong();
aStream->ReadChunk(&catInfo.code, cCatCodeLength + 1);
catInfo.filler = aStream->ReadChar();
catInfo.compRate.ReadFromStream(aStream);
catInfo.taxRate.ReadFromStream(aStream);

// right now we clear the filler byte since it wasn't
// initialized for older data. TCS 6/17/03
catInfo.filler = 0;

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

ReadSubcatArrayFromStream(aStream, *catInfo.subcatArray, cHasSafetyTag);
mCategories.Append(catInfo);
}

/// aStream->ReadChunk(&mDefaultCompRate, cFileLength);

mDefaultCompRate.ReadFromStream(aStream); // mfs_sa rev 20feb2k3
mDefaultTaxRate.ReadFromStream(aStream);

*((UInt8*)&mDefaultTaxRate + sizeof(mDefaultTaxRate)) = aStream->ReadBits(4); // --Bitfield

mPadding = aStream->ReadChar();

mEndSafetyTag = aStream->ReadEndSafetyTag(this);

if (!IsValidEndTag(mEndSafetyTag)) // TCS 9/8/02
ReportDamagedObject(GetDBClassID(), GetDBID());
}/*********************************************************************************

WriteObject

write the persistent object's data to a stream

*********************************************************************************/
void CCategorySystem::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(mEndSafetyTag))
{
ReportDamagedObject(GetDBClassID(), GetDBID());
mEndSafetyTag = tag_endsafetytag; // TCS 11/26/02
}

// after the blob is set up we can write as usual
CNeoDebugExport checker(aStream, this, cCheckTooSmall);

THE_SUPERCLASS::WriteObject(aStream, aTag);

// write out how many categories there are. Note that we
// do NOT write out the mCategories array itself
aStream->WriteLong(mCategories.GetCount());

// write out the categories, including information for
// each subarray just after the category info
TCatArrayIterator iterator(mCategories);
SCatInfo catInfo;
while (iterator.Next(catInfo))
{
// write out the category information
//aStream->WriteChunk(&catInfo, cCatStructLength); // TCS rev 3/28/02

aStream->WriteLong(catInfo.catID); // TCS bugfix 6/17/03
aStream->WriteLong(catInfo.costClass);
aStream->WriteChunk(&catInfo.code, cCatCodeLength + 1);
aStream->WriteChar(catInfo.filler);
catInfo.compRate.WriteToStream(aStream);
catInfo.taxRate.WriteToStream(aStream);

// now write out the subcategory information
WriteSubcatArrayToStream(aStream, *catInfo.subcatArray, cHasSafetyTag);
}

// finally, write out basic object info

/// aStream->WriteChunk(&mDefaultCompRate, cFileLength);

mDefaultCompRate.WriteToStream(aStream); // mfs_sa rev 20feb2k3
mDefaultTaxRate.WriteToStream(aStream);

aStream->WriteChar(*((UInt8*)&mDefaultTaxRate + sizeof(mDefaultTaxRate))); // --Bitfield

aStream->WriteChar(mPadding);

aStream->WriteEndSafetyTag(mEndSafetyTag, this);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

CCategorySystem_Desc
GetTableColInfo

return information about table columns
*********************************************************************************/
Boolean CCategorySystem_Desc::GetTableColInfo(const TagType tag, const TableIndexT col,
STableColInfo *colInfo)
{
if (tag == tag_cattable)
{ // it's the cat system table
switch (col)
{
case CCategorySystem::col_cat:
colInfo->colType = coltype_cv;
colInfo->fieldType = fieldtype_cv;
colInfo->colData = id_Category;
TCS_BufferFromText(colInfo->colName,
TCS_GetStockString(stockID_Category), cTableColNameLength);
return true;
break;

case CCategorySystem::col_costclass:
colInfo->colType = coltype_cv;
colInfo->fieldType = fieldtype_cv;
colInfo->colData = id_CategoryClass;
TCS_BufferFromText(colInfo->colName,
TCS_GetStockString(stockID_Class), cTableColNameLength);
return true;
break;

case CCategorySystem::col_catcode:
colInfo->colType = coltype_edit;
colInfo->fieldType = fieldtype_string;
colInfo->colData = 0;
TCS_BufferFromText(colInfo->colName,
TCS_GetStockString(stockID_Code), cTableColNameLength);
return true;
break;

case CCategorySystem::col_cattaxrate:
colInfo->colType = coltype_edit;
colInfo->fieldType = fieldtype_emoney;
colInfo->colData = 0;
TCS_BufferFromText(colInfo->colName,
TCS_GetStockString(stockID_TaxRate), cTableColNameLength);
return true;
break;

case CCategorySystem::col_catcomprate:
colInfo->colType = coltype_edit;
colInfo->fieldType = fieldtype_emoney;
colInfo->colData = 0;
TCS_BufferFromText(colInfo->colName,
TCS_GetStockString(stockID_CompRate), cTableColNameLength);
return true;
break;

default:
return false;
break;
}
}
else if (tag == tag_subcattable)
{
switch (col)
{
case CCategorySystem::col_subcat:
colInfo->colType = coltype_cv;
colInfo->fieldType = fieldtype_cv;
colInfo->colData = id_Category;
TCS_BufferFromText(colInfo->colName,
TCS_GetStockString(stockID_Subcat), cTableColNameLength);
return true;
break;

case CCategorySystem::col_subcattaxrate:
colInfo->colType = coltype_edit;
colInfo->fieldType = fieldtype_emoney;
colInfo->colData = 0;
TCS_BufferFromText(colInfo->colName,
TCS_GetStockString(stockID_TaxRate), cTableColNameLength);
return true;
break;

case CCategorySystem::col_subcatcomprate:
colInfo->colType = coltype_edit;
colInfo->fieldType = fieldtype_emoney;
colInfo->colData = 0;
TCS_BufferFromText(colInfo->colName,
TCS_GetStockString(stockID_CompRate), cTableColNameLength);
return true;
break;

default:
return false;
break;
}
}
else
return false;
}
/*********************************************************************************

ExportCatCString

return the value of a category column element TCS 6/12/98

*********************************************************************************/
CTextString CCategorySystem::ExportCatCString(const SInt32 catIndex,
const TableIndexT col)
{
SCatInfo catInfo;
CTextString menuText;

if (GetCatInfo(catIndex, &catInfo))
{
switch (col)
{
case col_cat:
if (FetchCVMenuText(col, catInfo.catID, &menuText))
return menuText.AppendCVExportString(catInfo.catID);
else
return cEmptyString;

case col_costclass:
if (FetchCVMenuText(col, catInfo.costClass, &menuText))
return menuText.AppendCVExportString(catInfo.costClass);
else
return cEmptyString;
break;

case col_catcode:
return CTextString(catInfo.code);
break;

case col_cattaxrate:
if (mTaxAsPercent)
return catInfo.taxRate.GetPercentString();
else
return catInfo.taxRate.GetExtendedCurrencyString();
break;

case col_catcomprate:
if (mCompAsPercent)
return catInfo.compRate.GetPercentString();
else
return catInfo.compRate.GetExtendedCurrencyString();
break;

default:
return menuText;
break;
}
}
else
return menuText;
}
/*********************************************************************************

ExportSubcatCString

return the value of a subcategory column element TCS 6/12/98

*********************************************************************************/
CTextString CCategorySystem::ExportSubcatCString(const SInt32 catIndex,
const SInt32 subcatIndex,
const TableIndexT col)
{
SSubcatInfo subcatInfo;
if (GetSubcatInfo(catIndex, subcatIndex, &subcatInfo))
{
switch (col)
{
case col_subcat:
{
CTextString menuText;
if (FetchCVMenuText(col, subcatInfo.subcatID, &menuText))
return menuText.AppendCVExportString(subcatInfo.subcatID);
else
return cEmptyString;
}

case col_subcattaxrate:
{
if (mTaxAsPercent)
return subcatInfo.taxRate.GetPercentString();
else
return subcatInfo.taxRate.GetExtendedCurrencyString();
}
break;

case col_subcatcomprate:
{
if (mCompAsPercent)
return subcatInfo.compRate.GetPercentString();
else
return subcatInfo.compRate.GetExtendedCurrencyString();
}
break;

default:
return cEmptyString;
break;
}
}
else
return cEmptyString;
}
/*********************************************************************************

ImportCatCString

fill a column element in our category struct TCS 6/12/98

*********************************************************************************/
Boolean CCategorySystem::ImportCatCString(const SInt32 catIndex,
const TableIndexT col,
const CTextString &inString)
{
if (catIndex > GetCatCount())
AddCategory();
// we should never have to add more than one category at a time
TCS_ASSERTMsg( catIndex == GetCatCount(), TCS_GetErrString(errID_BadCatSystem));

// fill in category info
SCatInfo catInfo;
if (GetCatInfo(catIndex, &catInfo))
{
switch (col)
{
case col_cat:
catInfo.catID = inString.ParseID();
break;

case col_costclass:
catInfo.costClass = inString.ParseID();
break;

case col_catcode: // we don't allow punct (may use in menus someday)
TCS_BufferFromText(catInfo.code, ConvertImportCString(inString,
cCatCodeLength, false), cCatCodeLength + 1);
break;

case col_cattaxrate:
catInfo.taxRate = ConvertImportEMoney(inString);
break;

case col_catcomprate:
catInfo.compRate = ConvertImportEMoney(inString);
break;

default:
return false;
break;
}
SetCatInfo(catIndex, catInfo, true);
return true;
}
return false;
}
/*********************************************************************************

ImportSubcatCString

fill a column element in our subcategory struct TCS 6/12/98

*********************************************************************************/
Boolean CCategorySystem::ImportSubcatCString(const SInt32 catIndex,
const SInt32 subcatIndex,
const TableIndexT col,
const CTextString &inString)
{
if (subcatIndex > GetSubcatCount(catIndex))
AddSubcatToCatByIndex(catIndex);
// we should never have to add more than one category
TCS_ASSERTMsg( subcatIndex == GetSubcatCount(catIndex), TCS_GetErrString(errID_BadCatSystem));

// fill in category info
SSubcatInfo subcatInfo;
if (GetSubcatInfo(catIndex, subcatIndex, &subcatInfo))
{
switch (col)
{
case col_subcat:
subcatInfo.subcatID = inString.ParseID();
break;

case col_subcattaxrate:
subcatInfo.taxRate = ConvertImportEMoney(inString);
break;

case col_subcatcomprate:
subcatInfo.compRate = ConvertImportEMoney(inString);
break;

default:
return false;
break;
}
SetSubcatInfo(catIndex, subcatIndex, subcatInfo);
return true;
}
return false;
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

PostImportNew

post an import action
*********************************************************************************/
void CCategorySystem::PostImportNew(const Boolean /*fromPostAction*/)
{
AdjustCategoryArrays();
}
/*********************************************************************************

PostNewRecord TCS 12/14/98

we add this system to the array in all the categories it includes

*********************************************************************************/
void CCategorySystem::PostNewRecord(const UInt8 creationType)
{
AdjustCategoryArrays();

THE_SUPERCLASS::PostNewRecord(creationType);
}
/*********************************************************************************

PostDeletion TCS 12/14/98

we override to remove this record from any account arrays

*********************************************************************************/
void CCategorySystem::PostDeletion(const Boolean postAudit)
{
AdjustCategoryArrays(true);

THE_SUPERCLASS::PostDeletion(postAudit);
}
/*********************************************************************************

PostRecordChanging TCS 12/14/98

a record will be changing. Post the change.
*********************************************************************************/
void CCategorySystem::PostRecordChanging(const Boolean accountChanging,
const Boolean jobChanging)
{
AdjustCategoryArrays(true);

THE_SUPERCLASS::PostRecordChanging(accountChanging, jobChanging);
}
/*********************************************************************************

PostRecordChanged TCS 12/14/98

a record has changed. Post it.
*********************************************************************************/
void CCategorySystem::PostRecordChanged(const CMoney &oldAmount, const Boolean accountChanged,
const Boolean jobChanged)
{
AdjustCategoryArrays();

THE_SUPERCLASS::PostRecordChanged(oldAmount, accountChanged, jobChanged);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

SetCatInfo

set information for the given category

*********************************************************************************/
void CCategorySystem::SetCatInfo(SInt32 catIndex, const SCatInfo &catInfo,
Boolean ignoreSubs)
{
if (ignoreSubs)
{
SCatInfo newCatInfo = catInfo;
newCatInfo.subcatArray = GetSubcatArray(catIndex);
TCS_FailNILMsg(newCatInfo.subcatArray, TCS_GetErrString(errID_BadArray));
mCategories.AssignItemAt(catIndex, newCatInfo);
}
else
mCategories.AssignItemAt(catIndex, catInfo);
}
/*********************************************************************************

SetSubcatInfo

set information for the given subcategory

*********************************************************************************/
void CCategorySystem::SetSubcatInfo(SInt32 catIndex, SInt32 subcatIndex,
const SSubcatInfo &subcatInfo)
{
SCatInfo catInfo;
GetCatInfo(catIndex, &catInfo);
SSubcatInfo newSubcatInfo = subcatInfo;

TSubCatArray *newSubcatArray = GetSubcatArray(catIndex);
TCS_FailNILMsg(newSubcatArray, TCS_GetErrString(errID_BadArray));
newSubcatArray->AssignItemAt(subcatIndex, newSubcatInfo);

catInfo.subcatArray = newSubcatArray;
mCategories.AssignItemAt(catIndex, catInfo);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

GetCurrentCatSystem (static)

fetch the stored value for the current category system
*********************************************************************************/
DBid CCategorySystem::GetCurrentCatSystem()
{
if (sCurrentCatSystem)
return sCurrentCatSystem;
else
return GetDefaultCatSystem();
}
/*********************************************************************************

SetCurrentCatSystem (static)

set the stored value for the current category system
*********************************************************************************/
void CCategorySystem::SetCurrentCatSystem(const DBid inSystem)
{
sCurrentCatSystem = inSystem;
}
/*********************************************************************************

GetDefaultCatSystem rev & renamed TCS 7/15/00

return the db id of the default category system, which we store in prefs.
If there is no cat system there we grab the first one.
*********************************************************************************/
DBid CCategorySystem::GetDefaultCatSystem()
{
DBid defaultID = GetPrefsObjectID(id_ExpensePrefs, tag_catsystem);

if (defaultID)
return defaultID;
else
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
return gDBFile->GetFirstObjectID(id_CategorySystem);
}
}