Skip to content

Instantly share code, notes, and snippets.

@hnestmann
Created December 2, 2020 07:52
Show Gist options
  • Save hnestmann/1996ef390f21b444595637f88e5c1112 to your computer and use it in GitHub Desktop.
Save hnestmann/1996ef390f21b444595637f88e5c1112 to your computer and use it in GitHub Desktop.
add-to-cart.js
const { appendFile } = require("fs");
const fetch = require("node-fetch");
const fs = require('fs');
const params = JSON.parse(fs.readFileSync('./config.json'));
/* Example
{
"accountManager": {
"scope": "SALESFORCE_COMMERCE_API:xxxx_xxx sfcc.yy",
"clientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"secret": "xXxXxxx"
},
"shopperProductSearchApi": {
"siteId": "xxx",
"searchTerm": "shoe",
"shortCode": "xxxx",
"organizationId": "f_ecom_xxx"
}
}
*/
const startTimeStamp = (new Date()).toISOString().replace(/[^a-zA-Z0-9]/g, "");
/**
* Logs a message to a file and optionally to console
*/
function log(message) {
if (!fs.existsSync('./logs/')) {
fs.mkdirSync('./logs/', 0744);
}
const logFileName = `./logs/${startTimeStamp}.log`
fs.appendFileSync(logFileName, message + '\n');
if (params.execution.verbose) {
console.info((new Date()).toISOString() + ': ' + message)
}
}
async function searchProducts(searchTerm, start, limit) {
log(`searching ${limit} products from point ${start}`);
const url = `https://${params.shopperProductSearchApi.shortCode}.api.commercecloud.salesforce.com/search/shopper-search/v1/organizations/${params.shopperProductSearchApi.organizationId}/product-search?q=${searchTerm}&siteId=${params.shopperProductSearchApi.siteId}`;
var token = await getAuthenticationToken();
const response = await fetch(url, {
method: 'get',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
});
const searchResponseDocument = await response.json();
return searchResponseDocument;
}
async function createCart() {
const url = `https://${params.shopperProductSearchApi.shortCode}.api.commercecloud.salesforce.com/checkout/shopper-baskets/v1/organizations/${params.shopperProductSearchApi.organizationId}/baskets?siteId=${params.shopperProductSearchApi.siteId}`;
var token = await getAuthenticationToken();
const response = await fetch(url, {
method: 'post',
body: '{}',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
});
const basketResponse = await response.json();
return basketResponse;
}
async function addToCart(basketId, pid) {
const url = `https://${params.shopperProductSearchApi.shortCode}.api.commercecloud.salesforce.com/checkout/shopper-baskets/v1/organizations/${params.shopperProductSearchApi.organizationId}/baskets/${basketId}/items?siteId=${params.shopperProductSearchApi.siteId}`;
var request = [
{
"productId": pid,
"quantity": 1
}
]
var token = await getAuthenticationToken();
const response = await fetch(url, {
method: 'post',
body: JSON.stringify(request),
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
});
const basketResponse = await response.json();
return basketResponse;
}
async function changePidInCart(basketId, itemId, pid) {
const url = `https://${params.shopperProductSearchApi.shortCode}.api.commercecloud.salesforce.com/checkout/shopper-baskets/v1/organizations/${params.shopperProductSearchApi.organizationId}/baskets/${basketId}/items/${itemId}?siteId=${params.shopperProductSearchApi.siteId}`;
var request = {
"productId": pid,
"quantity": 1
}
var token = await getAuthenticationToken();
const response = await fetch(url, {
method: 'patch',
body: JSON.stringify(request),
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
});
const basketResponse = await response.json();
return basketResponse;
}
var expiration = new Date(0);
var token;
/**
* Gets the authentication token and generates a new one if timed out
*/
async function getAuthenticationToken() {
const url = `https://${params.shopperProductSearchApi.shortCode}.api.commercecloud.salesforce.com/customer/shopper-customers/v1/organizations/${params.shopperProductSearchApi.organizationId}/customers/actions/login?siteId=${params.shopperProductSearchApi.siteId}&clientId=${params.accountManager.clientId}`;
if (expiration.getTime() < Date.now() || !token) {
log('fetching new jwt')
const searchParams = JSON.stringify({
"type": "guest"
})
const authString = `${params.accountManager.clientId}:${params.accountManager.secret}`;
const buff = Buffer.from(authString, 'utf-8');
const b64AuthString = buff.toString('base64');
const response = await fetch(url, {
method: 'post',
body: searchParams,
headers: {
'Content-Type': 'application/json',
'Authorization': `Basic ${b64AuthString}`
},
});
const json = await response.json();
// the locally held token will expire a minute before the actual
expiration = new Date(Date.now() + ((30 * 60) - 60) * 1000);
token = response.headers.get('authorization').replace('Bearer ', '');
}
return token;
};
/**
* The main 'controller' - externalized as async function
*/
async function mainAsync() {
var productsInitial = await searchProducts(params.shopperProductSearchApi.searchTerm, 0, 2);
log(`found ${JSON.stringify(productsInitial.total)} products`);
var pages = Math.ceil(productsInitial.total / 25);
var pid1 = productsInitial.hits[0].representedProducts[0].id;
var pid2 = productsInitial.hits[1].representedProducts[0].id;
var basketResponse = await createCart();
var basketId = basketResponse.basketId;
var addToCartResponse = await addToCart(basketId, pid1);
log(`added ${pid1} - basketTotal ${addToCartResponse.productTotal}`)
var itemId = addToCartResponse.productItems.pop().itemId;
var changePidResonse = await changePidInCart(basketId, itemId, pid2)
log(`changed to ${changePidResonse.productItems.pop().productId} - basketTotal ${changePidResonse.productTotal}`)
}
mainAsync();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment