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

Payroll Records (Source Code)

Link to: header | source 1 | source 2 | source 3 | transactions directory

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

Comments

CPayrollRecord

This class manages payroll records for the Goldenseal accounting software,
payroll software and business management software.

It's a record of one employee's payroll info for one pay period. These transactions
are the heart of the Goldeneseal payroll software-- they store wages, commissions,
deductions, employer taxes, benefits and vacation info. Goldenseal generates
these via Labor Hours records, using the Write Payroll command.

Unlike other transactions, a payroll record includes multiple breakdowns which
show wages, deductions, payroll taxes etc.

This is probably the most complicated transaction class.

SUPERCLASS = CBreakdownTransaction

Constructor

/*********************************************************************************
constructor
*********************************************************************************/
CPayrollRecord::CPayrollRecord()
{
mMainAccountClass = id_EmployeeAccount;
mDueDate.SetToToday();
mStatus = status_Entered;
mConditions = condition_MiscWages;

mTransactionRef = 0;

mWagesTotal = mCommissionsTotal = mDeductionsTotal = 0;
mEmployeeBenefitsTotal = mEmployerBenefitsTotal = 0;

mCompTimeBalance = mCompTimeChange = 0;
mVacationBalance = mVacationChange = 0;
mSickTimeBalance = mSickTimeChange = 0;
mOtherVacationBalance = mOtherVacationChange = 0;

mBreakdownClassID = id_WagesBreakdownEntry;

mNextRecord = mPriorRecord = 0;

mEmployerTaxTotal = 0;
mEmployerCatTaxTotal = 0;
mEmployeeCatTaxTotal = 0;

mHoursTotal = 0;

mPeriodStartDate.SetToToday(); // TCS 9/14/01
mPeriodCloseDate.SetToToday();
mExpansionLong = 0;
mExpansionMoney = 0;

mWageSchedule = 0;

mTimeUnit = time_day;
mPayRecPadding = 0;

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

Source Code

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

GetFileLength

return the file length to reserve for this object

*********************************************************************************/
NeoSize CPayrollRecord::GetFileLength(const CNeoFormat *aFormat) const
{
long basicLength = THE_SUPERCLASS::GetFileLength(aFormat) +
ARRAY_FILE_SIZE(mCommissionArray) +
ARRAY_FILE_SIZE(mDeductionArray) +
ARRAY_FILE_SIZE(mEmployerTaxArray) +
ARRAY_FILE_SIZE(mCategoryItemArray) +
ARRAY_FILE_SIZE(mBenefitArray) +
ARRAY_FILE_SIZE(mVacationArray);

return basicLength + cFileLength;
}
/*********************************************************************************

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

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

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

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

if (mConditions == condition_Withholding || mConditions == condition_WithholdingCredit ||
mConditions == condition_EmployerTax || mConditions == condition_EmployerTaxCredit ||
mConditions == condition_Benefit || mConditions == condition_BenefitCredit)
{
mTransactionRef = src->mTransactionRef; // TCS 7/29/02
}
else
{
mTransactionRef = 0; // TCS 4/27/01
}
}/*********************************************************************************

GetMemberValue

return the value of the member with the given tag

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

switch (aTag)
{
case tag_wagerate: // TCS 9/24/02
return ConvertObjectIDMember(mWageSchedule, id_WageSchedule, aValue, aType);
break;

case tag_transactionref: // TCS 9/27/00 rev 11/21/03
if (GetTransactionRefClass())
return ConvertObjectIDMember(mTransactionRef, GetTransactionRefClass(), aValue, aType);
else
return ConvertMember(&mTransactionRef, type_objectid, aValue, aType);
break;

case tag_conditions:
return ConvertEnumMember(mConditions, MENU_PayrollRecordConditions, aValue, aType);
break;

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

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

case tag_timeunit: // TCS 6/13/02
return ConvertEnumMember(mTimeUnit, MENU_HourstoDaysTimeUnits, aValue, aType);
break;

case tag_duedate:
return ConvertMember(&mDueDate, type_date, aValue, aType);
break;

case tag_wagestotal:
return ConvertMember(&mWagesTotal, type_money, aValue, aType);
break;

case tag_hourstotal:
return ConvertMember(&mHoursTotal, type_money, aValue, aType);
break;

case tag_commissionstotal:
return ConvertMember(&mCommissionsTotal, type_money, aValue, aType);
break;

case tag_deductionstotal: // total of basic deductions
return ConvertMember(&mDeductionsTotal, type_money, aValue, aType);
break;

case tag_employeecattax:
return ConvertMember(&mEmployeeCatTaxTotal, type_money, aValue, aType);
break;

case tag_employercattax:
return ConvertMember(&mEmployerCatTaxTotal, type_money, aValue, aType);
break;

case tag_employertax:
return ConvertMember(&mEmployerTaxTotal, type_money, aValue, aType);
break;

case tag_employeebenefits:
return ConvertMember(&mEmployeeBenefitsTotal, type_money, aValue, aType);
break;

case tag_employerbenefits:
return ConvertMember(&mEmployerBenefitsTotal, type_money, aValue, aType);
break;

// for vacation balances, we store the previous balance, but show
// the balance after changes from the current record.
case tag_comptimebalance: // TCS 7/22/02
case tag_currbalance: // (layouts use the old tag- CBAL not CMBL)
amount = mCompTimeBalance + mCompTimeChange;
return ConvertMember(&amount, type_number, aValue, aType);
break;

case tag_vacationbalance: // TCS 7/22/02
amount = mVacationBalance + mVacationChange;
return ConvertMember(&amount, type_number, aValue, aType);
break;

case tag_sicktimebalance: // TCS 7/22/02
amount = mSickTimeBalance + mSickTimeChange;
return ConvertMember(&amount, type_number, aValue, aType);
break;

case tag_otherbalance: // TCS 7/22/02
amount = mOtherVacationBalance + mOtherVacationChange;
return ConvertMember(&amount, type_number, aValue, aType);
break;

case tag_comptimechange: // TCS 7/22/02
return ConvertMember(&mCompTimeChange, type_number, aValue, aType);
break;

case tag_vacationchange: // TCS 7/22/02
return ConvertMember(&mVacationChange, type_number, aValue, aType);
break;

case tag_sicktimechange: // TCS 7/22/02
return ConvertMember(&mSickTimeChange, type_number, aValue, aType);
break;

case tag_otherchange: // TCS 7/22/02
return ConvertMember(&mOtherVacationChange, type_number, aValue, aType);
break;

case tag_startdate:
case tag_periodstart: // TCS 9/14/01 bugfix TCS 2/1/02
return ConvertMember(&mPeriodStartDate, type_date, aValue, aType);
break;

case tag_enddate:
case tag_periodend: // TCS 9/14/01 bugfix TCS 2/1/02
return ConvertMember(&mPeriodCloseDate, type_date, aValue, aType);
break;

case tag_actiondate:
case tag_payday: // TCS 9/14/01 bugfix TCS 2/1/02
return ConvertMember(&mDate, type_date, aValue, aType);
break;

case tag_prior:
return ConvertMember(&mPriorRecord, type_long, aValue, aType);
break;

case tag_next:
return ConvertMember(&mNextRecord, type_long, aValue, aType);
break;

case tag_allemployertaxtotal:
{
CMoney amount = mEmployerTaxTotal + mEmployerCatTaxTotal + mEmployerBenefitsTotal;
return ConvertMember(&amount, type_money, aValue, aType);
}
break;

case tag_alldeductionstotal: // total of all deductions
{
CMoney amount = mDeductionsTotal + mEmployeeCatTaxTotal + mEmployeeBenefitsTotal;
return ConvertMember(&amount, type_money, aValue, aType);
}
break;

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

SetMemberValue

set the value of the member with the given tag

*********************************************************************************/
Boolean CPayrollRecord::SetMemberValue(const TagType aTag, const TagType aType,
const void *aValue)
{
switch (aTag)
{
case tag_wagerate: // TCS 9/24/02
return ConvertMember(aValue, aType, &mWageSchedule, type_objectid);
break;

case tag_transactionref:
return ConvertMember(aValue, aType, &mTransactionRef, type_objectid);
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_timeunit: // TCS 6/13/02
return ConvertMember(aValue, aType, &mTimeUnit, type_enum);
break;

case tag_duedate:
return ConvertMember(aValue, aType, &mDueDate, type_date);
break;

case tag_wagestotal:
return ConvertMember(aValue, aType, &mWagesTotal, type_money);
break;

case tag_hourstotal:
return ConvertMember(aValue, aType, &mHoursTotal, type_money);
break;

case tag_commissionstotal:
return ConvertMember(aValue, aType, &mCommissionsTotal, type_money);
break;

case tag_deductionstotal:
return ConvertMember(aValue, aType, &mDeductionsTotal, type_money);
break;

case tag_employeecattax:
return ConvertMember(aValue, aType, &mEmployeeCatTaxTotal, type_money);
break;

case tag_employercattax:
return ConvertMember(aValue, aType, &mEmployerCatTaxTotal, type_money);
break;

case tag_employertax:
return ConvertMember(aValue, aType, &mEmployerTaxTotal, type_money);
break;

case tag_employeebenefits:
return ConvertMember(aValue, aType, &mEmployeeBenefitsTotal, type_money);
break;

case tag_employerbenefits:
return ConvertMember(aValue, aType, &mEmployerBenefitsTotal, type_money);
break;

case tag_comptimechange: // TCS 7/22/02
return ConvertMember(aValue, aType, &mCompTimeChange, type_number);
break;

case tag_vacationchange: // TCS 7/22/02
return ConvertMember(aValue, aType, &mVacationChange, type_number);
break;

case tag_sicktimechange: // TCS 7/22/02
return ConvertMember(aValue, aType, &mSickTimeChange, type_number);
break;

case tag_otherchange: // TCS 7/22/02
return ConvertMember(aValue, aType, &mOtherVacationChange, type_number);
break;

case tag_periodstart: // TCS 9/14/01 bugfix TCS 2/1/02
return ConvertMember(aValue, aType, &mPeriodStartDate, type_date);
break;

case tag_periodend: // TCS 9/14/01 bugfix TCS 2/1/02
return ConvertMember(aValue, aType, &mPeriodCloseDate, type_date);
break;

case tag_prior:
return ConvertMember(aValue, aType, &mPriorRecord, type_long);
break;

case tag_next:
return ConvertMember(aValue, aType, &mNextRecord, type_long);
break;

case tag_comptimebalance: // set these members via the direct call,
case tag_vacationbalance: // since we store and display different values
case tag_sicktimebalance:
case tag_otherbalance:
case tag_currbalance: // TCS 9/9/02
return true;
break;

case tag_alldeductionstotal: // calculated, no need to set
case tag_allemployertaxtotal:
case tag_payday: // TCS 9/14/01 bugfix TCS 2/1/02
return true;
break;

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

ReadObject

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

ReadIDArrayFromStream(aStream, mCommissionArray, cHasSafetyTag);
ReadIDArrayFromStream(aStream, mDeductionArray, cHasSafetyTag);
ReadIDArrayFromStream(aStream, mEmployerTaxArray, cHasSafetyTag);
ReadIDArrayFromStream(aStream, mCategoryItemArray, cHasSafetyTag);
ReadIDArrayFromStream(aStream, mBenefitArray, cHasSafetyTag);
ReadIDArrayFromStream(aStream, mVacationArray, cHasSafetyTag);

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

mDueDate.ReadFromStream(aStream); // mfs_sa rev 20feb2k3

mStatus = aStream->ReadChar();
mConditions = aStream->ReadChar();
mTimeUnit = aStream->ReadChar();
mPayRecPadding = aStream->ReadChar();

mTransactionRef = aStream->ReadID();
mPriorRecord = aStream->ReadID();
mNextRecord = aStream->ReadID();

mWagesTotal.ReadFromStream(aStream);
mHoursTotal.ReadFromStream(aStream);
mCommissionsTotal.ReadFromStream(aStream);
mDeductionsTotal.ReadFromStream(aStream);
mEmployerTaxTotal.ReadFromStream(aStream);
mEmployerCatTaxTotal.ReadFromStream(aStream);
mEmployeeCatTaxTotal.ReadFromStream(aStream);
mEmployeeBenefitsTotal.ReadFromStream(aStream);
mEmployerBenefitsTotal.ReadFromStream(aStream);
mCompTimeBalance.ReadFromStream(aStream);
mVacationBalance.ReadFromStream(aStream);
mSickTimeBalance.ReadFromStream(aStream);
mOtherVacationBalance.ReadFromStream(aStream);
mCompTimeChange.ReadFromStream(aStream);
mVacationChange.ReadFromStream(aStream);
mSickTimeChange.ReadFromStream(aStream);
mOtherVacationChange.ReadFromStream(aStream);

mPeriodStartDate.ReadFromStream(aStream);
mPeriodCloseDate.ReadFromStream(aStream);

mWageSchedule = aStream->ReadID();

mExpansionLong = aStream->ReadID();

mExpansionMoney.ReadFromStream(aStream);

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 CPayrollRecord::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);

WriteIDArrayToStream(aStream, mCommissionArray, cHasSafetyTag);
WriteIDArrayToStream(aStream, mDeductionArray, cHasSafetyTag);
WriteIDArrayToStream(aStream, mEmployerTaxArray, cHasSafetyTag);
WriteIDArrayToStream(aStream, mCategoryItemArray, cHasSafetyTag);
WriteIDArrayToStream(aStream, mBenefitArray, cHasSafetyTag);
WriteIDArrayToStream(aStream, mVacationArray, cHasSafetyTag);

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

mDueDate.WriteToStream(aStream); // mfs_sa rev 20feb2k3

aStream->WriteChar(mStatus);
aStream->WriteChar(mConditions);
aStream->WriteChar(mTimeUnit);
aStream->WriteChar(mPayRecPadding);

aStream->WriteID(mTransactionRef);
aStream->WriteID(mPriorRecord);
aStream->WriteID(mNextRecord);

mWagesTotal.WriteToStream(aStream);
mHoursTotal.WriteToStream(aStream);
mCommissionsTotal.WriteToStream(aStream);
mDeductionsTotal.WriteToStream(aStream);
mEmployerTaxTotal.WriteToStream(aStream);
mEmployerCatTaxTotal.WriteToStream(aStream);
mEmployeeCatTaxTotal.WriteToStream(aStream);
mEmployeeBenefitsTotal.WriteToStream(aStream);
mEmployerBenefitsTotal.WriteToStream(aStream);
mCompTimeBalance.WriteToStream(aStream);
mVacationBalance.WriteToStream(aStream);
mSickTimeBalance.WriteToStream(aStream);
mOtherVacationBalance.WriteToStream(aStream);
mCompTimeChange.WriteToStream(aStream);
mVacationChange.WriteToStream(aStream);
mSickTimeChange.WriteToStream(aStream);
mOtherVacationChange.WriteToStream(aStream);

mPeriodStartDate.WriteToStream(aStream);
mPeriodCloseDate.WriteToStream(aStream);

aStream->WriteID(mWageSchedule);

aStream->WriteID(mExpansionLong);

mExpansionMoney.WriteToStream(aStream);

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

PostNewRecord TCS 11/21/03

post info for a new record
*********************************************************************************/
void CPayrollRecord::PostNewRecord(const UInt8 creationType)
{
PostUseCount(GetTransactionRefClass(), mTransactionRef);
PostUseCount(id_WageSchedule, mWageSchedule);

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

PostDeletion TCS 11/21/03

post info from a deleted record
*********************************************************************************/
void CPayrollRecord::PostDeletion(const Boolean postAudit)
{
PostUseCount(GetTransactionRefClass(), mTransactionRef, cRemoveItem);
PostUseCount(id_WageSchedule, mWageSchedule, cRemoveItem);

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

PostRecordActivated TCS 2/6/99 rev TCS 5/16/00

post info from a transaction that is new or activated
*********************************************************************************/
void CPayrollRecord::PostRecordActivated(const UInt8 creationType)
{
// let the superclass do any posting (this is where hours are updated)
THE_SUPERCLASS::PostRecordActivated(creationType);

// we have extra arrays that need to be told about the activation
PostBreakdownsActivated(mCommissionArray, id_CommishBreakdownEntry, creationType);
PostBreakdownsActivated(mDeductionArray, id_DeductBreakdownEntry, creationType);
PostBreakdownsActivated(mEmployerTaxArray, id_EmpTaxBreakdownEntry, creationType);
PostBreakdownsActivated(mCategoryItemArray, id_CatTaxBreakdownEntry, creationType);
PostBreakdownsActivated(mBenefitArray, id_BennyBreakdownEntry, creationType);
PostBreakdownsActivated(mVacationArray, id_VacBreakdownEntry, creationType);

AddToEmployeeArray();

// better update billing rates in listed labor logs, etc
PostPayrollSources();

// update payables TCS 4/25/01
PostPayablesAccount();

// update any special posting items TCS 7/29/02
PostVacationTime();
PostAdjustments();
}
/*********************************************************************************

PostRecordCancelled TCS 2/6/99 rev TCS 5/16/00

post info from a voided or deleted transaction
*********************************************************************************/
void CPayrollRecord::PostRecordCancelled(const UInt8 cancelType)
{
// let the superclass do any posting(this is where hours are updated)
THE_SUPERCLASS::PostRecordCancelled(cancelType);

// we have extra arrays that need to be told about the cancellation
PostBreakdownsCancelled(mCommissionArray, id_CommishBreakdownEntry, cancelType);
PostBreakdownsCancelled(mDeductionArray, id_DeductBreakdownEntry, cancelType);
PostBreakdownsCancelled(mEmployerTaxArray, id_EmpTaxBreakdownEntry, cancelType);
PostBreakdownsCancelled(mCategoryItemArray, id_CatTaxBreakdownEntry, cancelType);
PostBreakdownsCancelled(mBenefitArray, id_BennyBreakdownEntry, cancelType);
PostBreakdownsCancelled(mVacationArray, id_VacBreakdownEntry, cancelType);

// remove this item from the employee array
AddToEmployeeArray(cRemoveItem);
// if there was a prior record, we should restore its status
if (mPriorRecord)
{
DB_PersistentObject *prevRecord = gDBFile->GetOneObject(id_PayrollRecord, mPriorRecord);
if (prevRecord)
{
DB_ObjectWatcher watcher(prevRecord);

DBid noID = 0;
prevRecord->SetMemberValue(tag_next, type_objectid, &noID); // bugfix 3/15/00
prevRecord->MakeDirty();
}
}
// better update billing rates in listed labor logs, etc
PostPayrollSources(cRemoveItem);

// update payables TCS 4/25/01
PostPayablesAccount(cRemoveItem);

// update any special posting items TCS 7/29/02
PostVacationTime(cRemoveItem);
PostAdjustments(cRemoveItem);
}
/*********************************************************************************

PostRecordChanging TCS 2/22/99 rev TCS 5/16/00

a record will be changing. Post the change.
*********************************************************************************/
void CPayrollRecord::PostRecordChanging(const Boolean accountChanging, const Boolean jobChanging)
{
// the superclass updates hours breakdowns
THE_SUPERCLASS::PostRecordChanging(accountChanging, jobChanging);

// we have extra arrays that need to be told about the change TCS 12/18/99
PostBreakdownsChanging(mCommissionArray, id_CommishBreakdownEntry, accountChanging, jobChanging);
PostBreakdownsChanging(mDeductionArray, id_DeductBreakdownEntry, accountChanging, jobChanging);
PostBreakdownsChanging(mEmployerTaxArray, id_EmpTaxBreakdownEntry, accountChanging, jobChanging);
PostBreakdownsChanging(mCategoryItemArray, id_CatTaxBreakdownEntry, accountChanging, jobChanging);
PostBreakdownsChanging(mBenefitArray, id_BennyBreakdownEntry, accountChanging, jobChanging);
PostBreakdownsChanging(mVacationArray, id_VacBreakdownEntry, accountChanging, jobChanging);

// update the ref in the employee record
if (accountChanging)
AddToEmployeeArray(cRemoveItem);

// better update billing rates in listed labor logs, etc
PostPayrollSources(cRemoveItem);

// update payables TCS 4/25/01
PostPayablesAccount(cRemoveItem);

// update any special posting items TCS 7/29/02
PostVacationTime(cRemoveItem);
PostAdjustments(cRemoveItem);

PostUseCount(GetTransactionRefClass(), mTransactionRef, cRemoveItem); // TCS 11/21/03
PostUseCount(id_WageSchedule, mWageSchedule, cRemoveItem);
}
/*********************************************************************************

PostRecordChanged TCS 2/22/99 rev TCS 5/16/00

a record has changed. Post it.
*********************************************************************************/
void CPayrollRecord::PostRecordChanged(const CMoney &oldAmount, const Boolean accountChanged,
const Boolean jobChanged)
{
// the superclass handles hours updating
THE_SUPERCLASS::PostRecordChanged(oldAmount, accountChanged, jobChanged);

// we have extra arrays that need to be told about the change TCS 12/18/99
PostBreakdownsChanged(mCommissionArray, id_CommishBreakdownEntry, oldAmount, accountChanged, jobChanged);
PostBreakdownsChanged(mDeductionArray, id_DeductBreakdownEntry, oldAmount, accountChanged, jobChanged);
PostBreakdownsChanged(mEmployerTaxArray, id_EmpTaxBreakdownEntry, oldAmount, accountChanged, jobChanged);
PostBreakdownsChanged(mCategoryItemArray, id_CatTaxBreakdownEntry, oldAmount, accountChanged, jobChanged);
PostBreakdownsChanged(mBenefitArray, id_BennyBreakdownEntry, oldAmount, accountChanged, jobChanged);
PostBreakdownsChanged(mVacationArray, id_VacBreakdownEntry, oldAmount, accountChanged, jobChanged);

// update the ref in the employee record
if (accountChanged)
AddToEmployeeArray();

// better update billing rates in listed labor logs, etc
PostPayrollSources();

// update payables TCS 4/25/01
PostPayablesAccount();

// update any special posting items TCS 7/29/02
PostVacationTime();
PostAdjustments();

PostUseCount(GetTransactionRefClass(), mTransactionRef); // TCS 11/21/03
PostUseCount(id_WageSchedule, mWageSchedule);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

PostBreakdownChanging TCS 4/12/00

the breakdown type is changing. We override since nothing should be done
*********************************************************************************/
void CPayrollRecord::PostBreakdownChanging()
{
}
/*********************************************************************************

PostPayablesAccount TCS 4/25/01

post this transaction to a payables utility account.
*********************************************************************************/
void CPayrollRecord::PostPayablesAccount(const Boolean removeItem)
{
CUtilityAccount::AddToActiveArray(account_UnpaidPayroll, this, removeItem);
}
/*********************************************************************************

PostPayrollSources TCS rev 5/8/00 rev 3/21/02

update reimbursed expenses, and labor logs that use net payroll for billing rates, etc.
*********************************************************************************/
void CPayrollRecord::PostPayrollSources(const Boolean removeItem)
{
// sanity check
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));

if (mBreakdownType == breakdown_none)
{
switch (mConditions)
{
case condition_MaterialReimburse: // for an employee reimbursement, mark
case condition_OtherCostReimburse: // the referenced transaction as paid TCS 11/10/00
case condition_SubcontractReimburse:
{
DB_PersistentObject *source = gDBFile->GetOneObject(mConditions, mTransactionRef);

if (source)
{
DB_ObjectWatcher watcher(source);
if (removeItem)
{
source->HandlePaymentMade(-mAmount, id_PayrollRecord, GetDBID(), id_PayrollRecord, cRemoveItem);
}
else
{
source->HandlePaymentMade(mAmount, id_PayrollRecord, GetDBID(), id_PayrollRecord);
}
}
else
ReportMissingObject(mConditions, mTransactionRef);
}
break;

case condition_Withholding: // we need to post taxes to the transaction
case condition_WithholdingCredit: // arrays and util accounts TCS 3/21/02 rev TCS 7/29/02
case condition_EmployerTax:
case condition_EmployerTaxCredit:
PostTaxesDue(removeItem);
break;

case condition_Benefit: // TCS 7/29/02
case condition_BenefitCredit:
PostBenefitsDue(removeItem);
break;

case condition_Advance:
case condition_Repay:
{
// no need to post here-- it happens in HandlePaymentMade
}
break;

case condition_Bonus:
case condition_MiscWages:
case condition_Tips:
case condition_Commissions:

case condition_AddCompTime:
case condition_AddVacation:
case condition_AddSickTime:
case condition_AddOtherVacation:

case condition_UseCompTime:
case condition_UseVacation:
case condition_UseSickTime:
case condition_UseOtherVacation:
{
// update vacation balances and misc wages in the employee account
CEmployeeAccount *employee =
TCS_SAFE_CAST(gDBFile->GetOneObject(id_EmployeeAccount, mMainAccount),
CEmployeeAccount);
if (employee) // TCS 4/23/03
{
DB_ObjectWatcher empWatcher (employee);
employee->AdjustPayrollBalance(mConditions, mAmount, removeItem);
}
}
break;

default:
TCS_DebugAlert("Oops, bad case in CPayrollRecord::UpdatePayrollSources!");
break;
}
}
else // we have breakdowns.
{
// initialize
DBid breakdownID;
CLaborLog *laborLog;
DB_PersistentObject *breakdown;

// prepare to loop thru wage entries, so we can pass along net payroll info
// so labor logs can update job cost and billing amounts that are based on
// the net payroll cost (including employer tax burden). Note that we dive
// directly into the labor log here, rather than passing this method along
// to the wage breakdown.
TObjectIDArrayIterator iterator(mBreakdownArray);

while (iterator.Next(breakdownID))
{
breakdown = gDBFile->GetOneObject(id_WagesBreakdownEntry, breakdownID);

if (breakdown)
{
DB_ObjectWatcher watcher(breakdown);

if (!breakdown->IsMarked()) // TCS 8/27/01
continue;

DBid laborLogID = 0;
breakdown->GetMemberValue(tag_transactid, type_objectid, &laborLogID);

laborLog = TCS_SAFE_CAST(gDBFile->GetOneObject(id_LaborHours, laborLogID),
CLaborLog);
if (laborLog)
{
DB_ObjectWatcher logWatcher(laborLog);

laborLog->HandlePayrollRecordMade(removeItem, mWagesTotal, // rev TCS 4/25/01
mEmployerTaxTotal + mEmployerBenefitsTotal,
mHoursTotal, this, mPeriodStartDate); // rev TCS 9/14/01
}
}
}
}
}
/*********************************************************************************

PostVacationTime TCS 7/29/02

post adjustments to vacation and comp time. Note that right now this
handles only regular vacation time from normal payroll. Adjustments are
posted in PostPayrollSources instead.
*********************************************************************************/
void CPayrollRecord::PostVacationTime(const Boolean removeItem)
{
if (mBreakdownType == breakdown_none)
return;

CEmployeeAccount *employee =
TCS_SAFE_CAST(gDBFile->GetOneObject(id_EmployeeAccount, mMainAccount),
CEmployeeAccount);

if (employee)
{
DB_ObjectWatcher watcher (employee);

employee->AdjustVacationBalances(mCompTimeChange, mVacationChange,
mSickTimeChange, mOtherVacationChange, removeItem);
}
}
/*********************************************************************************

PostAdjustments TCS 7/29/02

post misc adjustments. This may not be needed-- there is already posting via
PostVacationTime and UpdatePayrollSources and that may be sufficient
*********************************************************************************/
void CPayrollRecord::PostAdjustments(const Boolean /*removeItem*/)
{

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

PostTaxesDue TCS 7/29/02

post a payroll tax deduction or credit
*********************************************************************************/
void CPayrollRecord::PostTaxesDue(const Boolean removeItem)
{
CMoney paymentAmount = GetTaxPaymentAmount(); // rev TCS 12/28/01

if (paymentAmount.IsZero())
return;

TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
DBid expenseAccountID = account_UnpaidPayrollTaxes;

// fetch the tax item so we can add to a tax agency
CTaxItem *taxItem = TCS_SAFE_CAST(gDBFile->GetOneObject(id_TaxItem, mTransactionRef),
CTaxItem);
if (taxItem)
{
DB_ObjectWatcher watcher(taxItem);

expenseAccountID = taxItem->HandleTaxesDue(id_PayrollRecord, GetDBID(), removeItem);
}

// also add to the virtual account TCS 11/10/00 rev 11/21/00
CUtilityAccount::AddToBothArrays(expenseAccountID, this, removeItem);
}
/*********************************************************************************

PostBenefitsDue TCS 7/29/02

post a benefit deduction or credit
*********************************************************************************/
void CPayrollRecord::PostBenefitsDue(const Boolean removeItem)
{
CMoney paymentAmount = GetTaxPaymentAmount(); // rev TCS 12/28/01

if (paymentAmount.IsZero())
return;

TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));

DBid expenseAccountID = account_UnpaidBenefits;

// post to the benefit item (which will update the account)
CBenefitItem *benefitItem = TCS_SAFE_CAST(gDBFile->GetOneObject(id_BenefitItem, mTransactionRef),
CBenefitItem);
if (benefitItem)
{
DB_ObjectWatcher watcher(benefitItem);

expenseAccountID = benefitItem->HandleTaxesDue(id_PayrollRecord, GetDBID(), removeItem);
}

// also post to the virtual account TCS 11/10/00 rev TCS 11/21/00
CUtilityAccount::AddToBothArrays(expenseAccountID, this, removeItem);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

AddToEmployeeArray TCS 2/22/99

add or remove this transaction in the employee array
*********************************************************************************/
void CPayrollRecord::AddToEmployeeArray(const Boolean removeIt)
{
CEmployeeAccount *employee = TCS_SAFE_CAST(gDBFile->GetOneObject(id_EmployeeAccount,
mMainAccount), CEmployeeAccount);
if (employee)
{
DB_ObjectWatcher watcher(employee);
employee->AddToPayrollRecordArray(GetDBID(), removeIt);
}
}
/*********************************************************************************

HandlePaymentMade TCS 4/11/00 rev TCS 6/6/00

deal with a payment that has been made for this item. We overide, since it should
also be passed along to the extra breakdown arrays.
*********************************************************************************/
void CPayrollRecord::HandlePaymentMade(const CMoney &inAmount, const UInt8 sourceClass,
const DBid sourceID, const UInt8 transactionType, const Boolean removeItem)
{
// We post very differently for advances. rev TCS 9/18/01, 9/20/01
if (mConditions == condition_Repay || mConditions == condition_Advance)
{
DB_PersistentObject *employee = gDBFile->GetOneObject(id_EmployeeAccount, mMainAccount);

if (employee)
{
DB_ObjectWatcher watcher(employee);
employee->PayOnAccount(inAmount);
}

// prepare to update
UInt8 saveType = PrepareViewerDisplay();

if (removeItem)
SetStatus(status_Entered);
else
SetStatus(status_Paid);

// if we are currently in a viewer, need to update it
UpdateViewerDisplay(saveType);
}
else if (mConditions == condition_MaterialReimburse || mConditions == condition_OtherCostReimburse ||
mConditions == condition_SubcontractReimburse)
{
// for reimbursements there is no further posting, so we just
// change the status. TCS 9/30/03

// prepare to update
UInt8 saveType = PrepareViewerDisplay();

if (removeItem)
SetStatus(status_Entered);
else
SetStatus(status_Paid);

// if we are currently in a viewer, need to update it
UpdateViewerDisplay(saveType);
}
else
{ // the superclass handles most posting details- status, amount paid etc
// it also updates the main breakdown array (wage items)
THE_SUPERCLASS::HandlePaymentMade(inAmount, sourceClass, sourceID, transactionType, removeItem);

// we pass along payment info to our other breakdown arrays, also TCS 5/1/00
MarkBreakdownsPaid(mCommissionArray, id_CommishBreakdownEntry, !removeItem, inAmount,
sourceClass, sourceID, transactionType, removeItem, cPaymentMade);
MarkBreakdownsPaid(mDeductionArray, id_DeductBreakdownEntry, !removeItem, inAmount,
sourceClass, sourceID, transactionType, removeItem, cPaymentMade);
MarkBreakdownsPaid(mEmployerTaxArray, id_EmpTaxBreakdownEntry, !removeItem, inAmount,
sourceClass, sourceID, transactionType, removeItem, cPaymentMade);
MarkBreakdownsPaid(mCategoryItemArray, id_CatTaxBreakdownEntry, !removeItem, inAmount,
sourceClass, sourceID, transactionType, removeItem, cPaymentMade);
MarkBreakdownsPaid(mBenefitArray, id_BennyBreakdownEntry, !removeItem, inAmount,
sourceClass, sourceID, transactionType, removeItem, cPaymentMade);
}

// update the payables account TCS 4/25/01
CUtilityAccount::AddToActiveArray(account_UnpaidPayroll, this, !removeItem);

// store payment refs TCS 7/29/02
AddToObjectInfoArray(mPaymentArray, sourceClass, sourceID, mConditions, removeItem, true);
}
/*********************************************************************************

HandlePaymentReceived TCS 9/18/01

deal with a payment received, via payment receipt or deposit. We override
the superclass, since the only time we need to deal with a payment received
is when this transaction is an advance repayment.
*********************************************************************************/
void CPayrollRecord::HandlePaymentReceived(const CMoney &inAmount, const UInt8 sourceClass,
const DBid sourceID, const UInt8 /*transactionType*/,
const Boolean removeItem, const Boolean /*fromDeposit*/,
const Boolean /*fromBillRecord*/)
{
// we should never receive payment if void TCS 12/7/99
if (HasVoidStatus())
{
TCS_DebugAlert("Oops, invalid void payment in CPayrollRecord:: HandlePaymentReceived!");
return;
}
// if this is an advance repay, adjust the employee 'on account' balance
// note that inAmount is negative if a payment is being cancelled, so we don't
// need to adjust the sign here.
if (mConditions == condition_Repay)
{
DB_PersistentObject *employee = gDBFile->GetOneObject(id_EmployeeAccount, mMainAccount);

if (employee)
{
DB_ObjectWatcher watcher(employee);

employee->PayOnAccount(-inAmount);
}

UInt8 success = PrepareViewerDisplay(); // TCS 8/7/02

// adjust the status
if (removeItem)
SetStatus(status_Entered);
else
SetStatus(status_Paid);

UpdateViewerDisplay(success);

// store payment refs TCS 7/29/02
AddToObjectInfoArray(mPaymentArray, sourceClass, sourceID, condition_Repay, removeItem, true);
}
else if (mConditions == condition_MaterialReimburse || mConditions == condition_OtherCostReimburse ||
mConditions == condition_SubcontractReimburse) // TCS 9/30/03
{
// prepare to update
UInt8 saveType = PrepareViewerDisplay();

if (removeItem)
SetStatus(status_Entered);
else
SetStatus(status_Paid);

// if we are currently in a viewer, need to update it
UpdateViewerDisplay(saveType);
}
}
/*********************************************************************************

HandleDeposit TCS 9/18/01

deal with a deposit.
*********************************************************************************/
void CPayrollRecord::HandleDeposit(const CMoney &/*amount*/, const UInt8 /*sourceClass*/,
const DBid /*sourceID*/, const Boolean /*removeItem*/,
const Boolean /*fromBillRecord*/)
{
// We don't do anything at all, since advance repayments are the only payroll item
// that would ever be deposited, and we really don't need to use deposited status for them.
}
/*********************************************************************************

HandleTaxesPaid TCS 7/29/02

handle payment of a tax item. This applies to miscellaneous tax payments and
credits.
*********************************************************************************/
void CPayrollRecord::HandleTaxesPaid(const DBClass sourceClass, const DBid sourceID,
const Boolean removeItem)
{
// We can just use the basic tax posting code, but reversed.
switch (mConditions)
{
case condition_Withholding: // we need to post taxes to the transaction
case condition_WithholdingCredit: // arrays and util accounts TCS 3/21/02 rev TCS 7/29/02
case condition_EmployerTax:
case condition_EmployerTaxCredit:
PostTaxesDue(!removeItem);
break;

case condition_Benefit: // TCS 7/29/02
case condition_BenefitCredit:
PostBenefitsDue(!removeItem);
break;

default:
TCS_DebugAlert("Oops, bad case in CPayrollRecord::HandleTaxesPaid!");
break;
}

// we use the receivables bit as a flag for tax payments
SetBeenReceivableBilled(!removeItem); // TCS 6/29/01

// store payment refs TCS 7/29/02
AddToObjectInfoArray(mPaymentArray, sourceClass, sourceID, id_OtherCost, removeItem, true);
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

GetCategoryTaxAmount TCS 6/2/00

return the amount of category tax for the given category and wage info
*********************************************************************************/
CMoney CPayrollRecord::GetCategoryTaxAmount(const DBid category, const CMoney &hours,
const CMoney &wageAmount) const
{
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));

TObjectIDArrayIterator iterator(mCategoryItemArray);
DBid id;
CCatTaxBreakdownEntry *entry;

while (iterator.Next(id))
{
entry = TCS_SAFE_CAST(gDBFile->GetOneObject(id_CatTaxBreakdownEntry, id),
CCatTaxBreakdownEntry);
if (entry)
{
DB_ObjectWatcher watcher(entry);

if (!category || entry->GetCategory() == category) // rev TCS 5/3/01
{
return (entry->CalculateCatTaxDeduction(hours, wageAmount));
}
}
}
// if we got this far, we must not have a matching category tax.
// use the default rate for the category system?
return 0;
}
/*********************************************************************************

GetStarterStatus TCS TCS 6/14/00

return the starting status. That depends on whether a payroll record was made

*********************************************************************************/
UInt8 CPayrollRecord::GetStarterStatus() const
{
if (IsMarked())
return status_PayRecord;
else
return status_Entered;
}
/*********************************************************************************

GetTaxName TCS 7/29/02

return the name of a tax or benefit item referenced by this item

*********************************************************************************/
CTextString CPayrollRecord::GetTaxName() const
{
if (mConditions == condition_Withholding || mConditions == condition_WithholdingCredit ||
mConditions == condition_EmployerTax || mConditions == condition_EmployerTaxCredit)
{
return gDBFile->GetObjectName(id_TaxItem, mTransactionRef);
}
else if (mConditions == condition_Benefit || mConditions == condition_BenefitCredit)
{
return gDBFile->GetObjectName(id_BenefitItem, mTransactionRef);
}
else
return GetMenuName();
}
/*********************************************************************************

GetTransactionRefClass TCS 11/21/03

get the class to use for the transaction ref.

*********************************************************************************/
DBClass CPayrollRecord::GetTransactionRefClass() const
{
if (mConditions == condition_Withholding || mConditions == condition_WithholdingCredit ||
mConditions == condition_EmployerTax || mConditions == condition_EmployerTaxCredit)
return id_TaxItem;
else if (mConditions == condition_Benefit || mConditions == condition_BenefitCredit)
return id_BenefitItem;
else
return 0;
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

CanBeDeleted TCS 2/6/99

we can't be deleted if a later record refers to us

*********************************************************************************/
Boolean CPayrollRecord::CanBeDeleted(const Boolean giveMessage) const
{
if (mNextRecord)
{ // we have a subsequent record. Let's see if it still exists
TCS_FailNILMsg(gDBFile, TCS_GetErrString(errID_BadFile));
if (gDBFile->ObjectExists(id_PayrollRecord, mNextRecord))
{
if (giveMessage)
{
TCS_ErrorAlert(TCS_GetMsgString(msgID_CantDeletePostedItem));
}
return false;
}
}
// if we got this far, pass it along for judgement
return THE_SUPERCLASS::CanBeDeleted(giveMessage); // bugfix TCS 8/7/02
}