Discussing Shopify Functions development, deployment, and usage in Shopify apps.
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.
Solved! Go to the solution
This is an accepted solution.
Hi! Can you clarify what you are trying to achieve? Is it a fixed amount discount to apply to each quantity of the given product variant, or a fixed quantity that should be applied per line? If the former, take a look at the `appliesToEach` property of FixedAmount.
As for CartLineTarget not working - can you verify you're using API 2024-07 or newer? The error message makes me think you might be using 2024-04, which didn't include support for cart line targeting. I'm assuming that the cart line code you showed continues to build a complete FunctionRunResult that uses the targets array for a single discount proposal, right?
Cheers,
Jonathan
Experiencing the same issue.
This is an accepted solution.
Hi! Can you clarify what you are trying to achieve? Is it a fixed amount discount to apply to each quantity of the given product variant, or a fixed quantity that should be applied per line? If the former, take a look at the `appliesToEach` property of FixedAmount.
As for CartLineTarget not working - can you verify you're using API 2024-07 or newer? The error message makes me think you might be using 2024-04, which didn't include support for cart line targeting. I'm assuming that the cart line code you showed continues to build a complete FunctionRunResult that uses the targets array for a single discount proposal, right?
Cheers,
Jonathan
Thanks for your reply Jonathan. Ideally we'd like to target CartLines rather than productVariants because different lines of the same product variant might get a different discount amount depending on personalization selected.
I believe I was on 2024-07, and just switched to 2024-10 to test that with the same result. Can you confirm the correct procedure for switching the api version? I'm setting it within the app configuration in the Shopify Partners UI and in shopify.app.toml where I save and rerun 'shopify app dev' from the CLI.
😁Just realized I need to set in shopify.extension.toml, that has resolved the issue with targeting CartLines.
Happy to hear it! Cheers 🙂