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

Labor Hours (Source Code)

Link to: header | source 2 | transactions directory

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

Comments

CLaborLog

This class manages employee hours for the Goldenseal accounting software,
time tracking software, construction project management software and
payroll software.

It's a record of employee hours. This is the raw material for the Goldenseal
payroll software and time tracking-- it generates the wage or salary amount.

We also use labor hours records for job costing and for t&m billing.
They are are a general record of which employee did what where.

SUPERCLASS = CTimeLog

Constructor

/*********************************************************************************
constructor
*********************************************************************************/
CLaborLog::CLaborLog()
{
mWageSchedule = 0;
mTMBillingRate = mJobCostRate = 0;

mBillingAmount = mBurdenAmount = 0;
mWageRateAmount = 0;
mDaysWorked = 1; // rev TCS 9/26/00

mOvertimeType = condition_None;
mStatus = status_Entered; // bugfix TCS 2/23/00
mMainAccountClass = id_EmployeeAccount;
mConditions = condition_None;

mPayrollRecord = 0;
mWageBreakdownID = 0;

mStartDate.SetToToday();
mEndDate.SetToToday();

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

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

NeoVersion version = GetVersion();

if (version > 3) // TCS 4/20/04
TCS_BlockMove(&src->mWageSchedule, &mWageSchedule, cCopyFileLength4);
else
TCS_BlockMove(&src->mWageSchedule, &mWageSchedule, cCopyFileLength);

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

GetFileLength rev TCS 8/31/01

return the file length used by this object

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

if (version > 3) // TCS 4/20/04
return THE_SUPERCLASS::GetFileLength(aFormat) + cFileLength4;
else
return THE_SUPERCLASS::GetFileLength(aFormat) + cFileLength;
}/*********************************************************************************

GetMemberValue

return the value of the member with the given tag

*********************************************************************************/
Boolean CLaborLog::GetMemberValue(const TagType aTag, const TagType aType,
void *aValue) const
{
CMoney amount = 0;

switch (aTag)
{
case tag_wagerate:
return ConvertObjectIDMember(mWageSchedule, id_WageSchedule, aValue, aType);
break;

case tag_payrecord:
return ConvertObjectIDMember(mPayrollRecord, id_PayrollRecord, aValue, aType);
break;

case tag_jobcostrate:
return ConvertObjectIDMember(mJobCostRate, id_LaborBillingRate, aValue, aType);
break;

case tag_breakdownref:
return ConvertObjectIDMember(mWageBreakdownID, id_WagesBreakdownEntry, aValue, aType);
break;

case tag_billingrate:
return ConvertObjectIDMember(mTMBillingRate, id_LaborBillingRate, aValue, aType);
break;

case tag_timeunit:
return ConvertEnumMember(mTimeUnit, MENU_HourToYearTimeUnits, aValue, aType);
break;

case tag_overtimetype:
return ConvertEnumMember(mOvertimeType, MENU_LaborLogOvertime, aValue, aType);
break;

case tag_breakdown:
return ConvertEnumMember(mBreakdownType, MENU_TimeCatItemBreakdown, aValue, aType);
break;

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

case tag_wageamount: // we calculate wage amount from regular amount
return ConvertMember(&mAmount, type_money, aValue, aType);
break;

case tag_actuallabor: // for job cost item reports TCS 4/15/02
return ConvertMember(&mJobCostAmount, type_money, aValue, aType);
break;

case tag_billingamount:
return ConvertMember(&mBillingAmount, type_money, aValue, aType);
break;

case tag_burdenamount:
return ConvertMember(&mBurdenAmount, type_money, aValue, aType);
break;

case tag_daysworked:
return ConvertMember(&mDaysWorked, type_number, aValue, aType);
break;

case tag_startdate: // TCS 4/20/04
return ConvertMember(&mStartDate, type_date, aValue, aType);
break;

case tag_enddate: // TCS 4/20/04
return ConvertMember(&mEndDate, type_date, aValue, aType);
break;

case tag_starttime: // TCS 4/20/04
return ConvertMember(&mStartDate, type_time, aValue, aType);
break;

case tag_endtime: // TCS 4/20/04
return ConvertMember(&mEndDate, type_time, aValue, aType);
break;

case tag_jobname: // we fetch the job name from the job account
{
CTextString jobName;

if (mJob && mJobClass)
{
DB_PersistentObject *job = gDBFile->GetOneObject(mJobClass, mJob);
if (job)
{
DB_ObjectWatcher watcher(job);
job->GetMemberValue(tag_name, type_cstring, &jobName);
}
}
return ConvertMember(&jobName, type_cstring, aValue, aType);
}
break;

case tag_overtimeamount: // overtime amount is calculated from wage rate
// this is the amount ADDED to base wage
amount = GetOvertimeAmount();
return ConvertMember(&amount, type_money, aValue, aType);
break;

case tag_overtimerate: // overtime rate is calculated from wage rate
// this is the total hourly rate including overtime
amount = GetOvertimeRate(time_hour);
return ConvertMember(&amount, type_money, aValue, aType);
break;

case tag_wagerateamount: // the actual wage rate amount per unit
if (mWageRateAmount.IsPositive()) // rev TCS 8/31/01
amount = mWageRateAmount;
else
amount = CalcWageRateAmount(mWageSchedule, mTimeUnit, mMainAccount);
return ConvertMember(&amount, type_money, aValue, aType);
break;

case tag_costarea: // calculated-- for reports // TCS 7/10/02
return ConvertEnumMember(costtype_labor, MENU_EstimateItemCostTypes, aValue, aType);
break;

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

SetMemberValue

set the value of the member with the given tag

*********************************************************************************/
Boolean CLaborLog::SetMemberValue(const TagType aTag, const TagType aType,
const void *aValue)
{
CDate date;

switch (aTag)
{
case tag_wagerate:
return ConvertDataToObjectID(aValue, aType, &mWageSchedule, id_WageSchedule);
break;

case tag_billingrate:
return ConvertDataToObjectID(aValue, aType, &mTMBillingRate, id_LaborBillingRate);
break;

case tag_payrecord:
return ConvertDataToObjectID(aValue, aType, &mPayrollRecord, id_PayrollRecord);
break;

case tag_breakdownref:
return ConvertMember(aValue, aType, &mWageBreakdownID, type_objectid);
break;

case tag_jobcostrate:
return ConvertDataToObjectID(aValue, aType, &mJobCostRate, id_LaborBillingRate);
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_overtimetype: // TCS 1/12/00
return ConvertMember(aValue, aType, &mOvertimeType, type_enum);
break;

case tag_billingamount:
return ConvertMember(aValue, aType, &mBillingAmount, type_money);
break;

case tag_wagerateamount: // TCS 8/31/01
return ConvertMember(aValue, aType, &mWageRateAmount, type_money);
break;

case tag_burdenamount:
return ConvertMember(aValue, aType, &mBurdenAmount, type_money);
break;

case tag_daysworked: // TCS 3/31/00
return ConvertMember(aValue, aType, &mDaysWorked, type_number);
break;

case tag_startdate: // TCS 4/20/04
if (ConvertMember(aValue, aType, &date, type_date))
{
mStartDate.SetDate(date);
return true;
}
else
return false;
break;

case tag_enddate: // TCS 4/20/04
if (ConvertMember(aValue, aType, &date, type_date))
{
mEndDate.SetDate(date);
return true;
}
else
return false;
break;

case tag_starttime: // TCS 4/20/04
if (ConvertMember(aValue, aType, &date, type_time))
{
mStartDate.SetTime(date);
return true;
}
else
return false;
break;

case tag_endtime: // TCS 4/20/04
if (ConvertMember(aValue, aType, &date, type_time))
{
mEndDate.SetTime(date);
return true;
}
else
return false;
break;

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

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

ReadObject

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

mWageSchedule = aStream->ReadID(); // mfs_sa rev 20feb2k3
mTMBillingRate = aStream->ReadID();
mJobCostRate = aStream->ReadID();

mBillingAmount.ReadFromStream(aStream);
mDaysWorked.ReadFromStream(aStream);
mWageRateAmount.ReadFromStream(aStream);

mOvertimeType = aStream->ReadChar();
mStatus = aStream->ReadChar();

if (version > 3) // TCS 4/20/04
{
mStartDate.ReadFromStream(aStream);
mEndDate.ReadFromStream(aStream);
}

mBurdenAmount.ReadFromStream(aStream);

mPayrollRecord = aStream->ReadID();
mWageBreakdownID = 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 CLaborLog::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();

aStream->WriteID(mWageSchedule); // mfs_sa rev 20feb2k3
aStream->WriteID(mTMBillingRate);
aStream->WriteID(mJobCostRate);

mBillingAmount.WriteToStream(aStream);
mDaysWorked.WriteToStream(aStream);
mWageRateAmount.WriteToStream(aStream);

aStream->WriteChar(mOvertimeType);
aStream->WriteChar(mStatus);

if (version > 3) // TCS 4/20/04
{
mStartDate.WriteToStream(aStream);
mEndDate.WriteToStream(aStream);
}

mBurdenAmount.WriteToStream(aStream);

aStream->WriteID(mPayrollRecord);
aStream->WriteID(mWageBreakdownID);

aStream->WriteEndSafetyTag(mEndSafetyTag, this);

}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

FinishViewerCreate TCS 1/19/04

fill in values after creation
*********************************************************************************/
void CLaborLog::FinishViewerCreate()
{
// let the superclass do its stuff
THE_SUPERCLASS::FinishViewerCreate();

// for labor-only, fill in the employee ID and other info.
if (gDBFile->LaborHoursOnly())
{
FinishNonViewerCreate();
}
}
/*********************************************************************************

FinishTemplateCreate TCS 1/19/04

fill in values after creation from a template or recurring transaction.
*********************************************************************************/
void CLaborLog::FinishTemplateCreate()
{
if (gDBFile->LaborHoursOnly())
{
// for labor-only, fill in the employee ID and related info.
// we can do that via our existing method for non viewers
FinishNonViewerCreate();
}
else
THE_SUPERCLASS::FinishTemplateCreate();
}
/*********************************************************************************

FinishNonViewerCreate

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

// for labor-only, fill in the employee ID TCS 1/19/04
if (gDBFile->LaborHoursOnly())
{
mMainAccount = gDBFile->GetEmployeeID();
}

// 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);

// update the wage schedule field
if (!mWageSchedule)
account->GetMemberValue(tag_wagerate, type_objectid, &mWageSchedule);

// update the billing rate field moved TCS 9/29/02
if (!mTMBillingRate)
account->GetMemberValue(tag_billingrate, type_objectid, &mTMBillingRate);

// update the job cost rate field
if (!mJobCostRate)
account->GetMemberValue(tag_jobcostrate, type_objectid, &mJobCostRate);
// no need to set billing amount or t&m amount, since both start at zero
}

// calculate the wage amount rev TCS 4/26/00
mAmount = CalculateWageAmount(mTimeUsed, mMainAccount,
mTimeUnit, mWageSchedule, mOvertimeType, mDaysWorked);

// calculate the t&m billing amount
mBillingAmount = CalculateTMBillingAmount(id_LaborHours, mTimeUsed, mMainAccount,
mTimeUnit, mTMBillingRate, mAmount, 0);

// calculate the job cost amount TCS 6/12/02
mJobCostAmount = CalculateJobCostAmount(id_LaborHours, mTimeUsed, mMainAccount,
mTimeUnit, mJobCostRate, mAmount, 0);
}
/*********************************************************************************

FinishImportCreate rev TCS 8/11/99

fill in values after creation from an import
*********************************************************************************/
void CLaborLog::FinishImportCreate()
{
// let the superclass do its stuff
THE_SUPERCLASS::FinishImportCreate();

// we used to recalc the wage amount and billing amount, but that causes
// problems if wage rate has changed. TCS removed 5/9/02
}
/*********************************************************************************

FinishBreakdownUpdate TCS 4/17/01 rev 2/22/02 rev 1/25/03 removed 6/10/03 rev 2/18/04

If there is no cost area column, we fill in the cost type
*********************************************************************************/
void CLaborLog::FinishBreakdownUpdate(CBreakdownEntry *breakdown, CBreakdownTable *table)
{
TCS_FailNILMsg(breakdown, TCS_GetErrString(errID_BadBreakdown));
TCS_FailNILMsg(table, TCS_GetErrString(errID_BadTable));

if (!table->HasColumn(tag_costarea))
{
UInt8 costArea = costtype_labor;
breakdown->SetMemberValue(tag_costarea, type_enum, &costArea);
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

PostNewRecord TCS 11/21/03

post info for a new record
*********************************************************************************/
void CLaborLog::PostNewRecord(const UInt8 creationType)
{
PostUseCount(id_WageSchedule, mWageSchedule);
PostUseCount(id_LaborBillingRate, mTMBillingRate);
PostUseCount(id_LaborBillingRate, mJobCostRate);

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

PostDeletion TCS 11/21/03

post info from a deleted record
*********************************************************************************/
void CLaborLog::PostDeletion(const Boolean postAudit)
{
PostUseCount(id_WageSchedule, mWageSchedule, cRemoveItem);
PostUseCount(id_LaborBillingRate, mTMBillingRate, cRemoveItem);
PostUseCount(id_LaborBillingRate, mJobCostRate, cRemoveItem);

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

PostRecordChanging TCS 11/21/03

a record will be changing. Post the change.
*********************************************************************************/
void CLaborLog::PostRecordChanging(const Boolean accountChanging, const Boolean jobChanging)
{
PostUseCount(id_WageSchedule, mWageSchedule, cRemoveItem);
PostUseCount(id_LaborBillingRate, mTMBillingRate, cRemoveItem);
PostUseCount(id_LaborBillingRate, mJobCostRate, cRemoveItem);

// let the superclass do any posting
THE_SUPERCLASS::PostRecordChanging(accountChanging, jobChanging);
}
/*********************************************************************************

PostRecordChanged TCS 11/21/03

a record has changed. Post it.
*********************************************************************************/
void CLaborLog::PostRecordChanged(const CMoney &oldAmount, const Boolean accountChanged,
const Boolean jobChanged)
{
PostUseCount(id_WageSchedule, mWageSchedule);
PostUseCount(id_LaborBillingRate, mTMBillingRate);
PostUseCount(id_LaborBillingRate, mJobCostRate);

// let the superclass do any posting
THE_SUPERCLASS::PostRecordChanged(oldAmount, accountChanged, jobChanged);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

PostExpenseAccount TCS 12/5/00

post this transaction to a general ledger expense account. We override
since we need to reset the account if the wage rate has changed.
*********************************************************************************/
void CLaborLog::PostExpenseAccount(const Boolean removeItem)
{
// if this goes to a stock account, reset the account, just in
// case the wage type has changed
if (mExpenseAccount == account_LaborExpenses || mExpenseAccount == account_OwnerHours ||
mExpenseAccount == account_SweatEquity)
{
mExpenseAccount = GetDefaultExpenseAccount();
MakeDirty();
}

// pass it along
THE_SUPERCLASS::PostExpenseAccount(removeItem);
}
/*********************************************************************************

PostPayablesAccount TCS moved 4/25/01

post this transaction to a payables utility account. We override, since
we always post
*********************************************************************************/
void CLaborLog::PostPayablesAccount(const Boolean removeItem)
{
CUtilityAccount::AddToActiveArray(account_UnpaidLaborHrs, this, removeItem);
}