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

Price Rounding Methods (Source Code)

Link to: header | lists directory

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

Comments

CRoundingMethod

This class manages price rounding methods for the Goldenseal accounting software,
retail sales software, project management software and business management software.

a rounding method is used for pricing of items for sale. It computes retail
sale prices that end in .95 or other 'retail' type numbers. It also
handles simpler rounding, e.g. to the nearest penny or nickel.

SUPERCLASS = DB_ArrayOwner

Constructor

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

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

//TCS_BlockMove(&src->mStatus, &mStatus, cCopyFileLength);
}/*********************************************************************************

GetMemberValue

return the value of the member with the given tag

*********************************************************************************/
Boolean CRoundingMethod::GetMemberValue(const NeoTag aTag, const NeoTag aType,
void *aValue) const
{
switch (aTag)
{
default:
return THE_SUPERCLASS::GetMemberValue(aTag, aType, aValue);
break;
}
}/*********************************************************************************

SetMemberValue

set the value of the member with the given tag

*********************************************************************************/
Boolean CRoundingMethod::SetMemberValue(const NeoTag aTag, const NeoTag aType,
const void *aValue)
{
switch (aTag)
{
default:
return THE_SUPERCLASS::SetMemberValue(aTag, aType, aValue);
break;
}
}
/*********************************************************************************

ReadObject

read the persistent object's data in from a stream
*********************************************************************************/
void CRoundingMethod::ReadObject(CNeoStream *aStream, const NeoTag aTag)
{
TCS_FailNILMsg(aStream, TCS_GetErrString(errID_BadStream));

CNeoDebugImport checker(aStream, this, cCheckTooSmall); // TCS 2/24/00

THE_SUPERCLASS::ReadObject(aStream, aTag);

ReadRoundingArrayFromStream(aStream, mEntries, cHasSafetyTag); // TCS 5/31/03

mEndSafetyTag = aStream->ReadEndSafetyTag(this); // mfs_sa 20feb2k3

if (!IsValidEndTag(mEndSafetyTag))
ReportDamagedObject(GetDBClassID(), GetDBID());
}/*********************************************************************************

WriteObject

write the persistent object's data to a stream
*********************************************************************************/
void CRoundingMethod::WriteObject(CNeoStream *aStream, const NeoTag 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);

WriteRoundingArrayToStream(aStream, mEntries, cHasSafetyTag); // TCS 5/31/03

aStream->WriteEndSafetyTag(mEndSafetyTag, this); // TCS 9/8/02 mfs_sa 20feb2k3
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

GetTableColInfo

return information about table columns
*********************************************************************************/
Boolean CRoundingMethod::CRoundingMethod_Desc::GetTableColInfo(const TagType tag,
const TableIndexT col,
STableColInfo *colInfo)
{
if (tag == tag_roundingtable)
{ // it's the depreciation table
switch (col)
{
case col_from:
colInfo->colType = coltype_caption;
colInfo->fieldType = fieldtype_money;
colInfo->colData = 0;
TCS_BufferFromText(colInfo->colName,
TCS_GetStockString(stockID_From), cTableColNameLength);
return true;
break;

case col_to:
colInfo->colType = coltype_edit;
colInfo->fieldType = fieldtype_money;
colInfo->colData = 0;
TCS_BufferFromText(colInfo->colName,
TCS_GetStockString(stockID_UpTo), cTableColNameLength);
return true;
break;

case col_method:
colInfo->colType = coltype_menucv;
colInfo->fieldType = fieldtype_cv;
colInfo->colData = MENU_RoundingStepMethods;
TCS_BufferFromText(colInfo->colName,
TCS_GetStockString(stockID_Method), cTableColNameLength);
return true;
break;

case col_roundto:
colInfo->colType = coltype_edit;
colInfo->fieldType = fieldtype_money;
colInfo->colData = 0;
TCS_BufferFromText(colInfo->colName,
TCS_GetStockString(stockID_RoundTo), cTableColNameLength);
return true;
break;

default:
return false;
break;
}
}
else
return false;
}

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

GetEntryFromRow

fill in the given percent data structure with info from the table

*********************************************************************************/
Boolean CRoundingMethod::GetEntryFromRow(const CTCS_Table &aTable,
const TableIndexT row,
SRoundingInfo *outInfo)
{
outInfo->from = CMoney(aTable.GetCellText(row, col_from));
outInfo->to = CMoney(aTable.GetCellText(row, col_to));
outInfo->roundto = CMoney(aTable.GetCellText(row, col_roundto));
outInfo->method = aTable.GetCellValue(row, col_method);
outInfo->filler = 0;
return true;
}/*********************************************************************************

FillRowFromEntry

fill the given table row with information from our entry

*********************************************************************************/
Boolean CRoundingMethod::FillRowFromEntry(CTCS_Table *aTable, const TableIndexT row,
const SRoundingInfo &inInfo)
{
aTable->SetCellText(row, col_from, inInfo.from.GetCurrencyString());
aTable->SetCellText(row, col_to, inInfo.to.GetCurrencyString());
aTable->SetCellText(row, col_roundto, inInfo.roundto.GetCurrencyString());
aTable->SetCVCellValue(row, col_method, inInfo.method);
return true; // TCS 1/13/02
}
/*********************************************************************************

ExportColumnCString

return the value of a column element from our struct TCS 5/12/98

*********************************************************************************/
CTextString CRoundingMethod::ExportColumnCString(const TableIndexT col,
const SRoundingInfo &outInfo)
{
switch (col)
{
case col_from:
return outInfo.from.GetCurrencyString();
break;

case col_to:
return outInfo.to.GetCurrencyString();
break;

case col_roundto:
return outInfo.roundto.GetCurrencyString();
break;

case col_method:
{
CTextString menuText;
if (FetchCVMenuText(col, outInfo.method, &menuText))
return menuText.AppendCVExportString(outInfo.method);
else
return cEmptyString;
}
break;

default:
return cEmptyString;
break;
}
}
/*********************************************************************************

ImportColumnCString

fill a column element in our struct TCS 6/10/98

*********************************************************************************/
Boolean CRoundingMethod::ImportColumnCString(const TableIndexT col,
const CTextString &inString, SRoundingInfo *inInfo)
{
switch (col)
{
case col_from:
inInfo->from = ConvertImportMoney(inString);
return true;
break;

case col_to:
inInfo->to = ConvertImportMoney(inString);
return true;
break;

case col_roundto:
inInfo->roundto = ConvertImportEMoney(inString);
return true;
break;

case col_method:
inInfo->method = inString.ParseID();
return true;
break;

default:
return false;
break;
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/*********************************************************************************

ApplyRounding shell TCS 1/27/00

apply price rounding to a money value

*********************************************************************************/
void CRoundingMethod::ApplyRounding(CMoney &inValue) const
{
// if an empty table, just round to the penny
if (mEntries.GetCount() == 0)
{
inValue.RoundDigits();
return;
}

// fetch a value from the table
SRoundingInfo info;
CTmplArrayIterator<SRoundingInfo> iterator(mEntries);
CMoney upperValue, lowerValue;

while (iterator.Next(info))
{
if (inValue >= info.from && inValue <= info.to)
break;
}

// branch depending on the rounding calc TCS 8/23/00
switch (info.method)
{
case calc_round:
case calc_roundup:
case calc_rounddown:
inValue = GetRoundedValue(inValue, info.roundto, info.method);
break;

case calc_trim:
lowerValue = TrimDownTo(inValue, info.roundto);
upperValue = TrimUpTo(inValue, info.roundto);
if ((upperValue - inValue) >(inValue - lowerValue))
inValue = lowerValue;
else
inValue = upperValue;
break;

case calc_trimup:
inValue = TrimUpTo(inValue, info.roundto);
break;

case calc_trimdown:
inValue = TrimDownTo(inValue, info.roundto);
break;

case calc_norounding:
// don't do anything
break;

case calc_fixeddigits:
inValue = ReplaceDigits(inValue, info.roundto);
break;

case calc_fixedvalue:
inValue = info.roundto;
break;

default:
TCS_DebugAlert("Oops, bad case in CRoundingMethod::ApplyRounding!");
break;
}
}
/*********************************************************************************

GetRoundedValue TCS 8/23/00 rev 7/25/01

calculate the next lower value than inValue, using the modulo amount.

*********************************************************************************/
CMoney CRoundingMethod::GetRoundedValue(CMoney &inValue, const CMoney &modulo,
const UInt8 roundingType) const
{
CMoney baseAmount = inValue,
upperValue;

// get raw dollar and penny amounts, for easier manipulation of values
DollarType moduloDollars = modulo.GetDollars(),
inDollars = inValue.GetDollars();
PennyType moduloPennies = modulo.GetRawPennies(),
inPennies = inValue.GetRawPennies();
SInt32 moduloTotalPennies = 0,
excessDollars = 0,
excessPennies = 0;

// to simplify the 'modulo' action, we'll start at the next lower dollar
// amount(or next lower 10-to-nth-power dollars, if modulo is over $1).
// This will probably be more logical for users anyhow. Though who knows
// what someone would expect from rounding to 4.17 or similar odd values.
if (moduloDollars < 1)
{
baseAmount.SetDollars(inDollars);
excessPennies = inPennies % moduloPennies;
baseAmount.SetRawPennies(inPennies - excessPennies);
}
else if (moduloDollars < 10)
{
// start the base amount at the 10-to-nth value
baseAmount.RoundDown(-1);

// calculate the dollar and penny modulos
moduloTotalPennies = moduloDollars * 100 * cPrecision + moduloPennies;
excessDollars = inValue.GetDollars() - baseAmount.GetDollars();
excessPennies = excessDollars * 100 * cPrecision + inPennies;
excessPennies = (excessPennies - excessPennies % moduloTotalPennies);
excessDollars = excessPennies /(100 * cPrecision);

// add the modulo amount to the base value
baseAmount.AddDollars(excessDollars);
baseAmount.SetRawPennies(excessPennies - excessDollars * 100 * cPrecision);
}
else if (moduloDollars < 100)
{
// start the base amount at the 10-to-nth value
baseAmount.RoundDown(-2);

// calculate the dollar and penny modulos
moduloTotalPennies = moduloDollars * 1000 * cPrecision + moduloPennies;
excessDollars = inValue.GetDollars() - baseAmount.GetDollars();
excessPennies = excessDollars * 1000 * cPrecision + inPennies;
excessPennies = (excessPennies - excessPennies % moduloTotalPennies);
excessDollars = excessPennies /(1000 * cPrecision);

// add the modulo amount to the base value
baseAmount.AddDollars(excessDollars);
baseAmount.SetRawPennies(excessPennies - excessDollars * 1000 * cPrecision);
}
else // moduloDollars >= 100. We stop here so we don't get overflow in
{ // intermediate values, for large dollar amounts. This still may break
// for very large inValue values.

// start the base amount at the 10-to-nth value
baseAmount.RoundDown(-3);

// calculate the dollar and penny modulos
moduloTotalPennies = moduloDollars * 10000 * cPrecision + moduloPennies;
excessDollars = inValue.GetDollars() - baseAmount.GetDollars();
excessPennies = excessDollars * 10000 * cPrecision + inPennies;
excessPennies = (excessPennies - excessPennies % moduloTotalPennies);
excessDollars = excessPennies /(10000 * cPrecision);

// add the modulo amount to the base value
baseAmount.AddDollars(excessDollars);
baseAmount.SetRawPennies(excessPennies - excessDollars * 10000 * cPrecision);
}

switch (roundingType) // rev TCS 7/25/01
{
case calc_round:
upperValue = baseAmount + modulo;
if ((upperValue - inValue) >(inValue - baseAmount))
return baseAmount;
else
return upperValue;
break;

case calc_roundup:
if (excessPennies)
return baseAmount + modulo;
else
return baseAmount;
break;

case calc_rounddown:
return baseAmount;
break;

default:
TCS_DebugAlert("Oops, bad rounding type in CRoundingMethod::GetRoundedValue!");
return baseAmount;
break;

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

ReplaceDigits TCS 8/23/00

do a simple digit replacement, for rounding using the calc_fixeddigits method,
and for small change in retail trimming

*********************************************************************************/
CMoney CRoundingMethod::ReplaceDigits(CMoney &inValue, const CMoney &roundTo) const
{
SInt32 roundingDigits = roundTo.GetLargestDigit();

DollarType inDollars = inValue.GetDollars(),
roundedDollars = roundTo.GetDollars();
PennyType inPennies = inValue.GetRawPennies(),
roundedPennies = roundTo.GetRawPennies();
CMoney outValue = inValue;

switch (roundingDigits)
{
case 9: // replace the $100,000,000 digit(and smaller)
inDollars = inDollars - inDollars % 1000000000;
outValue.SetDollars(inDollars + roundedDollars);
outValue.SetRawPennies(roundedPennies);
break;

case 8: // replace the $10,000,000 digit(and smaller)
inDollars = inDollars - inDollars % 100000000;
outValue.SetDollars(inDollars + roundedDollars);
outValue.SetRawPennies(roundedPennies);
break;

case 7: // replace the $1,000,000 digit(and smaller)
inDollars = inDollars - inDollars % 10000000;
outValue.SetDollars(inDollars + roundedDollars);
outValue.SetRawPennies(roundedPennies);
break;

case 6: // replace the $100,000 digit(and smaller)
inDollars = inDollars - inDollars % 1000000;
outValue.SetDollars(inDollars + roundedDollars);
outValue.SetRawPennies(roundedPennies);
break;

case 5: // replace the $10,000 digit(and smaller)
inDollars = inDollars - inDollars % 100000;
outValue.SetDollars(inDollars + roundedDollars);
outValue.SetRawPennies(roundedPennies);
break;

case 4: // replace the $1,000 digit(and smaller)
inDollars = inDollars - inDollars % 10000;
outValue.SetDollars(inDollars + roundedDollars);
outValue.SetRawPennies(roundedPennies);
break;

case 3: // replace the $100 digit(and smaller)
inDollars = inDollars - inDollars % 1000;
outValue.SetDollars(inDollars + roundedDollars);
outValue.SetRawPennies(roundedPennies);
break;

case 2: // replace the $10 digit(and smaller)
inDollars = inDollars - inDollars % 100;
outValue.SetDollars(inDollars + roundedDollars);
outValue.SetRawPennies(roundedPennies);
break;

case 1: // replace the $1 digit(and pennies)
inDollars = inDollars - inDollars % 10;
outValue.SetDollars(inDollars + roundedDollars);
outValue.SetRawPennies(roundedPennies);
break;

case -1: // replace all the pennies
outValue.SetRawPennies(roundedPennies);
break;

case -2: // replace the penny digit
inPennies = inPennies - inPennies % 1000;
roundedPennies = roundedPennies % 1000;
outValue.SetRawPennies(inPennies + roundedPennies);
break;

case -3: // replace the tenth-of-a-cent digit
inPennies = inPennies - inPennies % 100;
roundedPennies = roundedPennies % 100;
outValue.SetRawPennies(inPennies + roundedPennies);
break;

case -4: // replace the hundredth-of-a-cent digit
inPennies = inPennies - inPennies % 10;
roundedPennies = roundedPennies % 10;
outValue.SetRawPennies(inPennies + roundedPennies);
break;

default:
// do nothing
break;
}

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

GetTrimUpDigit TCS 7/25/01

get the new digit to use when trimming a value up

*********************************************************************************/
UInt8 CRoundingMethod::GetTrimUpDigit(const UInt8 inDigit, const UInt8 roundDigit,
const Boolean digitIsFixed, Boolean &carryOver) const
{
switch (roundDigit)
{
case 0: // no trim value. Return the incoming digit,
if (carryOver) // with a digit increment if there's carryover.
{
if (inDigit == 9)
return 0; // continue carryover.
else if (digitIsFixed) // TCS 3/7/03
{
if (inDigit > 0)
carryOver = true;
return 0;
}
else
{
carryOver = false;
return inDigit + 1;
}
}
else
{
return inDigit;
}
break;

case 1: // go up to nearest odd value
switch (inDigit)
{
case 0:
carryOver = false;
case 1:
return 1;
break;

case 2:
carryOver = false;
case 3:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = true;
return 1;
}
else
return 3;
break;

case 4:
carryOver = false;
case 5:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = true;
return 1;
}
else
return 5;
break;

case 6:
carryOver = false;
case 7:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = true;
return 1;
}
else
return 7;
break;

case 8:
carryOver = false;
case 9:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = true;
return 1;
}
else
return 9;
break;

default:
TCS_DebugAlert("Oops, bad digit in CRoundingMethod::GetTrimUpDigit case 1!");
return 0;
break;
}
break;

case 2: // go up to nearest even value
switch (inDigit)
{
case 0:
return 0;
break;

case 1:
carryOver = false;
case 2:
return 2;
break;

case 3:
carryOver = false;
case 4:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = true;
return 2;
}
else
return 4;
break;

case 5:
carryOver = false;
case 6:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = true;
return 2;
}
else
return 6;
break;

case 7:
carryOver = false;
case 8:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = true;
return 2;
}
else
return 8;
break;

case 9:
carryOver = true;
if (digitIsFixed) // TCS 3/7/03
return 2;
else
return 0;
break;

default:
TCS_DebugAlert("Oops, bad digit in CRoundingMethod::GetTrimUpDigit case 2!");
return 0;
break;
}
break;

case 3: // go up to nearest 3, 6 or 9
switch (inDigit)
{
case 0:
case 1:
case 2:
carryOver = false;
case 3:
return 3;
break;

case 4:
case 5:
carryOver = false;
case 6:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = true;
return 3;
}
else
return 6;
break;

case 7:
case 8:
carryOver = false;
case 9:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = true;
return 3;
}
else
return 9;
break;

default:
TCS_DebugAlert("Oops, bad digit in CRoundingMethod::GetTrimUpDigit case 3!");
return 0;
break;
}
break;

case 4: // go up to nearest 4 or 9
switch (inDigit)
{
case 0:
case 1:
case 2:
case 3:
carryOver = false;
case 4:
return 4;
break;

case 5:
case 6:
case 7:
case 8:
carryOver = false;
case 9:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = true;
return 4;
}
else
return 9;
break;

default:
TCS_DebugAlert("Oops, bad digit in CRoundingMethod::GetTrimUpDigit case 4!");
return 0;
break;
}
break;

case 5: // go up to nearest 5 or 0
switch (inDigit)
{
case 0:
case 1:
case 2:
case 3:
case 4:
carryOver = false;
case 5:
return 5;

case 6:
case 7:
case 8:
case 9:
carryOver = true;
if (digitIsFixed)
return 5; // TCS 3/7/03
else
return 0;
break;

default:
TCS_DebugAlert("Oops, bad digit in CRoundingMethod::GetTrimUpDigit case 5!");
return 0;
break;
}
break;

case 6:
case 7:
case 8:
case 9:
if (inDigit < roundDigit) // adjust carry-over
carryOver = false;
else if (inDigit > roundDigit)
carryOver = true;

return roundDigit; // use the actual digit
break;

default:
TCS_DebugAlert("Oops, bad rounding digit in CRoundingMethod::GetTrimUpDigit!");
return 0;
break;
}
}
/*********************************************************************************

GetTrimDownDigit TCS 7/26/01

get the new digit to use when trimming a value down

*********************************************************************************/
UInt8 CRoundingMethod::GetTrimDownDigit(const UInt8 inDigit, const UInt8 roundDigit,
const Boolean digitIsFixed, Boolean &carryOver) const
{

switch (roundDigit)
{
case 0: // no trim value. Return the incoming digit
if (carryOver) // with a digit decrement if there's carryover.
{
if (digitIsFixed)
return 0; // continue carryover.
else if (inDigit == 0)
return 9; // continue carryover.
else
{
carryOver = false;
return inDigit - 1;
}
}
else
{
return inDigit;
}
break;

case 1: // go down to nearest odd value
switch (inDigit)
{
case 0:
carryOver = true;
case 9:
if (digitIsFixed) // TCS 3/7/03
{
return 1;
}
else
return 9;
break;

case 2:
carryOver = false;
case 1:
return 1;
break;

case 4:
carryOver = false;
case 3:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = false;
return 1;
}
else
return 3;
break;

case 6:
carryOver = false;
case 5:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = false;
return 1;
}
else
return 5;
break;

case 8:
carryOver = false;
case 7:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = false;
return 1;
}
else
return 7;
break;

default:
TCS_DebugAlert("Oops, bad digit in CRoundingMethod::GetTrimDownDigit case 1!");
return 0;
break;
}
break;

case 2: // go down to nearest even value
switch (inDigit)
{
case 1:
carryOver = false;
case 0:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = true;
return 2;
}
else
return 0;
break;

case 3:
carryOver = false;
case 2:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = false;
return 2;
}
else
return 2;
break;

case 5:
carryOver = false;
case 4:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = false;
return 2;
}
else
return 4;
break;

case 7:
carryOver = false;
case 6:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = false;
return 2;
}
else
return 6;
break;

case 9:
carryOver = false;
case 8:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = false;
return 2;
}
else
return 8;
break;

default:
TCS_DebugAlert("Oops, bad digit in CRoundingMethod::GetTrimDownDigit case 2!");
return 0;
break;
}
break;

case 3: // go down to nearest 3, 6 or 9
switch (inDigit)
{
case 0:
case 1:
case 2:
carryOver = true;
case 9:
if (digitIsFixed) // TCS 3/7/03
{
if (inDigit == 9)
carryOver = false;
return 3;
}
else
return 9;
break;

case 4:
case 5:
carryOver = false;
case 3:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = false;
return 3;
}
else
return 3;
break;

case 7:
case 8:
carryOver = false;
case 6:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = false;
return 3;
}
else
return 6;
break;

default:
TCS_DebugAlert("Oops, bad digit in CRoundingMethod::GetTrimDownDigit case 3!");
return 0;
break;
}
break;

case 4: // go down to nearest 4 or 9
switch (inDigit)
{
case 0:
case 1:
case 2:
case 3:
carryOver = true;
case 9:
if (digitIsFixed) // TCS 3/7/03
{
if (inDigit == 9)
carryOver = false;
return 4;
}
else
return 9;
break;

case 5:
case 6:
case 7:
case 8:
carryOver = false;
case 4:
return 4;
break;

default:
TCS_DebugAlert("Oops, bad digit in CRoundingMethod::GetTrimDownDigit case 4!");
return 0;
break;
}
break;

case 5: // go down to nearest 5 or 0
switch (inDigit)
{
case 1:
case 2:
case 3:
case 4:
carryOver = false;
case 0:
if (digitIsFixed) // TCS 3/7/03
{
carryOver = true;
return 5;
}
else
return 0;

case 6:
case 7:
case 8:
case 9:
carryOver = false;
case 5:
return 5;
break;

default:
TCS_DebugAlert("Oops, bad digit in CRoundingMethod::GetTrimDownDigit case 5!");
return 0;
break;
}
break;

case 6:
case 7:
case 8:
case 9:
if (inDigit > roundDigit) // adjust carry-over
carryOver = false;
else if (inDigit < roundDigit)
carryOver = true;
return roundDigit; // use the actual digit
break;

default:
TCS_DebugAlert("Oops, bad rounding digit in CRoundingMethod::GetTrimDownDigit!");
return 0;
break;
}
}
/*********************************************************************************

GetFirstNonZeroDigit TCS 3/7/03

get the digit position of the first digit that is "unfixed". That is the
first non-zero digit that has all zeros to its left.

*********************************************************************************/
SInt8 CRoundingMethod::GetFirstNonZeroDigit(const CMoney &inValue) const
{
UInt8 theDigit;

for (SInt8 digit = 10; digit > -4; digit--)
{
if (digit == 0) // TCS 3/9/03
continue;

theDigit = inValue.GetNthDigit(digit);

if (theDigit > 0)
return theDigit;
}

return -4;
}
/*********************************************************************************

TrimUpTo TCS 8/23/00 rev 7/25/01

trim a value up to 'retail' style pricing

*********************************************************************************/
CMoney CRoundingMethod::TrimUpTo(const CMoney &inValue, const CMoney &roundTo) const
{
// we loop an extra digit to allow for carryover
SInt32 roundingDigits = TCS_MIN(10, inValue.GetLargestDigit() + 1);

UInt8 inDigit, trimDigit, newDigit;
Boolean carryOver = false, digitIsFixed = true;

SInt8 firstUnfixedDigit = GetFirstNonZeroDigit(roundTo);

CMoney outValue = inValue;
// loop through digits from small to large, and replace as needed
for (SInt8 digit = -2; digit <= roundingDigits; digit++)
{
if (digit != 0)
{
if (digit < firstUnfixedDigit) // TCS bugfix 3/7/03
digitIsFixed = true;

inDigit = inValue.GetNthDigit(digit);
trimDigit = roundTo.GetNthDigit(digit);
newDigit = GetTrimUpDigit(inDigit, trimDigit, digitIsFixed, carryOver);

if (newDigit != inDigit)
outValue.SetNthDigit(digit, newDigit);
}
}

// drop any fractional pennies
outValue.Truncate();
return outValue;
}
/*********************************************************************************

TrimDownTo TCS 7/25/01

trim a value down to 'retail' style pricing

*********************************************************************************/
CMoney CRoundingMethod::TrimDownTo(const CMoney &inValue, const CMoney &roundTo) const
{
// we loop an extra digit to allow for carryover
SInt32 roundingDigits = TCS_MIN(10, inValue.GetLargestDigit() + 1);

UInt8 inDigit, trimDigit, newDigit;
Boolean carryOver = false, digitIsFixed = false;

SInt8 firstUnfixedDigit = GetFirstNonZeroDigit(roundTo);

CMoney outValue = inValue;
// loop through digits from small to large, and replace as needed
for (SInt8 digit = -2; digit <= roundingDigits; digit++)
{
if (digit != 0)
{
if (digit < firstUnfixedDigit) // TCS bugfix 3/7/03
digitIsFixed = true;

inDigit = inValue.GetNthDigit(digit);
trimDigit = roundTo.GetNthDigit(digit);
newDigit = GetTrimDownDigit(inDigit, trimDigit, digitIsFixed, carryOver);

if (newDigit != inDigit)
outValue.SetNthDigit(digit, newDigit);
}
}

// drop any fractional pennies
outValue.Truncate();
return outValue;
}
/*********************************************************************************

FillDataReport TCS 9/6/02

fill in a diagnostic table that shows data field values.

*********************************************************************************/
void CRoundingMethod::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);

FillFieldArrayRow(table, stream, "mEntries", mEntries);

FillEndSafetyTag(table, stream, mEndSafetyTag);
}