Copy link to clipboard
Copied
I am having an issue with the square API and want to make sure I'm not doing something stupid. Here's my code:
<cfset stFields = {
"order": {
"idempotency_key": "xxxxxx-215d-4dce-b92a-90c306eb5eba",
"location_id": "xxxxxx",
"total_money": {
"amount": 99999,
"currency_code": "USD"
},
"order": {
"location_id": "xxxxx",
"customer_id": "asdasd"
}
},
"idempotency_key": "xxxxxx-215d-4dce-b92a-90c306eb5eba",
"ask_for_shipping_address": false,
"merchant_support_email": "consectetur@loremipsum.com",
"redirect_url": "https://abc.com"
}
>
I keep getting the error:
{"errors":[{"category":"INVALID_REQUEST_ERROR","code":"VALUE_TOO_LOW","detail":"`order.total_money.amount` must be greater than 1.","field":"order.total_money.amount"}]} Yet... It looks to me like there's a value... Any ideas???
|
To reiterate, the error does not originate from the struct stFields. It originates from squareupdata, the output of a cfhttp post.
But we don't know the contents of squareupdata. So the original question is moot.
In any case, since CF2016 Update 2, you can specify the data type of a struct's key-value pair as follows:
<cfset metadata = {someKey: {type:"int"}}>
<cfset myStruct.setMetadata(metadata)>
Copy link to clipboard
Copied
It seems the issue was how CF2016 processes the JSON. The exact same code works in CF2021.
Copy link to clipboard
Copied
Could it be that the error message is justified? That is, could it be that order.total_money.amount must be in currency format? Hence 99999.00 instead of 99999.
Copy link to clipboard
Copied
Square uses the lowest common denominator of any currency. So in the US, that's a penny. Sending 1 equals $0.01 where sending 100 equals $1.00.
The issue was in CF 2016 when serializing the JSON CF wasn't sending the amounts as integers even if you wrapped it as INT(#value#). In CF2018 and CF2021 serializing the JSON created the value as an integer and Square was happy. We tested the exact same code in 2016, 2018, and 2021. It failed in 2016 and worked perfectly in the newer versions.
Copy link to clipboard
Copied
I tested your exact code on trycf.com. It worked without any problems.
Copy link to clipboard
Copied
Suggestions:
1) Ensure you have the latest CF2016 update.
2) Add the following fix just before the serializeJson(stFields) call:
<cfset metadata = {"amount": {type:"int"}}>
<cfset stFields.setMetadata(metadata)>
<!--- Try the following line instead, if the last line doesn't solve the problem.--->
<!---<cfset stFields.order.total_money.setMetadata(metadata)>--->
Copy link to clipboard
Copied
Hang on. I just noticed something. Apparently, you're looking at the wrong struct.
The error does not occur when you serialize the struct stFields. It occurs with the struct named SquareUpData.
Copy link to clipboard
Copied
I have updated to 2021. I appreciate your help though. For the next person reading this...
1) The field order.total_money_amount is actually a read-only field that Square calculates in the response. It is based on you sending order.amount and order.quantity. You don't send total_money in the request.
2) SquareUpData is the response data, not the data you send.
Here's an example of working code:
<cfset REQUEST.location_id = "YourLocationID">
<cfset REQUEST.Access_Token = "YourToken">
<cfset REQUEST.Square_Server = "connect.squareup.com">
<cfset REQUEST.Square_Version = "2020-12-16">
<cfif StructKeyExists(Session, "total") AND StructKeyExists(Session, "CustomerID")>
<cfset session.total = session.total * 100 />
<cfset REQUEST.Amount = #session.total#>
<cfif isDefined("URL.transactionId")>
<cfset rtFields = {
"order_ids": [
"#URL.orderID#"
]
}>
<cfhttp method="post" result="objGet" url="https://#REQUEST.Square_Server#/v2/locations/#REQUEST.location_id#/orders/batch-retrieve">
<cfhttpparam type="header" name="Accept" value="application/json">
<cfhttpparam type="header" name="Authorization" value="Bearer #REQUEST.Access_Token#">
<cfhttpparam type="header" name="Cache-Control" value="no-cache">
<cfhttpparam type="header" name="Content-Type" value="application/json">
<cfhttpparam type="body" value="#serializeJSON(rtFields)#">
</cfhttp>
<cfelse>
<cfset REQUEST.Base_Price_Money_Amount = #session.total#>
<cfset REQUEST.idempotency_key = #CreateUUID()#>
<cfset REQUEST.order_idempotency_key = #CreateUUID()#>
<cfset stFields = {
"idempotency_key": "#REQUEST.idempotency_key#",
"order": {
"idempotency_key": "REQUEST.order_idempotency_key",
"order": {
"location_id": "#session.REQUEST_LocationID",
"customer_id": "C-#session.CustomerID#",
"line_items": [
{
"quantity": '1',
"name": "Item Name",
"note": "Any Item Note",
"uid": "uid",
"base_price_money": {
"amount": int(#REQUEST.Base_Price_Money_Amount#),
"currency": "USD"
}
}
]
}
},
"ask_for_shipping_address": false,
"merchant_support_email": "CustomerService@example.com",
"redirect_url": "https://someURL.com/SquareOrderComplete.cfm"
}>
<cfhttp method="post" result="objGet" url="https://#REQUEST.Square_Server#/v2/locations/#REQUEST.location_id#/checkouts">
<cfhttpparam type="header" name="Square-Version" value="#REQUEST.Square_Version#">
<cfhttpparam type="header" name="Authorization" value="Bearer #REQUEST.Access_Token#">
<cfhttpparam type="header" name="Content-Type" value="application/json">
<cfhttpparam type="body" value="#serializeJSON(stFields)#">
</cfhttp>
</cfif>
<cfscript>
squareupdata = deserializeJSON(#objGet.FileContent#);
</cfscript>
3) If using CF2016 you need to add the metadata above in BKBK's post. You don't need it in 2018 and 2021.
4) Square checkout (unlike Stripe) after the customer completes the checkout does not return JSON. The customer can't get to the order complete page until the card has been approved. You get ID's for reference in the order complete URL.
Copy link to clipboard
Copied
To reiterate, the error does not originate from the struct stFields. It originates from squareupdata, the output of a cfhttp post.
But we don't know the contents of squareupdata. So the original question is moot.
In any case, since CF2016 Update 2, you can specify the data type of a struct's key-value pair as follows:
<cfset metadata = {someKey: {type:"int"}}>
<cfset myStruct.setMetadata(metadata)>
Copy link to clipboard
Copied
BKBK, I appreciate your response. You are always helpful. In this case, however, you are partially correct. Yes, metadata would have fixed the issue in 2016 but is not needed in 2018 or 2021.
"To reiterate, the error does not originate from the struct stFields. It originates from squareupdata, the output of a cfhttp post. But we don't know the contents of squareupdata. So the original question is moot."
As I said above the issue is in stFields, not SquareUpData. SquareUpData is the response data from Square. You do not post SquareUpData it is a read only response. You post stFields and Square responds with a check_out URL in SquareUpData unless there is an error and then Square responds with the error in SquareUpData. The field order.Total_Money_Amount is a read-only field calculated by Square based on the fields in order.line_items.quantity and order.line_items.amount. Quantity and amount need to be integers. If Square can't read quantity and amount then the total order amount is less than 1 and Square responds in SquareUpData what the error is.