Prefilled Cart Add-On
Using the Prefilled Cart Template in FlowBuilder
Prefilled Cart Activity in Flow
Adding the workflow property to the storefront configuration
Your storefront should have the workflow
property present in the configuration
. If it doesn't, you should add it:
mutation UpdateStorefront($name: String, $data: UpdateStorefrontInput!) {
updateStorefront(name: $name, data: $data) {
id
}
}
{
"name": "<<storefront-name>>",
"data": {
"configuration": {
"workflow": {
"<<worflow-name>>": {
"ng": true,
"name": "<<workflow-name>>",
"channel": "whatsapp",
"channelUid": "<<channel-phone-number>>"
},
}
}
}
}
Adding the pre-fill cart add-on to your storefront
â ď¸ Add just ONE of the add-on configurations below.
Configuration based on the last order (admin workspace)
mutation CreateAddOn($storefrontName: String!, $data: AddOnInput!) {
createAddOn(storefrontName: $storefrontName, data: $data) {
id
}
}
{
"storefrontName": "<<storefront_name>>",
"data": {
"type": "CREATE_SESSION",
"flavor": "REST",
"config": {
"url": "https://commerce-functions.yalochat.dev/v1/prefill",
"method": "POST",
"authMethod": "BASIC",
"token": "",
"body": {
"type": "lastOrder"
}
},
"executionTime": "AFTER"
}
}
Configuration based on recommendations (admin workspace)
mutation CreateAddOn($storefrontName: String!, $data: AddOnInput!) {
createAddOn(storefrontName: $storefrontName, data: $data) {
id
}
}
{
"storefrontName": "<<storefront_name>>",
"data": {
"type": "CREATE_SESSION",
"flavor": "REST",
"config": {
"url": "https://commerce-functions.yalochat.dev/v1/prefill",
"method": "POST",
"authMethod": "BASIC",
"token": "",
"body": {
"type": "suggestedOrder"
}
},
"executionTime": "AFTER"
}
}
Adding the pre-fill cart on LUA
đ You can see this implementations in prefillCart activity in yalo-commerce-product-prefill flow
Configuration based on the last order (flow studio)
-- staging environment "https://commerce-functions.yalochat.dev/v1"
functionsUrl = Profile.get('storefrontFunctionUrl')
url = functionsUrl.."/prefill"
commerceSessionObj = JSON.decode(Context.get('commerceSession'))
-- quick fix to make it work as the addon
commerceSessionObj._id = commerceSessionObj.id
artifacts = {
storefrontName = Profile.get('storefrontName'),
-- this session needs _id, customerUid or it will return 500
session = commerceSessionObj
}
inside = {
type = "lastOrder",
}
body = {
body = inside,
artifacts = artifacts
}
headers = {
["content-type"] = "application/json"
}
response = HTTP.post(url, body, headers)
if response.status == 200 then
Template.text("We already prefill your cart")
Workflow.branch(34)
else
Template.text("We couldn't get your last order")
Workflow.branch(62)
end
Configuration based on recommendations (flow studio)
-- staging environment "https://commerce-functions.yalochat.dev/v1"
functionsUrl = Profile.get('storefrontFunctionUrl')
url = functionsUrl.."/prefill"
commerceSessionObj = JSON.decode(Context.get('commerceSession'))
commerceSessionObj._id = commerceSessionObj.id
artifacts = {
storefrontName = Profile.get('storefrontName'),
-- this session needs _id, customerUid, workflow { name, channel, channelUid, userUid }, configuration { workflow } or it will return 500
session = commerceSessionObj
}
inside = {
type = "suggestedOrder",
}
body = {
body = inside,
artifacts = artifacts
}
headers = {
["content-type"] = "application/json"
}
response = HTTP.post(url, body, headers)
if response.status == 200 then
Template.text("We already prefill your cart")
Workflow.branch(34)
else
Template.text("We couldn't get your suggested order")
Workflow.branch(62)
end
Configuration based on fixed items (flow studio)
-- staging environment "https://storefront-user.yalochat.dev/v3/user/storefronts"
storefrontName = Profile.get('storefrontName')
userUrl = Profile.get('storefrontUserUrl')
commerceSessionObj = JSON.decode(Context.get('commerceSession'))
commerceSession = commerceSessionObj.id
headers = {
["content-type"] = "application/json"
}
-- prefilling 3 items of sku 10133, you can prefill n items and n skus
createSessionPayload = {
query = 'mutation UpdateStorefront($storefrontName: String!, $sessionUid: ID!, $items: [CartProductInput]) { prefillCart(storefrontName: $storefrontName, sessionUid: $sessionUid, items: $items) { id }}',
variables = string.format('{ "storefrontName": "%s", "sessionUid": "%s", "items": [{"sku": "%s", "quantity": %d }]}', storefrontName, commerceSession, "10133", 3)
}
-- Prefill cart
getClientResponse = HTTP.post(userUrl, createSessionPayload, headers)
if getClientResponse.status == 200 then
if getClientResponse.data["errors"] == null then
Template.text("We already prefill your cart")
Workflow.branch(34)
else
Template.text("We couldn't prefill your cart")
Workflow.branch(62)
end
else
Template.text("We couldn't prefill your cart")
Workflow.branch(62)
end
Creating a session (user workspace)
Sessions should be created including the workflow
property:
mutation CreateSession(
$createSessionStorefrontName: String!
$createSessionData: SessionInput!
) {
createSession(
storefrontName: $createSessionStorefrontName
data: $createSessionData
) {
id
}
}
{
"createSessionStorefrontName": "<<storefront-name>>",
"createSessionData": {
"code": "<<customer-phone-number",
"validateBy": "phoneNumber",
"validate": true,
"workflow": {
"name": "<<workflow-name>>",
"userUid": "<<users-phone-number>>"
}
}
}
Once the session is created, a cart will be create as well. If there are orders and the pre-fill is of type lastOrder
, the cart will be pre-filled with the products of that order; if it is of type suggestedOrder
, it will call an endpoint to get the product recommendations for that user and pre-fill the cart with those products.
If there are no orders or no recommendations, the cart will remain empty.
If there are products in the last order or in the recommendations that are out of stock or have been removed (inactive), they won't be added to the cart and won't throw any errors but you can see them in the warnings
:
query Cart($storefrontName: String!, $sessionUid: ID!) {
cart(storefrontName: $storefrontName, sessionUid: $sessionUid) {
id
items {
sku
quantity
price
}
warnings
}
}
{
"storefrontName": "<<storefront-name>>",
"sessionUid": "<<session-id>>"
}
Using the Pre-fill Cart Function without an Add-On
When you use the pre-fill cart add-on in a storefront, the configuration is easier but you lose flexibility, as the add-on will of a fixed type (lastOrder
or suggestedOrder
) and will be applied to all customers of that Flow.
To have more flexibility, you can call the pre-fill cart function directly, so you can choose when and how to call it.
Disabling your add-on
In case you already have a pre-fill cart add-on in your storefront, you can simply disable it using this mutation in the admin workspace:
mutation UpdateAddOn($storefrontName: String!, $updateAddOnId: ID!, $data: AddOnInputUpdate!) {
updateAddOn(storefrontName: $storefrontName, id: $updateAddOnId, data: $data) {
id
}
}
{
"storefrontName": "_STOREFRONT_NAME_",
"updateAddOnId": "_ADD_ON_ID_",
"data": {
"type": "CREATE_SESSION",
"flavor": "REST",
"config": {
"url": "https://commerce-functions.yalochat.dev/v1/prefill",
"method": "POST",
"authMethod": "BASIC",
"token": "",
"body": {
"type": "suggestedOrder"
}
},
"status": "DISABLED"
}
}
Calling the pre-fill cart function directly
Whether you're using the lastOrder
or the suggestedOrder
option, the only thing that changes in the payload is that, the body.type
property.
Here's an example of a minimal payload:
{
"artifacts": {
"storefrontName": "_STOREFRONT_NAME_",
"session": {
"_id": "_SESSION_ID_",
"customerUid": "_CUSTOMER_ID_",
"workflow": {
"channelUid": "_WORKFLOW_CHANNEL_ID_",
"userUid": "_USERS_PHONE_NUMBER_",
"name": "_WORKFLOW_NAME_"
},
"configuration": {
"workflow": {
"_WORKFLOW_NAME_": {
"name": "_WORKFLOW_NAME_"
}
}
}
}
},
"body": {
"type": "suggestedOrder" // CAN ALSO BE lastOrder
}
}
Calling the pre-fill cart function with Lua in FlowBuilder
Here's an example of how to call the function in Lua, to be used within your Flow in FlowBuilder:
-- STEP 1: create the session
-- this also could be 'code' when validating by a customer's document instead
validateBy = 'phoneNumber'
userId = tostring(Context.get('userId'))
commerceSession = Commerce.sessionCreate(validateBy, userId)
Context.set('commerceSession', commerceSession)
if commerceSession.status == 'ok' then
Context.set('commerceSession', commerceSession.data)
Workflow.branch(SUCCESS_STEP_ID)
end
Workflow.branch(FAIL_STEP_ID)
-- STEP 2: call the pre-fill cart function
commerceSession = JSON.decode(Context.get("commerceSession"))
prefillCartFunctionUrl = "https://commerce-functions-develop.yalochat.dev/v1/prefill"
prefillType = "suggestedOrder" -- can also be "lastOrder"
payload = {
artifacts = {
storefrontName = "STORE_FRONT_NAME",
session = commerceSession
},
body = {
type = prefillType,
},
}
headers = {
["content-type"] = "application/json"
}
response = HTTP.post(prefillCartFunctionUrl, payload, headers)
if response.status == 200 then
Workflow.branch(SUCCESS_STEP_ID)
end
Workflow.branch(FAIL_STEP_ID)
Checking if there are pre-fill cart recommendations
To do that, we can call the ML endpoint directly:
In the Flow, we might want to check if there is a pre-fill cart recommendation for that user before trying to pre-fill their cart.
curl --request POST 'https://api-staging2.yalochat.com/v0/ml/features/v1/features/pre-filled-cart/predict' \
--header 'Authorization: Bearer <<BEARER_TOKEN>>' \
--header 'Content-Type: application/json' \
--data-raw '{
"botId": "<<WORKFLOW_NAME>>",
"userId": "<<USERS_PHONE_NUMBER>>"
}'
[
{
"value": {
"amount": PRODUCT_QUANTITY,
"productId": "PRODUCT_ID",
"sku": "PRODUCT_SKU"
},
"weight": PRODUCT_RECOMMENDATION_WEIGHT
}
]
You should expect an empty array if there are no recommendations for that combination of Flow name and user ID.
Checking for recommendations with Lua in FlowBuilder
Here's an example of how to check if there are recommendations in FlowBuilder:
preFillCartUrl = "https://api-staging2.yalochat.com/v0/ml/features/v1/features/pre-filled-cart/predict"
headers = {
["content-type"] = "application/json",
["Authorization"] = "Bearer <<BEARER_TOKEN>>"
}
getSuggestedCartPayload = {
botId = "FLOW_NAME",
userId = "USERS_ID"
}
response = HTTP.post(preFillCartUrl, getSuggestedCartPayload, headers)
if response.status ~= 200 then
Workflow.branch(FAIL_STEP_ID)
end
items = {}
size = 0
for _, value in pairs(response.data) do
item = {}
item["sku"] = value["value"]["sku"]
item["quantity"] = value["value"]["amount"]
table.insert(items, item)
size = size + 1
end
hasCartSuggestions = size > 0
Context.set("prefillCartItems", items)
Context.set("hasCartSuggestions", hasCartSuggestions)
if hasCartSuggestions then
Workflow.branch(SUCCESS_STEP_ID)
end
Workflow.branch(FAIL_STEP_ID)
Checking if the customer has an order
If you want to include the option to pre-fill the cart with the last order's products, you may want to check if the customer has orders.
At the moment, we'll have to use the admin workspace to do that:
curl --request POST 'https://storefront-admin.yalochat.dev/v3/admin/storefronts' \
--header 'Content-Type: application/json' \
--data-raw '{
"query": "query Customer($storefrontName: String!, $customerId: ID!) {customer(storefrontName: $storefrontName, id: $customerId) {orders {id}}}",
"variables": {
"storefrontName": "STOREFRONT_NAME,
"customerId": "CUSTOMER_ID"
}
}'
{
"data": {
"customer": {
"orders": [
{
"id": "62cd9fd199db6c5202aeebfa"
}
]
}
}
}
If the customer has no orders, you'll receive an empty array instead:
{
"data": {
"customer": {
"orders": []
}
}
}
Checking for a customer's orders with Lua in FlowBuilder
Here's an example of how to check if there are orders for a customer in FlowBuilder:
headlessAdminUrl = "https://storefront-admin.yalochat.dev/v3/admin/storefronts"
headers = {
["content-type"] = "application/json",
}
getCustomerOrdersPayload = {
query = "query Customer($storefrontName: String!, $customerId: ID!) {customer(storefrontName: $storefrontName, id: $customerId) {orders {id}}}",
variables = {
storefrontName = "STOREFRONT_NAME",
customerId = "CUSTOMER_ID"
}
}
response = HTTP.post(headlessAdminUrl, getCustomerOrdersPayload, headers)
responseData = response.data.data
responseError = response.data.errors
if response.status == 200 and responseError == nil then
if tostring(responseData.customer) == 'null' then
Workflow.branch(CUSTOMER_NOT_FOUND_STEP_ID)
end
if #responseData.customer.orders > 0 then
Workflow.branch(HAS_ORDERS_STEP_ID)
end
Workflow.branch(HAS_NO_ORDERS_STEP_ID)
end
Workflow.branch(ERROR_GET_CUSTOMER_STEP_ID)
Updated over 1 year ago