Accounting Software
Small Business Software Estimating Software
Time Tracking SoftwareTime Management SoftwareTime Billing SoftwareContact Management SoftwareCustomer Management SoftwareProject Management SoftwareBusiness Management Software

Subassembly Tables (Source Code)

Link to: header | tables directory

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

Comments

CSubAssemblyTable

This class manages unit cost subassembly tables for the Goldenseal estimating software,
small business management software, construction project management software and
construction estimating software.

It's a table for displaying sub-assembly breakdowns. Each line is stored in a CSubAssembly.
Each line is a labor or material component of a larger assembly.
Subassemblies can also be tools, reminders, equipment and a variety of other items.

SUPERCLASS = CBreakdownTable

Related Classes-- See also CAssembly, CAssemblyViewer, CBreakdownArrayOwner and CBreakdownTable.

Constructor

/*********************************************************************************
constructor
*********************************************************************************/
CSubAssemblyTable::CSubAssemblyTable(const SPaneInfo &inPaneInfo,
const SViewInfo &inViewInfo,
DB_ClassDescriptor *desc,
CAssembly *assembly /*= nil*/)
: CBreakdownTable(inPaneInfo, inViewInfo, desc)
{
mAssembly = assembly;
mCatSystem = 0;
}

Source Code

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

ListenToMessage

listen to a message from one of this table's broadcasters. We need
to check for circular refs in the table. We do it here rather than in
HandleCellCVChanged, since we want to reset the cv value if it's circular.

*********************************************************************************/
void CSubAssemblyTable::ListenToMessage(MessageT inMessage, void *ioParam)
{
switch (inMessage)
{
case msg_ClairvoyantChanged:
{ // get the cv field which sent the message
CTCS_CVField *cv = (CTCS_CVField *)ioParam;
TCS_FailNILMsg(cv, TCS_GetErrString(errID_BadClairvoyant));

// let's see if it was the cost item cv
CTCS_CVField *costItemCV =
TCS_SAFE_CAST(FetchCellField(ROW(mSelectedCell),
GetMemberCol(tag_costitem)), CTCS_CVField);

if (cv == costItemCV)
{ // yep we're listening to the cost item cv, so we need to check the
// selected item and make sure it doesn't result in a circular ref
// we only need to worry if the subassembly is an assembly TCS 12/28/98
UInt8 calcType = 0;
SInt32 typeCol = GetMemberCol(tag_costarea);
if (typeCol)
calcType = GetCellValue(ROW(mSelectedCell), typeCol);

if (calcType != costtype_assembly && calcType != costtype_assmlabor &&
calcType != costtype_assmmaterial)
break;

// it's an assembly so we need to check for circularity
DBid objectID = cv->GetValue();
CAssembly *item =
TCS_SAFE_CAST(gDBFile->GetOneObject(id_Assembly, objectID),
CAssembly);
if (item)
{ // it's an assembly
DB_ObjectWatcher watcher(item);
TCS_FailNILMsg(mAssembly, TCS_GetErrString(errID_BadAssembly));

if (item->DependsOnItem(mAssembly->GetDBID()))
{
// there's a circular conflict. We should never get
// here, so we'll just beep and reset the value. Note that
// giving an error alert will cause big problems, since it
// returns to CleanUpClairvoyant reentrantly TCS rev 12/12/01
TCS_SysBeep();
costItemCV->SetValue(0);
}

// better free up memory TCS 11/25/03
gDBFile->ForcePurge();
}
}
}
break;

default:
break;
}
// the inherited method will take care of updating the row
THE_SUPERCLASS::ListenToMessage(inMessage, ioParam);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

GetColType

return the column type for the given column

*********************************************************************************/
SInt32 CSubAssemblyTable::GetColType(const TableIndexT row, const TableIndexT col) const
{
switch (GetColTag(col))
{
case tag_costarea:
return coltype_menucv;
break;

case tag_costitem: // TCS 12/12/01
if (RowUsesObjectID(row))
return coltype_mixcv;
else
return coltype_mixedit;
break;

case tag_amount: // TCS 6/4/01
return coltype_caption;
break;

case tag_materialmodifier: // TCS 12/11/01
case tag_labormodifier:
case tag_fixedquantity: // TCS 12/23/01
return coltype_checkmark;
break;
case tag_unitsize: // TCS 12/13/01
if (RowUsesUnitCost(row))
return coltype_lookup;
else
return coltype_edit;
break;
case tag_unitcost: // TCS 12/12/01
if (RowUsesUnitCost(row))
return coltype_caption;
else
return coltype_edit;
break;

default:
return THE_SUPERCLASS::GetColType(row, col);
break;
}
}
/*********************************************************************************

GetRowCostArea TCS 12/12/01

return the cost area for the given row

*********************************************************************************/
UInt8 CSubAssemblyTable::GetRowCostArea(const TableIndexT row) const
{
TableIndexT costTypeCol = GetMemberCol(tag_costarea);

if (costTypeCol)
{
UInt8 costArea = GetCellValue(row, costTypeCol);
return costArea;
}
else
return 0;
}
/*********************************************************************************

RowUsesUnitCost TCS 12/12/01

return whether the given row displays a cost item or assembly.

*********************************************************************************/
Boolean CSubAssemblyTable::RowUsesUnitCost(const TableIndexT row) const
{
UInt8 costArea = GetRowCostArea(row);

switch (costArea)
{
case costtype_labor:
case costtype_equipment:
case costtype_material:
case costtype_subcontractor:
case costtype_other:
case costtype_assembly:
case costtype_assmlabor:
case costtype_assmmaterial:
return true;

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

RowUsesObjectID TCS 12/12/01

return whether the given row displays an object ID and clairvoyant field

*********************************************************************************/
Boolean CSubAssemblyTable::RowUsesObjectID(const TableIndexT row) const
{
UInt8 costArea = GetRowCostArea(row);

switch (costArea)
{
case costtype_unlistedlabor:
case costtype_unlistedequip:
case costtype_unlistedmaterial:
case costtype_unlistedsub:
case costtype_unlistedother:
return false;

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

ResetCostItem TCS 12/12/01

erase the cost item. We override since the cell may be cv or text

*********************************************************************************/
void CSubAssemblyTable::ResetCostItem(TableIndexT row, const SInt32 /*oldValue*/,
const SInt32 /*newValue*/)
{
// we only change if there's a cv field
if (!RowUsesObjectID(row))
return;

TableIndexT col = GetMemberCol(tag_costitem);
if (col)
{
if (IsMixedCV(row, col))
ClearCVCell(row, col);
else
SetCellText(row, col, cEmptyString);
}
}
/*********************************************************************************

GetDetailTransactionClass TCS 11/18/99

get the transaction object class id for a row

*********************************************************************************/
UInt8 CSubAssemblyTable::GetDetailTransactionClass(const TableIndexT row) const
{
UInt8 costArea = GetRowCostArea(row);

UInt8 costClassID = DB_ClassDescriptor::GetCostAreaClass(costArea);
return costClassID; // TCS 12/12/01
}
/*********************************************************************************

CreateNewCellCVField

create a new cv field for the given cell. We override to create a
special field for the cost item column
*********************************************************************************/
CTCS_CVField *CSubAssemblyTable::CreateNewCellCVField(const TableCellT &inCell,
const SPaneInfo &inPaneInfo)
{
// get the member info from the column
SMemberInfo memberInfo;
TCS_ASSERTMsg(GetColMemberInfo(COL(inCell), &memberInfo), TCS_GetErrString(errID_BadColumn));

if (memberInfo.tag == tag_costitem)
{
CSubAssemblyItemCV *itemCV = NEW CSubAssemblyItemCV(inPaneInfo, mTextInfo, cHasPopup);
TCS_FailNILMsg(itemCV, TCS_GetErrString(errID_BadClairvoyant));

itemCV->SetOwnerID(GetOwnerID());

return itemCV;
}
else
return THE_SUPERCLASS::CreateNewCellCVField(inCell, inPaneInfo);
}
/*********************************************************************************

FillNewRowCells

fill in start values for a new row

*********************************************************************************/
void CSubAssemblyTable::FillNewRowCells(const TableIndexT row)
{
THE_SUPERCLASS::FillNewRowCells(row);

CMoney zeroValue(0,0);
CMoney oneValue(1,0);
CTextString blankString("");

// set default cost area
SetMemberCV(row, tag_costarea, costtype_material);

// set size, cat and subcat default to blank
SetMemberCV(row, tag_category, 0); // TCS rev 9/27/01
SetMemberCV(row, tag_subcategory, 0);
SetMemberCV(row, tag_unitsize, 0);

// set cost item default to blank
SetMemberCV(row, tag_costitem, 0);

// set quantity default to one
SetMemberColNumber(row, tag_quantity, oneValue);
// set unit cost default to zero
SetMemberColMoney(row, tag_unitcost, zeroValue);

// set total cost default to zero
SetMemberColMoney(row, tag_amount, zeroValue);

// set waste default to zero
SetMemberColPercent(row, tag_waste, zeroValue);

SetMemberColString(row, tag_materialmodifier, cCheckMarkString);
SetMemberColString(row, tag_labormodifier, cEmptyString);
}
/*********************************************************************************

RecalcRow

recalculate the given row

*********************************************************************************/
CMoney CSubAssemblyTable::RecalcBreakdownRow(const TableIndexT row, const TagType changedCol)
{
CMoney unitCost,
qty,
waste;
TableIndexT col,
amountCol = GetMemberCol(tag_amount),
typeCol = GetMemberCol(tag_costarea);
UInt8 costType = GetCellValue(row, typeCol);

// do we have an amount column?
if (!amountCol)
return 0;

// if we've changed the cost area, reset the
// modifier checkboxes TCS 12/11/01
if (changedCol == tag_costarea)
{
if (costType == costtype_labor || costType == costtype_unlistedlabor)
SetMemberColString(row, tag_labormodifier, cCheckMarkString);
else
SetMemberColString(row, tag_labormodifier, cEmptyString);

if (costType == costtype_material || costType == costtype_unlistedmaterial)
SetMemberColString(row, tag_materialmodifier, cCheckMarkString);
else
SetMemberColString(row, tag_materialmodifier, cEmptyString);
}

// look for the quantity
col = GetMemberCol(tag_quantity);
if (col)
qty = GetCellMoneyValue(row, col);
else
{ // no quantity column, so amount is zero
SetCellText(row, GetMemberCol(tag_amount), CMoney::GetZeroCurrencyString());
return 0;
}

// look for the unit cost col
col = GetMemberCol(tag_unitcost);
if (col) // there's a unit cost column
unitCost = GetCellMoneyValue(row, col);
else
{ // no unit cost col, so we need to fetch it from the cost item
col = GetMemberCol(tag_costitem);
if (!col)
{ // no cost item, so amount is zero
SetCellText(row, GetMemberCol(tag_amount), CMoney::GetZeroCurrencyString());
unitCost = 0;
}
else
{ // we must have a cost item, so let's fetch its price
CUnitCost *costItem = nil;
if (typeCol)
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
if (costType == costtype_assembly || costType == costtype_assmlabor ||
costType == costtype_assmmaterial)
{
costItem = TCS_SAFE_CAST(gDBFile->GetOneObject(id_Assembly,
GetCellValue(row, col)),CUnitCost);
}
else if (costType == costtype_labor || costType == costtype_equipment ||
costType == costtype_material || costType == costtype_other ||
costType == costtype_subcontractor)
{
costItem = TCS_SAFE_CAST(gDBFile->GetOneObject(id_CostItem,
GetCellValue(row, col)),CUnitCost);
}

}
if (costItem)
{
DB_ObjectWatcher watcher(costItem);
unitCost = costItem->GetComponentPrice();
}
else
unitCost = 0;
}
}
// look for the waste col
col = GetMemberCol(tag_waste);
if (col) // there's a waste column, so get its value
waste = GetCellMoneyValue(row, col);
else
waste = 0;

// now calculate the net cost
CMoney netCost = unitCost * qty;
TCS_Real wasteFactor = waste.GetPercentMultiplier();
netCost *= wasteFactor;
SetCellText(row, amountCol, netCost.GetExtendedCurrencyString());
return netCost;
}
/*********************************************************************************

UpdateItemDetails

a cost item has changed, so change data that comes from it

*********************************************************************************/
void CSubAssemblyTable::UpdateItemDetails(const TableIndexT row)
{
CTextString cstring;

// let's get cost type and cost item
SInt32 costType = GetMemberColValue(row, tag_costarea);
DBid costItemID = GetMemberColValue(row, tag_costitem);

// now fetch the cost item itself
CMoney zeroValue = 0;
CUnitCost *costItem = nil;

switch (costType)
{
case costtype_assembly:
case costtype_assmlabor:
case costtype_assmmaterial:
costItem = TCS_SAFE_CAST(gDBFile->GetOneObject(id_Assembly,
costItemID), CUnitCost);
break;

case costtype_labor:
case costtype_material:
case costtype_subcontractor:
case costtype_other:
case costtype_equipment:
costItem = TCS_SAFE_CAST(gDBFile->GetOneObject(id_CostItem,
costItemID), CUnitCost);
break;

case costtype_unlistedlabor: // no updating needed TCS 12/12/01
case costtype_unlistedequip:
case costtype_unlistedmaterial:
case costtype_unlistedsub:
case costtype_unlistedother:
default:
return;
break;
}

// the cost item could be nil, so we don't do a failnil here
if (!costItem)
{ // no cost item, just clear the fields
SetMemberCV(row, tag_unitsize, 0); // rev TCS 9/27/01
SetMemberColMoney(row, tag_unitcost, zeroValue);
}
else
{ // there is a cost item, let's fill in the fields
// with info from the cost item
DB_ObjectWatcher watcher(costItem);
// fill in unit size rev TCS 9/27/01
DBid sizeID = 0; // bugfix TCS 12/19/01
TCS_ASSERTMsg(costItem->GetMemberValue(tag_unitsize, type_objectid, &sizeID),
TCS_GetValueErrString(tag_unitsize));
SetMemberCV(row, tag_unitsize, sizeID);

// fill in unit cost
TCS_ASSERTMsg(costItem->GetMemberValue(tag_componentprice, type_cstring, &cstring),
TCS_GetValueErrString(tag_componentprice));
SetMemberColString(row, tag_unitcost, cstring);
}

}