Our Partner & Developer boards on the community are moving to a brand new home: the .dev community forums! While you can still access past discussions here, for all your future app and storefront building questions, head over to the new forums.

Issue with Discount Function Tutorial

Solved

Issue with Discount Function Tutorial

vbjornsson
Shopify Partner
9 1 2

I've been trying to learn how to create a discount function using this tutorial: https://shopify.dev/docs/apps/build/discounts/experience/build-discounts-function

 

I've successfully installed the app in my development store, but when I try to test it I keep getting InvalidOutputError.

 

I feel like I've followed the tutorial correctly and copied the Javascript provided into run.js and I'm not sure what the issue is. Any ideas?

 

Here is the code for run.js from the tutorial:

 

 

// @TS-check
import { DiscountApplicationStrategy } from "../generated/api";

// Use JSDoc annotations for type safety
/**
* @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: [],
};

// The configured entrypoint for the 'purchase.product-discount.run' extension target
/**
* @param {RunInput} input
* @returns {FunctionRunResult}
*/
export function run(input) {
  const targets = input.cart.lines
  // Only include cart lines with a quantity of two or more
  .filter(line => line.quantity >= 2)
  .map(line => {
    return /** @type {Target} */ ({
      // Use the cart line ID to create a discount target
      cartLine: {
        id: line.id
      }
    });
  });

  if (!targets.length) {
    // You can use STDERR for debug logs in your function
    console.error("No cart lines qualify for volume discount.");
    return EMPTY_DISCOUNT;
  }

  // The @Shopify/shopify_function package applies JSON.stringify() to your function result
  // and writes it to STDOUT
  return {
    discounts: [
      {
        // Apply the discount to the collected targets
        targets: targets,
        // Define a percentage-based discount
        value: {
          percentage: {
            value: "10.0"
          }
        }
      }
    ],
    discountApplicationStrategy: DiscountApplicationStrategy.First
  };
};

 

 

 

Here is run.graphql:

 

 

query RunInput {
  cart {
    lines {
      id
      quantity
    }
  }
}

 

 

 

 

Here's information from a run log:

 

Input (STDIN)

 

 

{
  "cart": {
    "lines": [
      {
        "id": "gid://shopify/CartLine/0",
        "quantity": 2
      }
    ]
  }
}

 

 

 

Output (STDOUT)

 

 

{
  "discounts": [
    {
      "targets": [
        {
          "cartLine": {
            "id": "gid://shopify/CartLine/0"
          }
        }
      ],
      "value": {
        "percentage": {
          "value": "10.0"
        }
      }
    }
  ],
  "discountApplicationStrategy": "FIRST"
}

 

 

 

Error message

 

 

[
  {
    "path": [
      "discounts",
      0,
      "targets",
      0
    ],
    "explanation": "Expected one of valid values: productVariant. Got: cartLine"
  }
]

 

 

 

Accepted Solutions (2)

SomeUsernameHe
Shopify Partner
522 58 115

This is an accepted solution.

Try changing 

 

	cartLine: {
        id: line.id
      }

to

 productVariant: {
          id: variant.id
        }

 

Have I helped? Consider putting coffee in my mouth!
Buy Me a Coffee

View solution in original post

vbjornsson
Shopify Partner
9 1 2

This is an accepted solution.

Thanks Liam. What functions example did you change on your end?

 

After seeing @SomeUsernameHe comment, I looked up the tutorial again and saw there was a link to a git repository and the run.js code on there was written a little differently than the tutorial I had found on the shopify.dev site: https://github.com/Shopify/function-examples/blob/main/sample-apps/discounts/extensions/product-disc...

 

Vs the tutorial I was going by: https://shopify.dev/docs/apps/build/discounts/experience/build-discounts-function

 

The code on Git had implemented user configuration but I just took what I needed to modify my run.graphql and run.js files and this what I ended up with (below). After running "shopify app function typegen" command and running the app again it worked!

 

vbjornsson_0-1720127051832.png

 

 

Here is my modified run.js:

// @ts-check
import { DiscountApplicationStrategy } from "../generated/api";

// Use JSDoc annotations for type safety
/**
* @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: [],
};

// The configured entrypoint for the 'purchase.product-discount.run' extension target
/**
* @param {RunInput} input
* @returns {FunctionRunResult}
*/
export function run(input) {
  const targets = input.cart.lines
    // Only include cart lines with a quantity of two or more
    .filter(line => line.quantity >= 2 &&
      line.merchandise.__typename == "ProductVariant")
    .map(line => {
      const variant = /** @type {ProductVariant} */ (line.merchandise);
      return /** @type {Target} */ ({
        // Use the cart line ID to create a discount target
        productVariant: {
          id: variant.id
        }
      });
    });

  if (!targets.length) {
    // You can use STDERR for debug logs in your function
    console.error("No cart lines qualify for volume discount.");
    return EMPTY_DISCOUNT;
  }

  // The @shopify/shopify_function package applies JSON.stringify() to your function result
  // and writes it to STDOUT
  return {
    discounts: [
      {
        // Apply the discount to the collected targets
        targets: targets,
        // Define a percentage-based discount
        value: {
          percentage: {
            value: 10.0
          }
        },
        message: "10% OFF"
      }
    ],
    discountApplicationStrategy: DiscountApplicationStrategy.First
  };
};

 

And my modified run.graphql:

query RunInput {
  cart {
    lines {
      quantity
      merchandise {
        __typename
        ... on ProductVariant {
          id
        }
      }
    }
  }
}

 

View solution in original post

Replies 5 (5)

Liam
Community Manager
3108 344 911

Hi Vbjornsson,

 

This could be due to the version you're calling in your toml file. You should update your toml file to make sure you're using 2024-07 and it should work then. Let me know if you're still seeing issues. 

Liam | Developer Advocate @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

vbjornsson
Shopify Partner
9 1 2

Thanks for the reply Liam, but it looks like I already have that api version set: 

 

Screenshot 2024-07-03 152115.jpg

Liam
Community Manager
3108 344 911

Hi again Vbjornsson,

 

We also updated the functions example on our side so it should work with 2024-07 now. 

Liam | Developer Advocate @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

vbjornsson
Shopify Partner
9 1 2

This is an accepted solution.

Thanks Liam. What functions example did you change on your end?

 

After seeing @SomeUsernameHe comment, I looked up the tutorial again and saw there was a link to a git repository and the run.js code on there was written a little differently than the tutorial I had found on the shopify.dev site: https://github.com/Shopify/function-examples/blob/main/sample-apps/discounts/extensions/product-disc...

 

Vs the tutorial I was going by: https://shopify.dev/docs/apps/build/discounts/experience/build-discounts-function

 

The code on Git had implemented user configuration but I just took what I needed to modify my run.graphql and run.js files and this what I ended up with (below). After running "shopify app function typegen" command and running the app again it worked!

 

vbjornsson_0-1720127051832.png

 

 

Here is my modified run.js:

// @ts-check
import { DiscountApplicationStrategy } from "../generated/api";

// Use JSDoc annotations for type safety
/**
* @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: [],
};

// The configured entrypoint for the 'purchase.product-discount.run' extension target
/**
* @param {RunInput} input
* @returns {FunctionRunResult}
*/
export function run(input) {
  const targets = input.cart.lines
    // Only include cart lines with a quantity of two or more
    .filter(line => line.quantity >= 2 &&
      line.merchandise.__typename == "ProductVariant")
    .map(line => {
      const variant = /** @type {ProductVariant} */ (line.merchandise);
      return /** @type {Target} */ ({
        // Use the cart line ID to create a discount target
        productVariant: {
          id: variant.id
        }
      });
    });

  if (!targets.length) {
    // You can use STDERR for debug logs in your function
    console.error("No cart lines qualify for volume discount.");
    return EMPTY_DISCOUNT;
  }

  // The @shopify/shopify_function package applies JSON.stringify() to your function result
  // and writes it to STDOUT
  return {
    discounts: [
      {
        // Apply the discount to the collected targets
        targets: targets,
        // Define a percentage-based discount
        value: {
          percentage: {
            value: 10.0
          }
        },
        message: "10% OFF"
      }
    ],
    discountApplicationStrategy: DiscountApplicationStrategy.First
  };
};

 

And my modified run.graphql:

query RunInput {
  cart {
    lines {
      quantity
      merchandise {
        __typename
        ... on ProductVariant {
          id
        }
      }
    }
  }
}

 

SomeUsernameHe
Shopify Partner
522 58 115

This is an accepted solution.

Try changing 

 

	cartLine: {
        id: line.id
      }

to

 productVariant: {
          id: variant.id
        }

 

Have I helped? Consider putting coffee in my mouth!
Buy Me a Coffee