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:
parent
c580e6ec78
commit
c65cd8242b
2 changed files with 6 additions and 4 deletions
|
|
@ -79,7 +79,7 @@
|
||||||
<cfset taxRate = (isNumeric(qOrder.TaxRate) AND val(qOrder.TaxRate) GT 0) ? val(qOrder.TaxRate) : 0>
|
<cfset taxRate = (isNumeric(qOrder.TaxRate) AND val(qOrder.TaxRate) GT 0) ? val(qOrder.TaxRate) : 0>
|
||||||
<cfset taxAmount = subtotal * taxRate>
|
<cfset taxAmount = subtotal * taxRate>
|
||||||
<cfset deliveryFee = (val(qOrder.OrderTypeID) EQ 3) ? val(qOrder.DeliveryFee) : 0>
|
<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) --->
|
<!--- Auto-apply user balance (silently reduces cash owed) --->
|
||||||
<cfset balanceApplied = 0>
|
<cfset balanceApplied = 0>
|
||||||
|
|
@ -92,7 +92,8 @@
|
||||||
)>
|
)>
|
||||||
<cfset userBalance = val(qBalance.Balance)>
|
<cfset userBalance = val(qBalance.Balance)>
|
||||||
<cfif userBalance GT 0>
|
<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 --->
|
<!--- Atomic deduct: only succeeds if balance is still sufficient --->
|
||||||
<cfset qDeduct = queryExecute(
|
<cfset qDeduct = queryExecute(
|
||||||
"UPDATE Users SET Balance = Balance - ? WHERE ID = ? AND Balance >= ?",
|
"UPDATE Users SET Balance = Balance - ? WHERE ID = ? AND Balance >= ?",
|
||||||
|
|
|
||||||
|
|
@ -134,13 +134,14 @@ try {
|
||||||
userBalance = val(qOrder.Balance ?: 0);
|
userBalance = val(qOrder.Balance ?: 0);
|
||||||
orderUserID = val(qOrder.UserID ?: 0);
|
orderUserID = val(qOrder.UserID ?: 0);
|
||||||
if (userBalance > 0 && orderUserID > 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
|
// Ensure Stripe minimum: adjusted amount after card fee must be >= $0.50
|
||||||
adjustedTest = ((totalBeforeCardFee - balanceApplied) + cardFeeFixed) / (1 - cardFeePercent);
|
adjustedTest = ((totalBeforeCardFee - balanceApplied) + cardFeeFixed) / (1 - cardFeePercent);
|
||||||
if (adjustedTest < 0.50) {
|
if (adjustedTest < 0.50) {
|
||||||
// Cap balance so Stripe charge stays >= $0.50
|
// Cap balance so Stripe charge stays >= $0.50
|
||||||
maxBalance = totalBeforeCardFee - ((0.50 * (1 - cardFeePercent)) - cardFeeFixed);
|
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)
|
// Store intent on order (actual deduction happens in webhook after payment succeeds)
|
||||||
if (balanceApplied > 0) {
|
if (balanceApplied > 0) {
|
||||||
|
|
|
||||||
Reference in a new issue