Link to: header | tables
directory
Copyright Turtle Creek Software 1996-2006. All Rights Reserved.
Comments
CItemBreakdownTable
This class manages item breakdown tables for the Goldenseal accounting software,
small business management software, construction
project management software and
construction
accounting software.
It's the parent of tables for displaying item breakdowns. We use these in estimates, sales,
material purchases and other transactions when the user is selecting cost items
or assemblies from a list. Item breakdowns provide automatic fill-in of price,
plus inventory updating, unit price updating, bills of materials etc.
SUPERCLASS = CCostBreakdownTable
Source Code
/*********************************************************************************
GetColType TCS 12/28/98
return the column type for the given cell. We override since many columns
use variable col types
*********************************************************************************/
SInt32 CItemBreakdownTable::GetColType(const TableIndexT row, const TableIndexT col) const
{
TagType tag = GetColTag(col);
switch (tag)
{
case tag_costitem:
if (RowUsesObjectID(row))
return coltype_mixcv;
else
return coltype_mixedit;
break;
case tag_unitcost: // TCS 6/22/99 rev 9/13/99 rev 11/15/99 rev 3/7/04
if (mOwnerClass == id_PurchaseWorkOrder || mOwnerClass == id_SubcontractorLog ||
mOwnerClass == id_MaterialPurchase || mOwnerClass == id_OtherCost ||
mOwnerClass == id_InventoryUsed || mOwnerClass == id_Allowance |
mOwnerClass == id_Bid)
return coltype_edit;
else if (mOwnerClass == id_LaborHours || mOwnerClass == id_EquipmentHours)
return coltype_caption;
else if (RowUsesObjectID(row))
{
if (RowUsesVariableCost(row)) // TCS 1/4/03
return coltype_edit;
else
return coltype_caption;
}
else if (RowUsesPercent(row)) // TCS 11/5/02
return coltype_caption;
else
return coltype_edit;
break;
case tag_category:
case tag_subcategory: // rev TCS 4/29/02
return coltype_cv;
break;
case tag_unitsize: // TCS 7/4/00, rev 11/8/01
if (CostItemIsUnitCost(row))
return coltype_lookup;
else if (GetCostArea(row) == costtype_delay) // TCS 4/29/02
return coltype_menucv;
else
return coltype_edit;
break;
case tag_amount: // TCS 11/15/99
if (mOwnerClass == id_PurchaseWorkOrder ||mOwnerClass == id_Allowance ||
mOwnerClass == id_MaterialPurchase || mOwnerClass == id_OtherCost ||
mOwnerClass == id_InventoryUsed)
return coltype_edit;
else
return coltype_caption;
break;
case tag_unithours:
case tag_laborhours:
return coltype_caption;
break;
default:
break;
}
// for other columns we use the usual tag method
return THE_SUPERCLASS::GetColType(row, col);
}
/*********************************************************************************
GetMenuCVClassID
return the class ID for cv field in the given column
*********************************************************************************/
DBid CItemBreakdownTable::GetMenuCVClassID(const TableCellT &inCell) const
{
TagType colTag = GetColTag(COL(inCell));
if (colTag == tag_costarea)
{
switch (GetOwnerClass())
{
case id_Estimate:
return MENU_EstimateItemCostTypes;
break;
case id_Allowance:
case id_ChangeOrder:
return MENU_EstimateItemCostTypes; // rev TCS 7/27/01
break;
case id_Sale:
case id_MaterialPurchase:
case id_Bid:
return MENU_ItemBreakdownCostTypes;
break;
case id_InventoryTransfer: // TCS 11/14/01
return MENU_InventoryCostTypes;
break;
default:
return MENU_ItemBreakdownCostTypes;
break;
}
}
else if (colTag == tag_unitsize)
{
return MENU_HourstoDaysTimeUnits;
}
else // pass along for other columns
return THE_SUPERCLASS::GetMenuCVClassID(inCell);
}
/*********************************************************************************
RowUsesObjectID TCS 3/15/99 rev 3/18/99 rev 4/29/02
return whether the given row displays an object ID and clairvoyant field
*********************************************************************************/
Boolean CItemBreakdownTable::RowUsesObjectID(const TableIndexT row) const
{
UInt8 costArea = GetCostArea(row);
if (costArea)
{
return CCostBreakdownEntry::RowUsesObjectID(costArea, false);
}
else
return true;
}
/*********************************************************************************
RowUsesVariableCost TCS 1/3/03
return whether the given row allows variable costs
*********************************************************************************/
Boolean CItemBreakdownTable::RowUsesVariableCost(const TableIndexT row) const
{
if (mOwnerClass == id_Sale || mOwnerClass == id_Estimate)
{
// we used to fetch from the object, but that causes
// huge numbers of object accesses since this is called by
// the cursor updating. So we now store an array and check that.
UInt8 arrayValue; // TCS rev 4/18/03
if (mVariableCostArray.FetchItemAt(row, arrayValue))
return arrayValue;
else
{
// we don't have a value yet, so fill it in
TableIndexT col = GetMemberCol(tag_costitem);
DBid transID = GetCellValue(row, col);
Boolean allowVariableCost = false;
DBClass transClass = GetDetailTransactionClass(row);
if ((transClass == id_CostItem || transClass == id_Assembly) && transID)
{
DB_PersistentObject *object = gDBFile->GetOneObject(transClass, transID);
if (object)
{
DB_ObjectWatcher watcher (object);
allowVariableCost = object->AllowVariablePrices();
}
}
return allowVariableCost;
}
}
// if we get this far, it's not a variable cost
return false;
}
/*********************************************************************************
CostItemIsUnitCost TCS 11/8/01 rev 4/29/02
return whether the given row uses a standard unit cost(assembly or cost item)
*********************************************************************************/
Boolean CItemBreakdownTable::CostItemIsUnitCost(const TableIndexT row) const
{
UInt8 costArea = GetCostArea(row);
if (costArea)
{
return CCostBreakdownEntry::CostItemIsUnitCost(costArea, false); // bugfix TCS 11/19/01
}
else
return true;
}
/*********************************************************************************
HandleCellTextChanged TCS 11/5/02
handle change of a text cell.
*********************************************************************************/
void CItemBreakdownTable::HandleCellTextChanged(const TableIndexT row,
const TableIndexT col,
const Boolean sendMessage)
{
// for some columns we may need to do a schedule update
TagType colTag = GetColTag(col);
switch (colTag)
{
case tag_costitem:
if (!InFindMode())
{
// we recalc the row in the superclass TCS rev 11/26/03
RecalcScheduleRow(row, colTag);
RefreshRow(row);
RecalcTotal();
}
break;
default:
THE_SUPERCLASS::HandleCellTextChanged(row, col, sendMessage);
break;
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************
FillNewRowCells
fill a row with starter values
*********************************************************************************/
void CItemBreakdownTable::FillNewRowCells(TableIndexT row)
{
// the superclass can fill in most columns
THE_SUPERCLASS::FillNewRowCells(row);
// starter cost type depends on the transaction TCS 3/20/99
switch (GetOwnerClass())
{
case id_EquipmentHours:
SetMemberCV(row, tag_costarea, costtype_equipment);
break;
case id_SubcontractorLog:
SetMemberCV(row, tag_costarea, costtype_subcontractor);
break;
case id_Estimate:
SetMemberCV(row, tag_costarea, costtype_assembly);
SetMemberColString(row, tag_crewsize, cOneString); // TCS 4/29/02
break;
case id_Allowance:
case id_Bid:
case id_ChangeOrder:
case id_LaborHours:
case id_PurchaseWorkOrder:
SetMemberCV(row, tag_costarea, costtype_assembly);
break;
case id_MaterialPurchase:
case id_Sale:
default:
SetMemberCV(row, tag_costarea, costtype_material);
break;
}
}
/*********************************************************************************
FinishRowFill TCS 4/18/03
finish up after filling in initial values. We now store an array of
variable cost values for each row, so we don't have to be fetching it from
the object (which happens frequently since it affects menu updating).
*********************************************************************************/
void CItemBreakdownTable::FinishRowFill(const TableIndexT row)
{
// store whether this row allows variable unit costs
TableIndexT col = GetMemberCol(tag_costitem);
DBid transID = GetCellValue(row, col);
Boolean allowVariableCost = false;
DBClass transClass = GetDetailTransactionClass(row);
CCursorSpinner spinner; // TCS 11/25/03
if ((transClass == id_CostItem || transClass == id_Assembly) && transID)
{
++spinner;
DB_PersistentObject *object = gDBFile->GetOneObject(transClass, transID);
if (object)
{
DB_ObjectWatcher watcher (object);
allowVariableCost = object->AllowVariablePrices();
}
}
if (row > mVariableCostArray.GetCount())
mVariableCostArray.Append(allowVariableCost);
else
mVariableCostArray.AssignItemAt(row, allowVariableCost);
// pass to the superclass TCS 11/25/03
// we do it after the above so it can use the array
THE_SUPERCLASS::FinishRowFill(row);
}
/*********************************************************************************
SetRowUsesVariableCost TCS 4/18/03
change variable cost details
*********************************************************************************/
void CItemBreakdownTable::SetRowUsesVariableCost(const TableIndexT row, const Boolean inValue)
{
if (row > mVariableCostArray.GetCount())
TCS_DebugAlert(TCS_GetErrString(errID_BadTable));
mVariableCostArray.AssignItemAt(row, inValue);
}
/*********************************************************************************
UpdateAllPrices TCS 9/23/99
update all unit prices in the table
*********************************************************************************/
void CItemBreakdownTable::UpdateAllPrices()
{
CCursorSpinner spinner;
CProgressBar *progressBar = nil;
if (GetNumRows() > 200 || (gIsClient && GetNumRows() > 80)) // TCS 11/25/03
progressBar = CProgressBar::CreateBar(TCS_GetStockString(stockID_UpdatingPrices));
if (progressBar)
{
progressBar->SetMaxValue(GetNumRows());
progressBar->SetActionType(TCS_GetStockString(stockID_Row));
}
CProgressBarWatcher watcher (progressBar);
// loop through each row and recalculate
for ( TableIndexT row = 1 ; row <= GetNumRows() ; row++ )
{
if (progressBar)
progressBar->Increment();
else
++spinner;
RecalcCostBreakdownRow(row, 0, true);
}
// make sure change messages get sent TCS 5/3/00
RecalcTotal();
// make sure we get redrawn
Refresh();
}
/*********************************************************************************
CheckInventoryQuantities TCS 1/11/02
check inventory quantities for line items in a sale item breakdown
*********************************************************************************/
Boolean CItemBreakdownTable::CheckInventoryQuantities(const DBid accountID) const
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
CInventoryAccount *account =
TCS_SAFE_CAST(gDBFile->GetOneObject(id_InventoryAccount, accountID),
CInventoryAccount);
DB_ObjectWatcher acctWatcher (account);
UInt8 costArea, costClass;
DBid costID;
CMoney saleQuantity, inventoryQuantity;
CUnitCost *unitCost = nil;
// loop through each row and check its inventory count
for ( TableIndexT row = 1 ; row <= GetNumRows() ; row++ )
{
costArea = GetMemberColValue(row, tag_costarea);
costClass = DB_ClassDescriptor::GetCostAreaClass(costArea);
if (costClass == id_CostItem || costClass == id_Assembly)
{
costID = GetMemberColValue(row, tag_costitem);
saleQuantity = GetMemberColMoney(row, tag_quantity);
unitCost = TCS_SAFE_CAST(gDBFile->GetOneObject(costClass, costID),
CUnitCost);
if (unitCost)
{
DB_ObjectWatcher costWatcher (unitCost);
if (unitCost->HasInventory())
{
inventoryQuantity = unitCost->GetInventoryQuantity();
if (inventoryQuantity < saleQuantity)
{
CTextString errorString = TCS_GetMsgString(msgID_InsufficientInventory);
errorString.ReplaceStdTokens(unitCost->GetName(), inventoryQuantity.GetNumberString());
TCS_ErrorAlert(errorString);
return false;
}
}
}
// also check inventory in the given account
if (account)
{
inventoryQuantity = account->GetInventoryQuantity(costClass, costID);
if (inventoryQuantity < saleQuantity)
{
CTextString errorString = TCS_GetMsgString(msgID_InsufficientInventoryHere);
errorString.ReplaceStdTokens(unitCost->GetName(), inventoryQuantity.GetNumberString());
TCS_ErrorAlert(errorString);
return false;
}
}
}
}
// if we get this far, all stocks are OK
return true;
}
|