Fix cash payment fee: use real Payfrit platform fee, not 2.25% cash handling fee
submitCash.cfm: Calculate platform fee from subtotal * PayfritFee, store in Orders.PlatformFee and Payments.PaymentPayfritsCut on submission. complete.cfm: Replace bogus 2.25% cash transaction fee with the real platform fee (customer fee + business fee = 2 × PayfritFee × subtotal). Credit full Payfrit revenue to User 0. Record business fee in PaymentPayfritNetworkFees. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
cb7e3b7fc6
commit
96c2ed3fc1
2 changed files with 51 additions and 23 deletions
|
|
@ -40,10 +40,13 @@
|
||||||
</cfif>
|
</cfif>
|
||||||
|
|
||||||
<cftry>
|
<cftry>
|
||||||
<!--- Get order details --->
|
<!--- Get order details with business fee rate --->
|
||||||
<cfset qOrder = queryExecute(
|
<cfset qOrder = queryExecute(
|
||||||
"SELECT ID, StatusID, UserID, BusinessID, ServicePointID, PaymentID
|
"SELECT o.ID, o.StatusID, o.UserID, o.BusinessID, o.ServicePointID, o.PaymentID,
|
||||||
FROM Orders WHERE ID = ? LIMIT 1",
|
b.PayfritFee
|
||||||
|
FROM Orders o
|
||||||
|
INNER JOIN Businesses b ON b.ID = o.BusinessID
|
||||||
|
WHERE o.ID = ? LIMIT 1",
|
||||||
[ { value = OrderID, cfsqltype = "cf_sql_integer" } ],
|
[ { value = OrderID, cfsqltype = "cf_sql_integer" } ],
|
||||||
{ datasource = "payfrit" }
|
{ datasource = "payfrit" }
|
||||||
)>
|
)>
|
||||||
|
|
@ -56,6 +59,21 @@
|
||||||
<cfset apiAbort({ "OK": false, "ERROR": "bad_state", "MESSAGE": "Order is not in cart state." })>
|
<cfset apiAbort({ "OK": false, "ERROR": "bad_state", "MESSAGE": "Order is not in cart state." })>
|
||||||
</cfif>
|
</cfif>
|
||||||
|
|
||||||
|
<!--- Calculate platform fee (customer portion — shown in cart) --->
|
||||||
|
<cfset feeRate = (isNumeric(qOrder.PayfritFee) AND val(qOrder.PayfritFee) GT 0) ? val(qOrder.PayfritFee) : 0>
|
||||||
|
<cfset customerFee = CashAmount * feeRate / (1 + feeRate)>
|
||||||
|
<!--- CashAmount already includes the customer fee (subtotal+tax+fee), back it out:
|
||||||
|
Actually CashAmount is what the Android app sends as the order total including fee.
|
||||||
|
The fee was calculated on subtotal, so we need the actual subtotal from line items. --->
|
||||||
|
<cfset qSubtotal = queryExecute(
|
||||||
|
"SELECT COALESCE(SUM(Price * Quantity), 0) AS Subtotal
|
||||||
|
FROM OrderLineItems WHERE OrderID = ? AND IsDeleted = b'0'",
|
||||||
|
[ { value = OrderID, cfsqltype = "cf_sql_integer" } ],
|
||||||
|
{ datasource = "payfrit" }
|
||||||
|
)>
|
||||||
|
<cfset subtotal = val(qSubtotal.Subtotal)>
|
||||||
|
<cfset platformFee = subtotal * feeRate>
|
||||||
|
|
||||||
<!--- Create Payment record with expected cash amount --->
|
<!--- Create Payment record with expected cash amount --->
|
||||||
<cfset CashAmountCents = round(CashAmount * 100)>
|
<cfset CashAmountCents = round(CashAmount * 100)>
|
||||||
<cfset qInsertPayment = queryExecute(
|
<cfset qInsertPayment = queryExecute(
|
||||||
|
|
@ -65,30 +83,34 @@
|
||||||
PaymentSentByUserID,
|
PaymentSentByUserID,
|
||||||
PaymentReceivedByUserID,
|
PaymentReceivedByUserID,
|
||||||
PaymentOrderID,
|
PaymentOrderID,
|
||||||
|
PaymentPayfritsCut,
|
||||||
PaymentAddedOn
|
PaymentAddedOn
|
||||||
) VALUES (?, 0, ?, 0, ?, NOW())",
|
) VALUES (?, 0, ?, 0, ?, ?, NOW())",
|
||||||
[
|
[
|
||||||
{ value = CashAmount, cfsqltype = "cf_sql_decimal" },
|
{ value = CashAmount, cfsqltype = "cf_sql_decimal" },
|
||||||
{ value = qOrder.UserID, cfsqltype = "cf_sql_integer" },
|
{ value = qOrder.UserID, cfsqltype = "cf_sql_integer" },
|
||||||
{ value = OrderID, cfsqltype = "cf_sql_integer" }
|
{ value = OrderID, cfsqltype = "cf_sql_integer" },
|
||||||
|
{ value = platformFee, cfsqltype = "cf_sql_decimal" }
|
||||||
],
|
],
|
||||||
{ datasource = "payfrit", result = "insertResult" }
|
{ datasource = "payfrit", result = "insertResult" }
|
||||||
)>
|
)>
|
||||||
|
|
||||||
<cfset PaymentID = insertResult.generatedKey>
|
<cfset PaymentID = insertResult.generatedKey>
|
||||||
|
|
||||||
<!--- Update order: link payment, set status to submitted, payment pending --->
|
<!--- Update order: link payment, set status to submitted, store platform fee --->
|
||||||
<cfset queryExecute(
|
<cfset queryExecute(
|
||||||
"UPDATE Orders
|
"UPDATE Orders
|
||||||
SET StatusID = 1,
|
SET StatusID = 1,
|
||||||
PaymentID = ?,
|
PaymentID = ?,
|
||||||
PaymentStatus = 'pending',
|
PaymentStatus = 'pending',
|
||||||
|
PlatformFee = ?,
|
||||||
TipAmount = ?,
|
TipAmount = ?,
|
||||||
SubmittedOn = NOW(),
|
SubmittedOn = NOW(),
|
||||||
LastEditedOn = NOW()
|
LastEditedOn = NOW()
|
||||||
WHERE ID = ?",
|
WHERE ID = ?",
|
||||||
[
|
[
|
||||||
{ value = PaymentID, cfsqltype = "cf_sql_integer" },
|
{ value = PaymentID, cfsqltype = "cf_sql_integer" },
|
||||||
|
{ value = platformFee, cfsqltype = "cf_sql_decimal" },
|
||||||
{ value = Tip, cfsqltype = "cf_sql_decimal" },
|
{ value = Tip, cfsqltype = "cf_sql_decimal" },
|
||||||
{ value = OrderID, cfsqltype = "cf_sql_integer" }
|
{ value = OrderID, cfsqltype = "cf_sql_integer" }
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -161,28 +161,31 @@
|
||||||
<cfset cashTip = val(qOrderTotal.TipAmount)>
|
<cfset cashTip = val(qOrderTotal.TipAmount)>
|
||||||
<cfset cashDeliveryFee = (val(qOrderTotal.OrderTypeID) EQ 3) ? val(qOrderTotal.DeliveryFee) : 0>
|
<cfset cashDeliveryFee = (val(qOrderTotal.OrderTypeID) EQ 3) ? val(qOrderTotal.DeliveryFee) : 0>
|
||||||
<cfset cashPayfritFee = (isNumeric(qOrderTotal.PayfritFee) AND val(qOrderTotal.PayfritFee) GT 0) ? val(qOrderTotal.PayfritFee) : 0.05>
|
<cfset cashPayfritFee = (isNumeric(qOrderTotal.PayfritFee) AND val(qOrderTotal.PayfritFee) GT 0) ? val(qOrderTotal.PayfritFee) : 0.05>
|
||||||
<cfset cashPlatformFee = cashSubtotal * cashPayfritFee>
|
|
||||||
<cfset orderTotalCents = round((cashSubtotal + cashTax + cashTip + cashDeliveryFee + cashPlatformFee) * 100)>
|
<!--- Customer fee: added to their total (visible in cart) --->
|
||||||
|
<cfset customerFeeDollars = cashSubtotal * cashPayfritFee>
|
||||||
|
<!--- Business fee: deducted when cash is distributed --->
|
||||||
|
<cfset businessFeeDollars = cashSubtotal * cashPayfritFee>
|
||||||
|
<!--- Total Payfrit revenue = customer fee + business fee --->
|
||||||
|
<cfset payfritRevenueDollars = customerFeeDollars + businessFeeDollars>
|
||||||
|
|
||||||
|
<cfset orderTotalCents = round((cashSubtotal + cashTax + cashTip + cashDeliveryFee + customerFeeDollars) * 100)>
|
||||||
|
|
||||||
<cfif CashReceivedCents LT orderTotalCents>
|
<cfif CashReceivedCents LT orderTotalCents>
|
||||||
<cfset apiAbort({ "OK": false, "ERROR": "insufficient_cash", "MESSAGE": "Cash received ($#numberFormat(CashReceivedCents/100, '0.00')#) is less than order total ($#numberFormat(orderTotalCents/100, '0.00')#)." })>
|
<cfset apiAbort({ "OK": false, "ERROR": "insufficient_cash", "MESSAGE": "Cash received ($#numberFormat(CashReceivedCents/100, '0.00')#) is less than order total ($#numberFormat(orderTotalCents/100, '0.00')#)." })>
|
||||||
</cfif>
|
</cfif>
|
||||||
|
|
||||||
<!--- Calculate cash transaction fee (on order total) --->
|
<cfset payfritRevenueCents = round(payfritRevenueDollars * 100)>
|
||||||
<cfif orderTotalCents LT 1000>
|
|
||||||
<cfset feeCents = round(orderTotalCents * 0.0225)>
|
|
||||||
<cfelse>
|
|
||||||
<cfset feeCents = 22 + round(orderTotalCents * 0.0005)>
|
|
||||||
</cfif>
|
|
||||||
|
|
||||||
<cfset changeCents = CashReceivedCents - orderTotalCents>
|
<cfset changeCents = CashReceivedCents - orderTotalCents>
|
||||||
<cfset businessReceivesCents = orderTotalCents - feeCents>
|
<cfset businessReceivesCents = orderTotalCents - payfritRevenueCents>
|
||||||
|
|
||||||
<cfset cashResult = {
|
<cfset cashResult = {
|
||||||
"orderTotalCents": orderTotalCents,
|
"orderTotalCents": orderTotalCents,
|
||||||
"cashReceivedCents": CashReceivedCents,
|
"cashReceivedCents": CashReceivedCents,
|
||||||
"changeCents": changeCents,
|
"changeCents": changeCents,
|
||||||
"feeCents": feeCents,
|
"customerFeeCents": round(customerFeeDollars * 100),
|
||||||
|
"businessFeeCents": round(businessFeeDollars * 100),
|
||||||
|
"payfritRevenueCents": payfritRevenueCents,
|
||||||
"businessReceivesCents": businessReceivesCents
|
"businessReceivesCents": businessReceivesCents
|
||||||
}>
|
}>
|
||||||
</cfif>
|
</cfif>
|
||||||
|
|
@ -296,12 +299,12 @@
|
||||||
}, { datasource = "payfrit" })>
|
}, { datasource = "payfrit" })>
|
||||||
</cfif>
|
</cfif>
|
||||||
|
|
||||||
<!--- Credit Payfrit fee to User 0 (Payfrit Network) --->
|
<!--- Credit Payfrit revenue (customer fee + business fee) to User 0 (Payfrit Network) --->
|
||||||
<cfif feeCents GT 0>
|
<cfif payfritRevenueCents GT 0>
|
||||||
<cfset queryTimed("
|
<cfset queryTimed("
|
||||||
UPDATE Users SET Balance = Balance + :fee WHERE ID = 0
|
UPDATE Users SET Balance = Balance + :fee WHERE ID = 0
|
||||||
", {
|
", {
|
||||||
fee: feeCents / 100
|
fee: payfritRevenueCents / 100
|
||||||
}, { datasource = "payfrit" })>
|
}, { datasource = "payfrit" })>
|
||||||
</cfif>
|
</cfif>
|
||||||
|
|
||||||
|
|
@ -333,7 +336,7 @@
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:sentBy, :receivedBy, :orderID,
|
:sentBy, :receivedBy, :orderID,
|
||||||
0, 0, :cashAmount,
|
0, 0, :cashAmount,
|
||||||
:payfritCut, 0, 0,
|
:payfritCut, 0, :bizFee,
|
||||||
'Cash payment', NOW()
|
'Cash payment', NOW()
|
||||||
)
|
)
|
||||||
", {
|
", {
|
||||||
|
|
@ -341,7 +344,8 @@
|
||||||
receivedBy: businessOwnerUserID,
|
receivedBy: businessOwnerUserID,
|
||||||
orderID: qTask.OrderID,
|
orderID: qTask.OrderID,
|
||||||
cashAmount: CashReceivedCents / 100,
|
cashAmount: CashReceivedCents / 100,
|
||||||
payfritCut: feeCents / 100
|
payfritCut: payfritRevenueCents / 100,
|
||||||
|
bizFee: round(businessFeeDollars * 100) / 100
|
||||||
}, { datasource = "payfrit" })>
|
}, { datasource = "payfrit" })>
|
||||||
|
|
||||||
<cfset cashProcessed = true>
|
<cfset cashProcessed = true>
|
||||||
|
|
@ -410,7 +414,9 @@
|
||||||
<cfset response["CashReceived"] = numberFormat(CashReceivedCents / 100, "0.00")>
|
<cfset response["CashReceived"] = numberFormat(CashReceivedCents / 100, "0.00")>
|
||||||
<cfset response["OrderTotal"] = numberFormat(orderTotalCents / 100, "0.00")>
|
<cfset response["OrderTotal"] = numberFormat(orderTotalCents / 100, "0.00")>
|
||||||
<cfset response["Change"] = numberFormat(changeCents / 100, "0.00")>
|
<cfset response["Change"] = numberFormat(changeCents / 100, "0.00")>
|
||||||
<cfset response["Fee"] = numberFormat(feeCents / 100, "0.00")>
|
<cfset response["CustomerFee"] = numberFormat(round(customerFeeDollars * 100) / 100, "0.00")>
|
||||||
|
<cfset response["BusinessFee"] = numberFormat(round(businessFeeDollars * 100) / 100, "0.00")>
|
||||||
|
<cfset response["PayfritRevenue"] = numberFormat(payfritRevenueCents / 100, "0.00")>
|
||||||
<cfset response["BusinessReceives"] = numberFormat(businessReceivesCents / 100, "0.00")>
|
<cfset response["BusinessReceives"] = numberFormat(businessReceivesCents / 100, "0.00")>
|
||||||
</cfif>
|
</cfif>
|
||||||
|
|
||||||
|
|
|
||||||
Reference in a new issue