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

Supplier & Subcontractor Bids (Source Code)

Link to: header | transactions directory

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

Comments

CBid

This class manages bids for the Goldenseal bidding software,
small business management software, construction project management software and
construction estimating software.

Bids are used to keep track of price quotes from subcontractors
and suppliers. Estimates may include several bids. A bid can be used in
only one estimate.

Bids now handle competitive bidding-- several bids can be linked to the same
'master bid', and the lowest price will be used in the estimate.

For many users such as construction general contractors, bids are an important
part of the Goldenseal estimating software and bidding software.

Inheritance note- bids are job cost transactions, but the job class and job
fields are not used for data entry. Instead they are passive storage for the
project or other job that eventually uses the estimate containing this bid.

SUPERCLASS = CJobCostTransaction

Constructor

/*********************************************************************************
constructor
*********************************************************************************/
CBid::CBid()
{
mMainAccountClass = id_MaterialAccount;

mTaxRate = mCompetesWith = 0;

mGrossAmount = mTaxAmount = 0;
mLowBidAmount = 0;
mLaborHours = 0;
mCrewSize = 1;

mStatus = status_Entered;

mCostPerUnit = false;
mFixedAmount = true;
mRoughEstimate = false;
bidFiller = 0;

mCostsToDate = mSalesTaxToDate = 0;
mQuantity = 1; // TCS 9/6/02

mEstimate = mProject = 0;
mPictureID = 0;

mEndSafetyTag = tag_endsafetytag; // TCS 9/8/02
}

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

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

// we don't copy arrays

// copy string
mDetails = src->mDetails;
mContractText = src->mContractText; // TCS 10/23/03

// copy remaining members
TCS_BlockMove(&src->mTaxRate, &mTaxRate, cCopyFileLength);

mPictureID = src->mPictureID; // TCS 10/23/03

if (HasLockedStatus()) // TCS 2/2/99
mStatus = GetStarterStatus(); // rev TCS 3/8/00
}/*********************************************************************************

GetFileLength

return the file length to use for this object

*********************************************************************************/
NeoSize CBid::GetFileLength(const CNeoFormat *aFormat) const
{
NeoVersion version = GetVersion();

NeoSize baseLength = THE_SUPERCLASS::GetFileLength(aFormat) +
ARRAY_FILE_SIZE(mExpenseArray) +
ARRAY_FILE_SIZE(mCompetingBidArray) + // TCS 9/6/00
mDetails.FileLength(cStandardTextLen); // rev TCS 3/14/00

if (version == 1)
return baseLength + cFileLength;
else
return baseLength +
mContractText.LongFileLength(cMaximumTextLen) +
cFileLength2;
}/*********************************************************************************

GetMemberValue

return the value of the member with the given tag

*********************************************************************************/
Boolean CBid::GetMemberValue(const TagType aTag, const TagType aType,
void *aValue) const
{
switch (aTag)
{
case tag_taxrate:
return ConvertObjectIDMember(mTaxRate, id_VendorSalesTax, aValue, aType);
break;

case tag_estimate: // TCS 2/14/00
return ConvertObjectIDMember(mEstimate, id_Estimate, aValue, aType);
break;

case tag_job: // TCS 12/22/00
return ConvertObjectIDMember(mProject, id_ProjectAccount, aValue, aType);
break;

/*case tag_projectaccount: // TCS 2/14/00
return ConvertObjectIDMember(mProject, id_ProjectAccount, aValue, aType);
break;*/

case tag_competitor: // TCS 9/6/00
return ConvertObjectIDMember(mCompetesWith, id_Bid, aValue, aType);
break;

case tag_picture: // TCS 10/23/03
return ConvertObjectIDMember(mPictureID, id_Picture, aValue, aType);
break;

/*case tag_conditions:
return ConvertEnumMember(mConditions, MENU_BidConditions, aValue, aType);
break;*/

case tag_jobclass: // override
{
UInt8 jobClass = id_ProjectAccount;
return ConvertEnumMember(jobClass, MENU_BidJobTypes, aValue, aType);
}
break;

case tag_status:
return ConvertEnumMember(mStatus, MENU_BidStatus, aValue, aType);
break;

case tag_costarea: // we calculate this for item cv's TCS 3/20/99
{
UInt8 costArea = costtype_bid;
return ConvertMember(&costArea, type_enum, aValue, aType);
}
break;

case tag_details:
return ConvertMember(&mDetails, type_cstring, aValue, aType);
break;

case tag_contracttext: // TCS 10/23/03
return ConvertMember(&mContractText, type_longcstring, aValue, aType);
break;

// TCS removed tag_menuname 11/8/01. Now handled via GetAdjustedName

case tag_grossprice:
return ConvertMember(&mGrossAmount, type_money, aValue, aType);
break;

case tag_taxamount: // TCS 1/12/00
return ConvertMember(&mTaxAmount, type_money, aValue, aType);
break;

case tag_costtodate: // TCS 1/18/00
return ConvertMember(&mCostsToDate, type_money, aValue, aType);
break;

case tag_salestaxtodate: // TCS 10/31/00
return ConvertMember(&mSalesTaxToDate, type_money, aValue, aType);
break;

case tag_laborhours: // TCS 5/16/02
return ConvertMember(&mLaborHours, type_number, aValue, aType);
break;

case tag_crewsize: // TCS 5/16/02
return ConvertMember(&mCrewSize, type_number, aValue, aType);
break;

case tag_quantity: // TCS 9/23/02
return ConvertMember(&mQuantity, type_number, aValue, aType);
break;

case tag_unitcost: // the 'per unit' checkbox
return ConvertBitFieldMember(mCostPerUnit, aValue, aType);
break;

case tag_flatamount: // TCS 9/6/00
return ConvertBitFieldMember(mFixedAmount, aValue, aType);
break;

case tag_roughestimate: // TCS 11/14/03
return ConvertBitFieldMember(mRoughEstimate, aValue, aType);
break;

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

SetMemberValue

set the value of the member with the given tag

*********************************************************************************/
Boolean CBid::SetMemberValue(const TagType aTag, const TagType aType,
const void *aValue)
{
switch (aTag)
{
case tag_taxrate:
return ConvertDataToObjectID(aValue, aType, &mTaxRate, id_VendorSalesTax);
break;

case tag_estimate: // TCS 2/14/00
return ConvertDataToObjectID(aValue, aType, &mEstimate, id_Estimate);
break;

case tag_job:
return ConvertDataToObjectID(aValue, aType, &mProject, id_ProjectAccount);
break;

case tag_competitor: // TCS 9/6/00
return ConvertDataToObjectID(aValue, aType, &mCompetesWith, id_Bid);
break;

case tag_picture: // TCS 10/23/03
return ConvertDataToObjectID(aValue, aType, &mPictureID, id_Picture);
break;

case tag_details:
return SafeConvertString(aValue, aType, &mDetails);
break;

case tag_contracttext: // TCS 10/23/03
return SafeConvertString(aValue, aType, &mContractText, type_longcstring);
break;

/*case tag_conditions:
return ConvertMember(aValue, aType, &mConditions, type_enum);
break;*/

case tag_status:
return ConvertMember(aValue, aType, &mStatus, type_enum);
break;

case tag_taxamount: // rev TCS 1/12/00
return ConvertMember(aValue, aType, &mTaxAmount, type_money);
break;

case tag_grossprice:
return ConvertMember(aValue, aType, &mGrossAmount, type_money);
break;

case tag_costtodate: // TCS 1/18/00
return ConvertMember(aValue, aType, &mCostsToDate, type_money);
break;

case tag_salestaxtodate: // TCS 10/31/00
return ConvertMember(aValue, aType, &mSalesTaxToDate, type_money);
break;

case tag_laborhours: // TCS 5/16/02
return ConvertMember(aValue, aType, &mLaborHours, type_number);
break;

case tag_crewsize: // TCS 5/16/02
return ConvertMember(aValue, aType, &mCrewSize, type_number);
break;

case tag_unitcost:
mCostPerUnit = ConvertDataToBitField(aValue, aType);
return true;
break;

case tag_flatamount: // TCS 9/6/00
mFixedAmount = ConvertDataToBitField(aValue, aType);
return true;
break;

case tag_roughestimate: // TCS 11/14/03
mRoughEstimate = ConvertDataToBitField(aValue, aType);
return true;
break;

case tag_quantity: // calculated, no need to set
return true;
break;

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

ReadObject

read the persistent object's data in from a stream
*********************************************************************************/
void CBid::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;

NeoVersion version = GetVersion();

ReadInfoArrayFromStream(aStream, mExpenseArray, cHasSafetyTag);
ReadMoneyIDArrayFromStream(aStream, mCompetingBidArray, cHasSafetyTag);

ReadTextFromStream(aStream, &mDetails);

if (version > 1)
ReadLongTextFromStream(aStream, &mContractText);

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

mTaxRate = aStream->ReadID(); // mfs_sa rev 20feb2k3
mCompetesWith = aStream->ReadID();

mGrossAmount.ReadFromStream(aStream);
mTaxAmount.ReadFromStream(aStream);
mLowBidAmount.ReadFromStream(aStream);
mLaborHours.ReadFromStream(aStream);
mCrewSize.ReadFromStream(aStream);

mStatus = aStream->ReadChar();
*((UInt8*)&mStatus + sizeof(mStatus)) = aStream->ReadBits(3); // --Bitfield

mCostsToDate.ReadFromStream(aStream);
mSalesTaxToDate.ReadFromStream(aStream);
mQuantity.ReadFromStream(aStream);

mEstimate = aStream->ReadID();
mProject = aStream->ReadID();

if (version > 1)
mPictureID = aStream->ReadID();

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 CBid::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
}

CNeoDebugExport checker(aStream, this, cCheckTooSmall);
THE_SUPERCLASS::WriteObject(aStream, aTag);

NeoVersion version = GetVersion();

WriteInfoArrayToStream(aStream, mExpenseArray, cHasSafetyTag);
WriteMoneyIDArrayToStream(aStream, mCompetingBidArray, cHasSafetyTag);

WriteTextToStream(aStream, mDetails, cStandardTextLen); // removed -1 TCS 2/28/00

if (version > 1)
WriteLongTextToStream(aStream, mContractText, cMaximumTextLen);

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

aStream->WriteID(mTaxRate); // mfs_sa rev 20feb2k3
aStream->WriteID(mCompetesWith);

mGrossAmount.WriteToStream(aStream);
mTaxAmount.WriteToStream(aStream);
mLowBidAmount.WriteToStream(aStream);
mLaborHours.WriteToStream(aStream);
mCrewSize.WriteToStream(aStream);

aStream->WriteChar(mStatus);

aStream->WriteChar(*((UInt8*)&mStatus + sizeof(mStatus))); // --Bitfield bugfix TCS 6/16/03

mCostsToDate.WriteToStream(aStream);
mSalesTaxToDate.WriteToStream(aStream);
mQuantity.WriteToStream(aStream);

aStream->WriteID(mEstimate);
aStream->WriteID(mProject);

if (version > 1)
aStream->WriteID(mPictureID); // TCS 10/23/03

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

FinishNonViewerCreate

fill in values after creation from an AFW drag or an action command
*********************************************************************************/
void CBid::FinishNonViewerCreate()
{
// let the superclass do its stuff
THE_SUPERCLASS::FinishNonViewerCreate();

// the reference number must always be equal to the object id
mReferenceNum = GetDBID();

DB_Account *account =
TCS_SAFE_CAST(gDBFile->GetOneObject(mMainAccountClass, mMainAccount),
DB_Account);
if (account)
{ // there is an account, so we can proceed
DB_ObjectWatcher watcher(account);

// fetch tax rate from the account
if (!mTaxRate)
account->GetMemberValue(tag_taxrate, type_objectid, &mTaxRate);
}
}
/*********************************************************************************

PostImportNew TCS 10/22/01

post a newly imported item
*********************************************************************************/
void CBid::PostImportNew(const Boolean fromPostAction)
{
// we don't try to post competitors during the first object import,
// since listed items may not exist yet. We do the posting during
// CDataTranslator::FinishClassImport instead. The superclass will
// get it back to us via PostNewRecord and PostRecordActivated.
if (fromPostAction)
{
THE_SUPERCLASS::PostImportNew(fromPostAction);
}

// we don't pass to the superclass during the basic each-object import posting,
// since posting will be done after all objects are in.
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

CanBeDeleted TCS 9/6/00

this bid can't be deleted if used in an estimate or project, or if competing
bids refer to us

*********************************************************************************/
Boolean CBid::CanBeDeleted(const Boolean giveMessage) const
{
if (mCompetingBidArray.GetCount() > 0 || mEstimate || mJob)
{
if (giveMessage)
TCS_ErrorAlert(TCS_GetMsgString(msgID_CantDeleteItem));
return false;
}

// if we got this far, pass it along for judgement
return THE_SUPERCLASS::CanBeDeleted(giveMessage);
}
/*********************************************************************************

HasRecordLock TCS 12/20/00 rev TCS 11/14/03

return whether this record should be locked. We overide since high and
low bid status has a locked status field, but is otherwise editable.

*********************************************************************************/
Boolean CBid::HasRecordLock() const
{
if (mStatus == status_HighBid || mStatus == status_LowBid ||
mStatus == status_Incomplete || mStatus == status_RoughEstimate)
return false;
else
return THE_SUPERCLASS::HasRecordLock();
}
/*********************************************************************************

HasLockedStatus TCS 5/9/01

certain status types are 'locked', meaning they cause the status menu and
most other fields to be non-user-accessible

*********************************************************************************/
Boolean CBid::HasLockedStatus() const
{
if (mStatus == status_Incomplete || mStatus == status_RoughEstimate)
return true;
else
return THE_SUPERCLASS::HasLockedStatus();
}
/*********************************************************************************

ExpenseIsAcceptable TCS 7/14/00 rev 10/31/00

return whether an expense of the given amount is OK. We check to see if it
has exceeded our total payments to date. Note that we use the GROSS PRICE
to compare- that way there won't be a hassle if the sales tax amount has changed.
*********************************************************************************/
UInt8 CBid::ExpenseIsAcceptable(CMoney &inAmount, const DBClass inClass,
const DBid inID)
{
if (mFixedAmount)
{
CMoney totalCosts = inAmount + mCostsToDate;

// have we already included this expense? TCS 10/31/00
SObjectInfo info;
info.classID = inClass;
info.itemID = inID;
info.transactionType = 0;

if (mExpenseArray.ContainsItem(info))
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
CTransaction *transaction =
TCS_SAFE_CAST(gDBFile->GetOneObject(inClass, inID), CTransaction);

if (transaction)
{
DB_ObjectWatcher watcher(transaction);
CMoney grossAmount = transaction->GetGrossAmount();
totalCosts -= grossAmount;
}
}

if (totalCosts <= GetGrossAmount())
return save_success;
else
{
UInt8 warnMethod = CExpensePreferences::GetPOWarning(mMainAccountClass);

if (warnMethod == time_never)
return save_success;
else if (warnMethod == time_sometimes)
{
if (TCS_OKCancelDialog(TCS_GetMsgString(msgID_AskBidLimit)))
return save_success;
else
{
inAmount = mGrossAmount - mCostsToDate; // TCS 10/31/00
return save_shouldrevert;
}
}
else
{
TCS_ErrorAlert(errID_BidOverLimit);
inAmount = mGrossAmount - mCostsToDate; // TCS 10/31/00
return save_shouldrevert;
}
}
}
else
return save_success;
}
/*********************************************************************************

TransactionMatches (static) TCS 11/8/01

should we include the given item in a transaction menu?

The method interprets transaction info data in two different formats:
VSN 1.07 & EARLIER VSN 1.08 & LATER
info.accountClass id_Estimate mMainAccountClass
info.accountID mEstimate mMainAccount
info.jobClass id_ProjectAccount id_ProjectAccount
info.jobID mProject mProject
info.spareBoolean variable mEstimate

Note that from 10/24/01 to 11/8/01 we used a different data format. No users have it,
so this method will act incorrectly only for our test files during that period.

source can be:
id_CostItem an estimate breakdown item, called from CCostItemCV::GetAllEntries
id_Bid the Competitor field of a bid, called via CCompetingBidCV::TransactionMatches

testing for the transaction ref field happens in CTransactionRefCV::TransactionMatches

*********************************************************************************/
Boolean CBid::TransactionMatches(const STransInfo &info, const UInt8 source)
{
switch (source)
{
case id_CostItem: // in a cost item cv, we show bids that are not already in an
// estimate, and that are either non-competing or the base competitor.
if (info.accountClass == id_Estimate)
return (!info.accountID && info.transDetails != status_HighBid); // old style data
else
return (!info.spareBoolean && info.transDetails != status_HighBid); // new style data
break;

case id_Bid: // in the competitor field of a bid, we show bids that are not already in a
// project, and that are either non-competing or a master competitor.
return (!info.jobID && info.transDetails != status_HighBid); // bugfix TCS 1/7/02
break;

default:
TCS_DebugAlert("Oops, bad case in CBid::TransactionMatches!");
return false;
break;
}

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

GetTransDetails TCS 12/21/00

we fill competing bid status into the trans. detail member in the menu array.

*********************************************************************************/
UInt8 CBid::GetTransDetails() const
{
if (mCompetesWith)
return status_HighBid;
else if (mCompetingBidArray.GetCount() > 0)
return status_Active;
else
return 0;
}/*********************************************************************************

GetAdjustedName TCS 11/8/01

get the adjusted name. We append either 'competing' or the vendor name

*********************************************************************************/
CTextString CBid::GetAdjustedName() const
{
CTextString adjustedName = mName,
supplierName;

if (mCompetingBidArray.GetCount() > 0)
supplierName = TCS_GetStockString(stockID_Competitive);
else
GetMemberValue(tag_mainaccount, type_cstring, &supplierName);
adjustedName.AppendBracketedText(supplierName);

return adjustedName;
}
/*********************************************************************************

GetProjectPrice TCS 12/13/00

get the project price. If there are competing bids, check them

*********************************************************************************/
CMoney CBid::GetProjectPrice() const
{
if (mCompetingBidArray.GetCount() > 0)
{
TMoneyIDInfoArrayIterator iterator(mCompetingBidArray);
SMoneyIDInfo info;
CMoney amount = GetAmount();

while (iterator.Next(info))
{
if (info.amount < amount)
amount = info.amount;
}

return amount;
}
else
return GetAmount();
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

PostNewRecord TCS 11/20/03

post info for a new record
*********************************************************************************/
void CBid::PostNewRecord(const UInt8 creationType)
{
PostUseCount(id_JobSalesTax, mTaxRate);
PostUseCount(id_ProjectAccount, mProject);

// let the superclass do any posting
THE_SUPERCLASS::PostNewRecord(creationType);
}
/*********************************************************************************

PostDeletion TCS 11/20/03

post info from a deleted record
*********************************************************************************/
void CBid::PostDeletion(const Boolean postAudit)
{
PostUseCount(id_JobSalesTax, mTaxRate, cRemoveItem);
PostUseCount(id_ProjectAccount, mProject, cRemoveItem);

// let the superclass do any posting
THE_SUPERCLASS::PostDeletion(postAudit);
}
/*********************************************************************************

PostRecordActivated

post a newly created or activated transaction

*********************************************************************************/
void CBid::PostRecordActivated(const UInt8 creationType)
{
if (UpdateCompetitors())
UpdateEstimate();

// let the superclass do any posting
THE_SUPERCLASS::PostRecordActivated(creationType);
}
/*********************************************************************************

PostRecordCancelled

post a deleted or voided transaction

*********************************************************************************/
void CBid::PostRecordCancelled(const UInt8 cancelType)
{
if (UpdateCompetitors(cRemoveItem))
UpdateEstimate(cRemoveItem);

// let the superclass do any posting
THE_SUPERCLASS::PostRecordCancelled(cancelType);
}
/*********************************************************************************

PostRecordChanging TCS 1/6/98

a record will be changing. Post the change.
*********************************************************************************/
void CBid::PostRecordChanging(const Boolean accountChanging, const Boolean jobChanging)
{
if (UpdateCompetitors(cRemoveItem))
UpdateEstimate(cRemoveItem);

PostUseCount(id_JobSalesTax, mTaxRate, cRemoveItem); // TCS 11/20/03
PostUseCount(id_ProjectAccount, mProject, cRemoveItem);
// let the superclass have a crack
THE_SUPERCLASS::PostRecordChanging(accountChanging, jobChanging);
}
/*********************************************************************************

PostRecordChanged TCS 3/22/99

a record has changed. Post it. If the amount has changed, we need to update any
estimates that use this bid.
*********************************************************************************/
void CBid::PostRecordChanged(const CMoney &oldAmount, const Boolean accountChanged,
const Boolean jobChanged)
{
if (UpdateCompetitors())
UpdateEstimate();

PostUseCount(id_JobSalesTax, mTaxRate); // TCS 11/20/03
PostUseCount(id_ProjectAccount, mProject);

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

UpdateCompetitors TCS 9/6/00 rev 12/20/00

update the status of any competing bids.
*********************************************************************************/
DBid CBid::UpdateCompetitors(const Boolean removeItem)
{
DBid lowBidID = GetDBID();

if (mCompetesWith)
{
// this is a subsidiary bid, so update the master competitor
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
CBid *bid = TCS_SAFE_CAST(gDBFile->GetOneObject(id_Bid, mCompetesWith), CBid);

if (bid)
{
DB_ObjectWatcher watcher(bid);

// change the master bid's array
bid->AddToCompetingBidArray(GetDBID(), GetAmount(), removeItem);

if (mEstimate && !bid->GetEstimateID())
bid->SetEstimateID(mEstimate);

// the master bid needs to update status in all its competitors
lowBidID = bid->UpdateCompetingBidStatus();
}
else
mCompetesWith = 0;
}
else if (mCompetingBidArray.GetCount() > 0)
{
// this is a master bid, so update all the subsidiary bids
lowBidID = UpdateCompetingBidStatus();
}
else // this might be a former competitor which no longer competes
{
if (mStatus == status_HighBid || mStatus == status_LowBid || mStatus == status_Incomplete)
SetToStarterStatus();
}

return lowBidID;
}
/*********************************************************************************

UpdateEstimate TCS 9/6/00 rev 12/20/00

update the estimate which includes this bid
*********************************************************************************/
void CBid::UpdateEstimate(const Boolean removeItem)
{
if (mEstimate)
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
CEstimate *estimate =
TCS_SAFE_CAST(gDBFile->GetOneObject(id_Estimate, mEstimate), CEstimate);

if (estimate)
{
DB_ObjectWatcher watcher(estimate);

if (mCompetesWith)
{ // update with the master competitor
estimate->UpdateLineItem(costtype_bid, mCompetesWith, mLowBidAmount,
mLaborHours, mCrewSize, mCostPerUnit);
}
else if (mCompetingBidArray.GetCount() > 0)
{ // this is a master competitor.
estimate->UpdateLineItem(costtype_bid, GetDBID(), mLowBidAmount,
mLaborHours, mCrewSize, mCostPerUnit);
}
else if (removeItem)
{
estimate->UpdateLineItem(costtype_bid, GetDBID(), 0, 0, 0, mCostPerUnit);
}
else
{ // just a simple update
estimate->UpdateLineItem(costtype_bid, GetDBID(), GetAmount(),
mLaborHours, mCrewSize, mCostPerUnit);
}
}
else
mEstimate = 0;
}
}
/*********************************************************************************

UpdateCompetingBidStatus TCS 12/20/00

update the status field in competing bids
*********************************************************************************/
DBid CBid::UpdateCompetingBidStatus()
{
DBid lowBidID = GetDBID();
CMoney roughEstimate = 0;

if (mCompetingBidArray.GetCount() > 0)
{
// this is a master competitor. Start with this amount
// as the low bid, and then scan competitors for lower.
if (mRoughEstimate) // TCS rev 11/14/03
{
roughEstimate = GetAmount();
mLowBidAmount = 0;
}
else
mLowBidAmount = GetAmount();

TMoneyIDInfoArrayIterator iterator(mCompetingBidArray);
SMoneyIDInfo info;
CBid *bid;

while (iterator.Next(info))
{
// we look for the lowest bid, but only if it's positive.
// TCS rev 11/10/03
if (info.amount.IsPositive())
{
if (!mLowBidAmount.IsPositive() || info.amount < mLowBidAmount)
{
mLowBidAmount = info.amount;
lowBidID = info.id;
}
}
}

// if there are no competing bids, we use the rough estimate
if (!mLowBidAmount.IsPositive()) // TCS 11/14/03
mLowBidAmount = roughEstimate;

// now iterate again and update the status
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));

Boolean hitLowest = false;

// first set status in this bid
CMoney amount = GetAmount();
if (mRoughEstimate)
SetStatus(status_RoughEstimate);
else if (!amount.IsPositive())
SetStatus(status_Incomplete);
else if (mLowBidAmount == amount)
{
SetStatus(status_LowBid);
hitLowest = true;
}
else
SetStatus(status_HighBid);

// now loop thru the competitors and set their status
iterator.ResetToStart();
while (iterator.Next(info))
{
bid = TCS_SAFE_CAST(gDBFile->GetOneObject(id_Bid, info.id), CBid);

if (bid)
{
DB_ObjectWatcher watcher(bid);

if (bid->GetStatus() == status_Awarded) // if one has been awarded, stop now
return 0;

bid->SetLowBidAmount(mLowBidAmount);

if (mEstimate && !bid->GetEstimateID())
bid->SetEstimateID(mEstimate);

if (info.id == lowBidID)
bid->SetStatus(status_LowBid);
else if (!info.amount.IsPositive())
bid->SetStatus(status_Incomplete); // TCS 11/10/03
else
bid->SetStatus(status_HighBid);
}
else
{ // we don't report a missing item, just eliminate ref to it
mCompetingBidArray.Remove(info);
}
}
}

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

HandleExpenseTrans TCS 1/18/00

add a cost item to our cost total and array
*********************************************************************************/
void CBid::HandleExpenseTrans(const CMoney &amount, const CMoney &taxAmount,
const UInt8 classID, const DBid costID,
const Boolean removeIt)
{
AddToExpenseArray(classID, costID, 0, removeIt);

if (!removeIt)
{
mCostsToDate += amount;
mSalesTaxToDate += taxAmount; // TCS 10/31/00
}
else
{
mCostsToDate -= amount;
mSalesTaxToDate -= taxAmount; // TCS 10/31/00
}

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

HandleEstimateUse TCS 9/7/00

this bid is now included in an estimate
*********************************************************************************/
void CBid::HandleEstimateUse(const DBid estimateID, const CMoney quantity, const Boolean removeIt)
{
UInt8 saveSuccess = PrepareViewerDisplay(); // TCS rev 12/13/00

if (removeIt)
{
mEstimate = 0;
mQuantity = 0; // TCS 8/9/02
}
else
{
mEstimate = estimateID;
mQuantity = quantity;
}

if (mCompetingBidArray.GetCount() > 0) // TCS rev 12/20/00 rev 1/3/03
{
TMoneyIDInfoArrayIterator iterator(mCompetingBidArray);
SMoneyIDInfo info;

while (iterator.Next(info))
{
CBid *bid = TCS_SAFE_CAST(gDBFile->GetOneObject(id_Bid, info.id), CBid);

if (bid)
{
DB_ObjectWatcher watcher(bid);

if (removeIt)
{
bid->SetEstimateID(0);
bid->SetQuantity(quantity);
}
else
{
bid->SetEstimateID(estimateID);
bid->SetQuantity(quantity);
}
}
}
}

MakeDirty();

// update menu arrays, since we ref the estimate there TCS 12/21/00
DB_ListManager::ChangeMenuStatus(this);

UpdateViewerDisplay(saveSuccess); // TCS rev 12/13/00

}
/*********************************************************************************

SetAwardedStatus TCS 6/23/00 rev 12/20/00

the estimate for this bid has been awarded. Mark our status. We also need
to fiddle with competing bids, and we return the id of the lowest bid so the
estimate can refer to it directly.
*********************************************************************************/
DBid CBid::SetAwardedStatus(const UInt8 jobClass, const DBid jobID,
const Boolean removeItem, const DBid estimateID)
{
DBid lowBidID = GetDBID();

// if previously awarded, no need to do anything
if (!removeItem && mStatus == status_Awarded)
return lowBidID;

// the bid display may be changing, so make sure we're ready for it
UInt8 saveSuccess = PrepareViewerDisplay(); // TCS 12/22/00
// this is a master bid, so loop thru the competitors
if (mCompetingBidArray.GetCount() > 0)
{
TMoneyIDInfoArrayIterator iterator(mCompetingBidArray);
SMoneyIDInfo info;
CMoney amount = GetAmount();

while (iterator.Next(info))
{
if (info.amount < amount)
lowBidID = info.id;
}

if (lowBidID == GetDBID())
{ // this is the low bid, so update it
if (removeItem)
{
SetJob(0); // we set the job before status, so it is updated
SetStatus(status_LowBid); // in the menu array rev TCS 12/23/00
}
else
{
SetJob(jobID);
SetStatus(status_Awarded);
}
}
else
{ // update status in the low bid rev TCS 12/21/00
CBid *lowBid = TCS_SAFE_CAST(gDBFile->GetOneObject(id_Bid, lowBidID), CBid);

if (lowBid)
{
DB_ObjectWatcher watcher(lowBid);

UInt8 lowBidSuccess = lowBid->PrepareViewerDisplay();

if (removeItem)
{
lowBid->SetJob(0);
lowBid->SetStatus(status_LowBid);
}
else
{
lowBid->SetJob(jobID);
lowBid->SetEstimateID(estimateID); // TCS 11/8/01
lowBid->SetStatus(status_Awarded);
}

lowBid->UpdateViewerDisplay(lowBidSuccess, cUpdateRecordCount);

return lowBidID;
}
// if low bid was eliminated, we just continue

}
// if we are un-awarding, better update status in all linked items,
// since amounts may have changed while out of the loop
if (removeItem)
UpdateCompetitors(removeItem);

// return the id of the awarded bid(or the master bid if un-awarding)
if (removeItem)
return GetDBID();
else
return lowBidID;
}
else if (mCompetesWith)
{ // this is a subsidiary bid. Pass it along to the master
CBid *masterBid = TCS_SAFE_CAST(gDBFile->GetOneObject(id_Bid, mCompetesWith), CBid);

if (masterBid)
{
DB_ObjectWatcher watcher(masterBid);
return masterBid->SetAwardedStatus(jobClass, jobID, removeItem, estimateID);
}
else
{ // the master competitor must have been deleted
mCompetesWith = 0;
MakeDirty(); // TCS 11/8/01
return GetDBID();
}
}
else
{ // just a simple bid bugfix TCS 12/28/00
if (removeItem)
{
SetJob(0);
SetToStarterStatus();
}
else
{
SetJob(jobID);
SetStatus(status_Awarded);
}
return GetDBID();
}

// our status may have changed // TCS 12/22/00
UpdateViewerDisplay(saveSuccess, cUpdateRecordCount);
}
/*********************************************************************************

SetCompletedStatus TCS 12/22/00

the project has been completed. Deal with the change.

*********************************************************************************/
void CBid::SetCompletedStatus(const Boolean removeItem)
{
// if previously completed, no need to do anything
if (!removeItem && GetStatus() == status_Completed)
return;

UInt8 saveType = PrepareViewerDisplay();

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

UpdateViewerDisplay(saveType);
}
/*********************************************************************************

AddToCompetingBidArray TCS 9/6/00

update any bids that this bid competes with
*********************************************************************************/
Boolean CBid::AddToCompetingBidArray(const DBid inID, const CMoney &inAmount,
const Boolean removeIt)
{
// adjust the array
Boolean changed = AddToMoneyIDArray(mCompetingBidArray, inID, inAmount, removeIt);

// if we've removed the last item, reset the status TCS 12/21/00
if (mCompetingBidArray.GetCount() == 0)
{
SetToStarterStatus(); // TCS rev 11/10/03
}

return changed;

// we used to update the estimate here, but that is now done explicitely in posting
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

FetchComponentCosts TCS 2/10/03

fill in a detailed breakdown of estimated costs for this bid
*********************************************************************************/
CMoney CBid::FetchComponentCosts(SAssemblyUpdateInfo &info, const CMoney &inQuantity)
{
if (mBreakdownArray.GetCount() > 0)
THE_SUPERCLASS::FetchComponentCosts(info, inQuantity);
else if (mMainAccountClass == id_SubcontractorAccount)
info.subcontractorCost += GetAmount() * inQuantity;
else if (mMainAccountClass == id_MaterialAccount)
info.materialCost += GetAmount() * inQuantity;
else if (mMainAccountClass == id_OtherCostAccount)
info.otherCost += GetAmount() * inQuantity;

return GetAmount();
}
/*********************************************************************************

WriteContractSpecs TCS 7/18/03

fill in specs for a bid. We use the details field.
*********************************************************************************/
void CBid::WriteContractSpecs(CTextOutputStream &stream, const DBid /*subcontractType*/,
const Boolean /*includeAllowances*/, const Boolean includeBids,
const Boolean /*includeCatBreakdowns*/, const Boolean /*includeUnlisted*/) const
{
if (includeBids)
{
stream.WriteString(mDetails);
stream.WriteEndOfLine();
}
}
/*********************************************************************************

FillDataReport TCS 9/6/02

fill in a diagnostic table that shows data field values.

*********************************************************************************/
void CBid::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, "mExpenseArray", mExpenseArray);
FillFieldArrayRow(table, stream, "mCompetingBidArray", mCompetingBidArray);

FillFieldStringRow(table, stream, tag_details, mDetails);

if (version > 1) // TCS 10/23/03
FillFieldStringRow(table, stream, tag_contracttext, mContractText, true);

FillFieldObjectIDRow(table, stream, tag_taxrate, mTaxRate, id_VendorSalesTax);
FillFieldObjectIDRow(table, stream, tag_competitor, mCompetesWith, id_Bid);

FillFieldTagRow(table, stream, tag_grossprice, cMoneySize, mGrossAmount.GetCurrencyString());
FillFieldTagRow(table, stream, tag_taxamount, cMoneySize, mTaxAmount.GetCurrencyString());
FillFieldTableRow(table, stream, "mLowBidAmount", cMoneySize, mLowBidAmount.GetCurrencyString());
FillFieldTagRow(table, stream, tag_laborhours, cMoneySize, mLaborHours.GetNumberString());
FillFieldTagRow(table, stream, tag_crewsize, cMoneySize, mCrewSize.GetNumberString());

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

FillFieldBitRow(table, stream, tag_unitcost, mCostPerUnit, true);
FillFieldBitRow(table, stream, tag_flatamount, mFixedAmount);
FillFieldStockRow(table, stream, stockID_Padding, -6, SInt32(bidFiller));

FillFieldTagRow(table, stream, tag_costtodate, cMoneySize, mCostsToDate.GetCurrencyString());
FillFieldTagRow(table, stream, tag_salestaxtodate, cMoneySize, mSalesTaxToDate.GetCurrencyString());
FillFieldTagRow(table, stream, tag_quantity, cMoneySize, mQuantity.GetNumberString());

FillFieldObjectIDRow(table, stream, tag_estimate, mEstimate, id_Estimate);
FillFieldObjectIDRow(table, stream, tag_job, mProject, id_ProjectAccount);

if (version > 1)
FillFieldObjectIDRow(table, stream, tag_picture, mPictureID, id_Picture);

FillEndSafetyTag(table, stream, mEndSafetyTag);
}