Skip to content

Commit aaf29b5

Browse files
authored
Merge pull request #11 from maze-consulting/feature/KSCU-7_cart-rebuilding-link
Feature/kscu 7 cart rebuilding link
2 parents b996886 + 11c23bb commit aaf29b5

5 files changed

Lines changed: 270 additions & 1 deletion

File tree

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
'use strict';
2+
3+
/* Script Modules */
4+
var app = require('*/cartridge/scripts/app');
5+
var guard = require('*/cartridge/scripts/guard');
6+
var cartModel = require('*/cartridge/scripts/models/CartModel');
7+
var recreateHelpers = require('*/cartridge/scripts/recreateCartHelpers');
8+
var res = require("*/cartridge/scripts/util/Response");
9+
10+
/* API Includes */
11+
var StringUtils = require('dw/util/StringUtils');
12+
var URLUtils = require('dw/web/URLUtils');
13+
14+
15+
/**
16+
* KlaviyoRecreate-Cart : The KlaviyoRecreate-Cart route rebuilds a cart page based on a query containing an ENCODED array of objects with product IDs, product quanty, the product's selected options within URL / endpoint.
17+
* A DECODED query would be structured as: <baseURL>/Cart-Recreate?items=[ {"productID": ProdID, "quantity": QTY, "options": [ {lineItemText, optionID, optionValueID} ]} ] *
18+
* @param {querystringparameter} - items - JSON containing product Ids, qty, options
19+
* @param {renders} - isml via the Cart-Show controller
20+
* @param {serverfunction} - Get
21+
*/
22+
function cart() {
23+
try {
24+
var cart = app.getModel('Cart').goc();
25+
var items = request.httpParameterMap.items ? JSON.parse(StringUtils.decodeBase64(request.httpParameterMap.items)) : null;
26+
} catch (error) {
27+
var test = error;
28+
res.renderJSON({
29+
success: false,
30+
error: true,
31+
errorMessage: `ERROR - ${error.message}. Please check encoded URL Object and the Cart Model reference.`
32+
});
33+
return;
34+
}
35+
36+
if (cart && items.length) {
37+
var renderInfo = recreateHelpers.addProductToCart(items, cart)
38+
39+
if (renderInfo.error) {
40+
res.renderJSON({
41+
success: renderInfo.success,
42+
error: renderInfo.error,
43+
errorMessage: renderInfo.errorMessage
44+
})
45+
return;
46+
}
47+
48+
if (renderInfo.source === 'giftregistry') {
49+
app.getView().render('account/giftregistry/refreshgiftregistry');
50+
} else if (renderInfo.template === 'checkout/cart/cart') {
51+
app.getView('Cart', {
52+
Basket: cart
53+
}).render(renderInfo.template);
54+
} else if (renderInfo.format === 'ajax') {
55+
app.getView('Cart', {
56+
cart: cart,
57+
BonusDiscountLineItem: renderInfo.BonusDiscountLineItem
58+
}).render(renderInfo.template);
59+
} else {
60+
response.redirect(URLUtils.url('Cart-Show'));
61+
}
62+
}
63+
64+
if (!cart) {
65+
res.renderJSON({
66+
success: false,
67+
error: true,
68+
errorMessage: `The Cart is: ${cart}. Please check the Cart obj to ensure there is a value.`
69+
})
70+
return;
71+
}
72+
}
73+
74+
75+
/*
76+
* Module exports
77+
*/
78+
exports.Cart = guard.ensure(['get'], cart);

cartridges/int_klaviyo_core/cartridge/scripts/klaviyo/eventData/startedCheckout.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ var ProductMgr = require('dw/catalog/ProductMgr');
44
var URLUtils = require('dw/web/URLUtils');
55
var klaviyoUtils = require('*/cartridge/scripts/klaviyo/utils');
66
var KLImageSize = klaviyoUtils.KLImageSize;
7+
var StringUtils = require('dw/util/StringUtils');
78

89
// prepares data for "Started Checkout" event
910
function getData(currentBasket) {
@@ -12,6 +13,7 @@ function getData(currentBasket) {
1213

1314
var data = {};
1415
var basketItems = currentBasket.getProductLineItems().toArray();
16+
var reconstructCartItems = [];
1517
// Create some top-level event data
1618
//data.event = EVENT_NAMES['startedCheckout'];
1719
data['Basket Gross Price'] = currentBasket.getTotalGrossPrice().value;
@@ -22,11 +24,20 @@ function getData(currentBasket) {
2224
data.Categories = [];
2325
data.Items = [];
2426
data.$email = currentBasket.customerEmail;
27+
data.cartRebuildingLink = URLUtils.abs('KlaviyoRecreate-Cart').toString() + `?items=${reconstructCartItems}`;
2528

2629
for (var itemIndex = 0; itemIndex < basketItems.length; itemIndex++) {
2730
var lineItem = basketItems[itemIndex];
2831
var currentProductID = lineItem.productID;
2932
var basketProduct = ProductMgr.getProduct(currentProductID);
33+
var quantity = lineItem.quantityValue;
34+
var options = [];
35+
if (lineItem && lineItem.optionProductLineItems) {
36+
for (let i = 0; i < lineItem.optionProductLineItems.length; i++){
37+
let currOption = lineItem.optionProductLineItems[i];
38+
options.push({optionID: lineItem.optionProductLineItems[i].optionID, optionValueID: lineItem.optionProductLineItems[i].optionValueID, lineItemText: lineItem.optionProductLineItems[i].lineItemText})
39+
}
40+
}
3041

3142
if (currentProductID != null && !empty(basketProduct) && basketProduct.getPriceModel().getPrice().value > 0) {
3243
var productObj = prepareProductObj( lineItem, basketProduct, currentProductID );
@@ -35,9 +46,12 @@ function getData(currentBasket) {
3546
data.line_items.push(productObj);
3647
data.Categories.push.apply(data.Categories, data.line_items[itemIndex].Categories);
3748
data.Items.push(data.line_items[itemIndex]['Product Name']);
49+
50+
reconstructCartItems.push({ productID: currentProductID, quantity, options });
3851
}
3952
}
4053

54+
data.cartRebuildingLink += StringUtils.encodeBase64(JSON.stringify(reconstructCartItems));
4155
return data;
4256
}
4357

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
'use strict';
2+
3+
/* Script Modules */
4+
var app = require('*/cartridge/scripts/app');
5+
6+
function addProductToCart(decodedItems, cartObj) {
7+
var productList = decodedItems.length ? decodedItems : null;
8+
var cart = cartObj;
9+
10+
if (cart.object.allProductLineItems) {
11+
for (let i = 0; i < cart.object.allProductLineItems.length; i++) {
12+
let currItem = cart.object.allProductLineItems[i];
13+
cart.removeProductLineItem(cart.object.allProductLineItems[i]);
14+
}
15+
}
16+
17+
var params = request.httpParameterMap;
18+
var format = params.hasOwnProperty('format') && params.format.stringValue ? params.format.stringValue.toLowerCase() : '';
19+
var newBonusDiscountLineItem;
20+
var Product = app.getModel('Product');
21+
var productOptionModel;
22+
var productToAdd;
23+
var template = 'checkout/cart/minicart';
24+
25+
if (params.source && params.source.stringValue === 'wishlist' && params.cartAction && params.cartAction.stringValue === 'update') {
26+
app.getController('Wishlist').ReplaceProductListItem();
27+
return;
28+
} else {
29+
var previousBonusDiscountLineItems = cart.getBonusDiscountLineItems();
30+
for (let i = 0; i < productList.length; i++) {
31+
try {
32+
productToAdd = Product.get(productList[i].productID);
33+
} catch (error) {
34+
return {
35+
success: false,
36+
error: true,
37+
errorMessage: `ERROR - Please check the encoded obj for any unexpected chars or syntax issues. ${error.message}`
38+
};
39+
}
40+
productOptionModel = productToAdd ? _updateOptions(productList[i], productToAdd.object) : null;
41+
cart.addProductItem(productToAdd.object, productList[i].quantity, productOptionModel);
42+
43+
newBonusDiscountLineItem = cart.getNewBonusDiscountLineItem(previousBonusDiscountLineItems);
44+
}
45+
}
46+
47+
return {
48+
format: format,
49+
template: template,
50+
BonusDiscountLineItem: newBonusDiscountLineItem
51+
};
52+
};
53+
54+
55+
function _updateOptions(params, product) {
56+
var optionModel = product.getOptionModel();
57+
58+
for (var i = 0; i < params.options.length; i++) {
59+
var optionID = params.options[i].optionID;
60+
var optionValueID = params.options[i].optionValueID;
61+
62+
if (optionValueID) {
63+
var option = optionModel.getOption(optionID);
64+
65+
if (option && optionValueID) {
66+
var optionValue = optionModel.getOptionValue(option, optionValueID);
67+
if (optionValue) {
68+
optionModel.setSelectedOptionValue(option, optionValue);
69+
}
70+
}
71+
}
72+
}
73+
return optionModel;
74+
}
75+
76+
/*
77+
* Module exports
78+
*/
79+
module.exports = {
80+
addProductToCart : addProductToCart,
81+
}

cartridges/int_klaviyo_sfra/cartridge/controllers/Cart.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,4 @@ server.append('AddProduct', function (req, res, next) {
3838
});
3939

4040

41-
module.exports = server.exports();
41+
module.exports = server.exports();
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
'use strict';
2+
3+
var server = require('server');
4+
5+
/* Script Modules */
6+
var shippingHelper = require('*/cartridge/scripts/checkout/shippingHelpers');
7+
var COHelpers = require('*/cartridge/scripts/checkout/checkoutHelpers');
8+
var collections = require('*/cartridge/scripts/util/collections');
9+
var cartHelpers = require('*/cartridge/scripts/cart/cartHelpers');
10+
11+
/* Models */
12+
var CartModel = require('*/cartridge/models/cart');
13+
14+
/* API Includes */
15+
var BasketMgr = require('dw/order/BasketMgr');
16+
var ProductMgr = require('dw/catalog/ProductMgr');
17+
var PromotionMgr = require('dw/campaign/PromotionMgr');
18+
var StringUtils = require('dw/util/StringUtils');
19+
var Transaction = require('dw/system/Transaction');
20+
var URLUtils = require('dw/web/URLUtils');
21+
22+
23+
/**
24+
* KlaviyoRecreate-Cart : The KlaviyoRecreate-Cart route rebuilds a cart page based on a query containing an ENCODED array of objects with product IDs, product quanty, the product's selected options within URL / endpoint.
25+
* A DECODED query would be structured as: <baseURL>/Cart-Recreate?items=[ {"productID": ProdID, "quantity": QTY, "options": [ {lineItemText, optionID, optionValueID} ]} ]
26+
* @function
27+
* @memberof Cart
28+
* @param {querystringparameter} - items - JSON containing product Ids, qty, childProducts, options
29+
* @param {renders} - isml
30+
* @param {serverfunction} - get
31+
*/
32+
server.get('Cart', function (req, res, next) {
33+
var currentBasket = BasketMgr.getCurrentOrNewBasket();
34+
try {
35+
var items = req.querystring.items ? JSON.parse(StringUtils.decodeBase64(req.querystring.items)) : null;
36+
} catch (error) {
37+
res.setStatusCode(500);
38+
res.json({
39+
error: true,
40+
errorMessage: `ERROR - ${error.message}. Please check the encoded obj for any unexpected chars or syntax issues.`,
41+
});
42+
return next();
43+
}
44+
45+
if (!currentBasket) {
46+
res.setStatusCode(500);
47+
res.json({
48+
error: true,
49+
errorMessage: `ERROR - Current Basket is: ${currentBasket}. Please check the Current Basket and try again.`,
50+
redirectUrl: URLUtils.url('Cart-Show').toString()
51+
});
52+
return next();
53+
};
54+
55+
// Clean the basket to prevent product duplication on page refresh
56+
if (currentBasket && currentBasket.productQuantityTotal > 0) {
57+
for (let i = 0; i < currentBasket.productLineItems.length; i++) {
58+
let lengthAtIteration = currentBasket.productLineItems.length;
59+
var shipmentToRemove = currentBasket.productLineItems[i].shipment;
60+
currentBasket.removeProductLineItem(currentBasket.productLineItems[i]);
61+
currentBasket.updateTotals();
62+
if (currentBasket.productLineItems.length < lengthAtIteration) {
63+
i--;
64+
}
65+
66+
if (shipmentToRemove.productLineItems.length && !shipmentToRemove.default) {
67+
currentBasket.removeShipment(shipmentToRemove);
68+
}
69+
PromotionMgr.applyDiscounts(currentBasket);
70+
}
71+
}
72+
73+
Transaction.wrap(function () {
74+
if (items && items.length) {
75+
for (let i = 0; i < items.length; i++) {
76+
var productToAdd = ProductMgr.getProduct(items[i].productID);
77+
var childProducts = productToAdd.bundledProducts ? collections.map(productToAdd.bundledProducts, function (product) { return { pid: product.ID, quantity: null } }) : [];
78+
var options = [];
79+
items[i].options.forEach(optionObj => {
80+
options.push({ lineItemText: optionObj.lineItemText, optionId: optionObj.optionID, selectedValueId: optionObj.optionValueID});
81+
})
82+
83+
var shipments = Array.from(currentBasket.shipments);
84+
shippingHelper.ensureShipmentHasMethod(shipments[0]);
85+
cartHelpers.addProductToCart(currentBasket, items[i].productID, items[i].quantity, childProducts, options);
86+
}
87+
COHelpers.recalculateBasket(currentBasket);
88+
}
89+
90+
var basketModel = new CartModel(currentBasket);
91+
res.render('cart/cart', basketModel);
92+
})
93+
next();
94+
});
95+
96+
module.exports = server.exports();

0 commit comments

Comments
 (0)