Skip to content

Instantly share code, notes, and snippets.

@niveshsaharan
Created October 16, 2024 17:41
Show Gist options
  • Save niveshsaharan/e634a1aca7cf8e3519f454671b52f290 to your computer and use it in GitHub Desktop.
Save niveshsaharan/e634a1aca7cf8e3519f454671b52f290 to your computer and use it in GitHub Desktop.
query RunInput {
presentmentCurrencyRate
cart {
lines {
id
check_bundle: attribute(key: "_bundle"){
value
}
merchandise {
__typename
... on ProductVariant {
id
product {
id
title
bundle_discount_percentage: metafield(namespace: "custom",key: "bundle_discount_percentage"){
value
}
bundle_products: metafield(namespace: "custom",key: "bundle_products"){
value
}
}
}
}
quantity
}
}
}
// @ts-check
/**
* @typedef {import("../generated/api").RunInput} RunInput
* @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult
*/
/**
* @type {FunctionRunResult}
*/
const NO_CHANGES = {
operations: [],
};
/**
* @param {RunInput} input
* @returns {FunctionRunResult}
*/
export function run(input) {
const bundles = new Map();
let nonBundles = new Map();
// let productLineQuantity = new Map();
const productsLines = new Map();
const finalBundles = [];
const productVariants = {}
for (const line of input.cart.lines) {
const {id, merchandise, quantity} = line;
// Only check for line items having attribute
if ((line.check_bundle?.value || "").toLowerCase() === 'yes' || (line.checkBundle?.value || "").toLowerCase() === 'yes') {
const {product} = merchandise;
if (product?.bundle_products?.value || product?.bundleProducts?.value) {
const eligibleProducts = product?.bundle_products?.value ? JSON.parse(product.bundle_products.value) : JSON.parse(product.bundleProducts.value);
if (eligibleProducts.length > 0) {
bundles.set(id, {
parentVariantId: merchandise.id,
price: {
percentageDecrease: {
value: parseFloat(product.bundle_discount_percentage?.value || product.bundleDiscountPercentage?.value || 0)
}
},
title: product.title,
quantity,
products: eligibleProducts,
});
}
}
nonBundles.set(id, {quantity, productId: product.id, variantId: merchandise.id, id});
productsLines.set(product.id, [...(productsLines.get(product.id) || []), id]);
productVariants[line.merchandise.product.id] = productVariants[line.merchandise.product.id] || {}
productVariants[line.merchandise.product.id][line.merchandise.id] = productVariants[line.merchandise.product.id][line.merchandise.id] || 0;
productVariants[line.merchandise.product.id][line.merchandise.id] += line.quantity;
}
}
if (bundles.size === 0 || nonBundles.size === 0) {
return NO_CHANGES;
}
function makeBundles() {
let recheck = false;
for (const [bundleLineId, bundle] of bundles) {
let bundleEligibleQuantity = bundle.quantity;
if (bundleEligibleQuantity > 0) {
const bundleEligibleQuantityOriginal = bundle.quantity;
// eslint-disable-next-line no-loop-func
const isValid = bundle.products.every(productId => {
if (!productVariants[productId]) {
return false
}
return Object.keys(productVariants[productId]).some(variantId => {
const availableQuantity = productVariants[productId][variantId] || 0;
if (availableQuantity > 0) {
if (availableQuantity < bundleEligibleQuantity) {
bundleEligibleQuantity = availableQuantity;
}
return true;
}
return false;
})
});
if (isValid) {
const _nonBundles = new Map([...nonBundles]);
const cartLines = bundle.products.map(productId => {
const lineId = productsLines.get(productId).find(line_id => {
const nonBundle = _nonBundles.get(line_id);
if (nonBundle && nonBundle.quantity >= bundleEligibleQuantity) {
nonBundle.quantity -= bundleEligibleQuantity;
return true;
}
return false;
});
return {cartLineId: lineId, quantity: bundleEligibleQuantity};
}).filter(item => !!item.cartLineId);
if (cartLines.length === bundle.products.length) {
cartLines.push({cartLineId: bundleLineId, quantity: bundleEligibleQuantity});
nonBundles = _nonBundles;
bundle.quantity -= bundleEligibleQuantity;
finalBundles.push({
merge: {
parentVariantId: bundle.parentVariantId,
price: bundle.price,
title: bundle.title,
cartLines,
}
});
}
if (bundle.quantity > 0 && bundle.quantity !== bundleEligibleQuantityOriginal) {
recheck = true;
}
}
}
}
if (recheck) {
makeBundles()
}
}
makeBundles();
return finalBundles.length > 0 ? {operations: finalBundles} : NO_CHANGES;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment