Round balance amounts to cents before applying

Prevents sub-cent precision (e.g. $0.883125) from accumulating in
BalanceApplied and payment records. All balance math now rounds to
nearest cent first.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
John Mizerek 2026-03-02 14:32:54 -08:00
parent c580e6ec78
commit c65cd8242b
2 changed files with 6 additions and 4 deletions

View file

@ -79,7 +79,7 @@
<cfset taxRate = (isNumeric(qOrder.TaxRate) AND val(qOrder.TaxRate) GT 0) ? val(qOrder.TaxRate) : 0>
<cfset taxAmount = subtotal * taxRate>
<cfset deliveryFee = (val(qOrder.OrderTypeID) EQ 3) ? val(qOrder.DeliveryFee) : 0>
<cfset orderTotal = subtotal + taxAmount + platformFee + Tip + deliveryFee>
<cfset orderTotal = round((subtotal + taxAmount + platformFee + Tip + deliveryFee) * 100) / 100>
<!--- Auto-apply user balance (silently reduces cash owed) --->
<cfset balanceApplied = 0>
@ -92,7 +92,8 @@
)>
<cfset userBalance = val(qBalance.Balance)>
<cfif userBalance GT 0>
<cfset balanceToApply = min(userBalance, orderTotal)>
<!--- Round to cents to avoid sub-cent precision issues --->
<cfset balanceToApply = round(min(userBalance, orderTotal) * 100) / 100>
<!--- Atomic deduct: only succeeds if balance is still sufficient --->
<cfset qDeduct = queryExecute(
"UPDATE Users SET Balance = Balance - ? WHERE ID = ? AND Balance >= ?",

View file

@ -134,13 +134,14 @@ try {
userBalance = val(qOrder.Balance ?: 0);
orderUserID = val(qOrder.UserID ?: 0);
if (userBalance > 0 && orderUserID > 0) {
balanceApplied = min(userBalance, totalBeforeCardFee);
// Round to cents to avoid sub-cent precision issues
balanceApplied = round(min(userBalance, totalBeforeCardFee) * 100) / 100;
// Ensure Stripe minimum: adjusted amount after card fee must be >= $0.50
adjustedTest = ((totalBeforeCardFee - balanceApplied) + cardFeeFixed) / (1 - cardFeePercent);
if (adjustedTest < 0.50) {
// Cap balance so Stripe charge stays >= $0.50
maxBalance = totalBeforeCardFee - ((0.50 * (1 - cardFeePercent)) - cardFeeFixed);
balanceApplied = max(0, min(userBalance, maxBalance));
balanceApplied = round(max(0, min(userBalance, maxBalance)) * 100) / 100;
}
// Store intent on order (actual deduction happens in webhook after payment succeeds)
if (balanceApplied > 0) {