We’re building a custom product discount extension with Shopify Functions. We’ve got some of the functionality working, but have noticed an unexpected outcome when the same product variant exists across multiple lines. We’re developing with the .js variant of the extension and are currently using api_version 2024-07 but have tested with 2024-04 as well.
run.graphql:
query RunInput {
cart {
lines {
id
cost {
amountPerQuantity {
amount
}
}
quantity
att1: attribute(key: "Stamp Style") {
value
}
att2: attribute(key: "Symbol") {
value
}
merchandise {
__typename
... on ProductVariant {
id
product {
id
metafield(key: "retail", namespace: "pricing",) {
type
value
}
}
}
}
}
}
discountNode {
metafield(
namespace: "$app:standard-pricing"
key: "function-configuration"
) {
value
}
}
}
run.js:
// -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
*/
/**
* {FunctionRunResult}
*/
const EMPTY_DISCOUNT = {
discountApplicationStrategy: DiscountApplicationStrategy.All,
discounts: [],
};
/**
* @param {RunInput} input
* @returns {FunctionRunResult}
*/
export function run(input) {
const discounts = input.cart.lines
.map(line => {
const variant = /** {ProductVariant} */ (line.merchandise);
const currentprice = parseFloat(line.cost.amountPerQuantity.amount);
const baseprice100 = parseFloat(variant.product.metafield?.value);
const baseprice = baseprice100 / 100;
const discountamount = (currentprice - baseprice) * line.quantity;
console.error(`Current Price: ${JSON.stringify(currentprice)}`);
console.error(`Base Price: ${JSON.stringify(baseprice)}`);
console.error(`Discount Amount: ${JSON.stringify(discountamount)}`);
return {
targets: [
{
productVariant: {
id: variant.id
}
}
],
value: {
fixedAmount: {
amount: discountamount
}
}
};
});
if (!discounts.length) {
console.error("No cart lines qualify for volume discount.");
return EMPTY_DISCOUNT;
}
return {
discounts,
discountApplicationStrategy: DiscountApplicationStrategy.All
};
};
This is the expected outcome:
But if the same variant exists on another line, the applied discount amount is split amongst the additional lines and therefore doesn’t fully apply to either line:
My first thought was to change the returned target to cartLine: { id: line.id } as specified in the ‘build discount function’ example documentation:
But that only generates the following error message and applies no discounts to any line:
[
{
"path": [
"discounts",
0,
"targets",
0
],
"explanation": "Expected one of valid values: productVariant. Got: cartLine"
},
{
"path": [
"discounts",
1,
"targets",
0
],
"explanation": "Expected one of valid values: productVariant. Got: cartLine"
},
{
"path": [
"discounts",
2,
"targets",
0
],
"explanation": "Expected one of valid values: productVariant. Got: cartLine"
}
]
Any insight or workarounds would be much appreciated.


