Hi everyone,
I’m building a Shopify Remix app for a volume discount feature and using GraphQL automatic discounts along with the Shopify Product Discount Function. I’m facing an issue where:
- When I create different discounts for two different products, only the last discounted product in the cart gets the discount applied.
- If I remove one product from the cart, the remaining product gets the correct discount applied as expected.
It seems like the discount function is not applying multiple discounts properly when different products with their own discounts are in the cart. I have set discountApplicationStrategy: DiscountApplicationStrategy.All, but the issue persists.
Has anyone faced a similar issue? How can I ensure that each eligible product gets its respective discount applied correctly?
Here’s my run.js file for reference:
// @TS -check
import { DiscountApplicationStrategy } from “../generated/api”;
/**
- @typedef {import(“../generated/api”).RunInput} RunInput
- @typedef {import(“../generated/api”).FunctionRunResult} FunctionRunResult
- @typedef {import(“../generated/api”).Target} Target
- @typedef {import(“../generated/api”).ProductVariant} ProductVariant
*/
/**
- @type {FunctionRunResult}
*/
const EMPTY_DISCOUNT = {
discountApplicationStrategy: DiscountApplicationStrategy.First,
discounts: ,
};
/**
- @param_1 {RunInput} input
- @returns {FunctionRunResult}
*/
export function run(input) {
// Parse configuration from metafield
let configuration;
try {
configuration = JSON.parse(input?.discountNode?.metafield?.value ?? “{}”);
} catch (error) {
console.error(“Error parsing configuration metafield:”, error);
return EMPTY_DISCOUNT;
}
if (!configuration.discountValues || !Array.isArray(configuration.discountValues)) {
return EMPTY_DISCOUNT;
}
// targets will be only products that are in configuration variants
const targets = input.cart.lines
.filter(line => {
const variant = line.merchandise;
// Ensure variants exists and is an array
if (!configuration.variants || !Array.isArray(configuration.variants)) {
console.error(“No variants defined in configuration.”);
return false;
}
return configuration.variants.some(v => v === variant.id);
})
.map(line => {
const variant = /** @type {ProductVariant} / (line.merchandise);
return /* @type {Target} */ ({
productVariant: {
id: variant.id
}
});
});
if (!targets.length) {
console.error(“No cart lines qualify for volume discount.”);
return EMPTY_DISCOUNT;
}
const discounts = ;
// Sort discount values by quantity in descending order
const sortedDiscountValues = configuration.discountValues.sort((a, b) => b.quantity - a.quantity);
for (const target of targets) {
const line = input.cart.lines.find(line => line.merchandise?.id === target?.productVariant?.id);
if (!line) continue;
const eligibleDiscount = sortedDiscountValues.find(discountValue => line.quantity >= discountValue.quantity);
for (const discountValue of sortedDiscountValues) {
if (line.quantity >= discountValue.quantity && eligibleDiscount.quantity > 0) {
// If line quantity is enough for this discount, create a discount for this line item
const discount = {
targets: [target],
message: eligibleDiscount.discount_message,
value: eligibleDiscount.discount_type === “Percentage”
? { percentage: { value: parseFloat(eligibleDiscount.discount_percent) } }
: { fixedAmount: { amount: parseFloat(eligibleDiscount.discount_fixed) } }
};
discounts.push(discount);
// Do not break the loop, continue checking the other line items
}
}
}
return {
discounts,
discountApplicationStrategy: DiscountApplicationStrategy.All
};
};