Can only one of the Function API discount and the code discount be applied?

In Shopify, I used the Function API to implement discounts on the website. However, I found that after implementing the discount, users are unable to use a code to stack discounts at the checkout page.

The one that takes effect is the greater discount. For example, if the discount a user can get through the Function API is $100, and the discount using a code is $200, then the discount from the code will be applied. Conversely, if the discount from the code is less than the discount calculated by the Function API, then the discount from the Function API will be applied.

Only one of the two discounts can be applied. Can anyone help with this issue?

If I change the discount to 85%, then the code will be applied.

Below is my code:

/**
 * @description 
 *  Ekko
 *  2024-06-26
 */
// -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.First,
  discounts: [],
};

/**
 *  {RunInput} input
 * @returns {FunctionRunResult}
 */
export function run(input) {
  console.log('input', JSON.stringify(input));

  const threshold = 1000; // Set your threshold amount here
  const giftProductId = "gid://shopify/ProductVariant/45838797930812"; // Set the product variant ID for the gift product

  let cartTotal = input.cart.cost.totalAmount.amount;
  console.log('cartTotal', cartTotal);
  let giftLine = null;

  // Calculate the cart total excluding the gift product
  input.cart.lines.forEach(line => {
    if (line.merchandise.__typename == "ProductVariant") {
      if (line.merchandise.id == giftProductId) {
        giftLine = line;
      }
    }
  });
console.log('giftLine', JSON.stringify(giftLine))
if (giftLine) {
  cartTotal = cartTotal - 600 // Assuming variant.price exists and is the price of the product
}
console.log('cartTotal', cartTotal);

  // Check if the cart total meets the threshold
  if (cartTotal >= threshold && giftLine) {
    const discount = {
      targets: [
        {
          productVariant: {
            id: giftProductId,
            quantity: 1
          },
        },
      ],
      value: {
        percentage: {
          value: "100.0",
        },
      },
    };

    return {
      discountApplicationStrategy: DiscountApplicationStrategy.First,
      discounts: [discount],
    };
  }

  console.error("Cart does not meet the threshold for a discount or no gift product found.");
  return EMPTY_DISCOUNT;
}

This is by design.

It’s not a Shopify Functions-only thing. I recommend reading this article from Shopify’s helpdesk:

https://help.shopify.com/en/manual/discounts/combining-discounts/discount-combinations

It explains the rules for combining discounts.

If you want to stack discounts, look into the Discounts Allocator Functions API:

https://shopify.dev/docs/api/functions/reference/discounts-allocator

It’s in developer preview, but will provide the necessary primitives to make discount stacking possible.

Best,

Tobe

I don’t quite understand what you mean. Currently, I am implementing discounts using the Function API’s product discount feature. Can it integrate with the discount allocator you mentioned and work together with the product discounts I have implemented so that discount codes can also be applied?

When you register your discount function in GraphiQL, in the mutation you could specify how this discount will stack with other discounts. Note combinesWith object. With this conig I am able to combine shipping discount entered by user in checkout with my automatic function based discount.

mutation {
  discountAutomaticAppCreate(automaticAppDiscount: {
    title: "Rebuy Discounts",
    functionId: "***",
    startsAt: "2024-06-22T00:00:00",
    combinesWith: {
      orderDiscounts: true,
      productDiscounts: true,
      shippingDiscounts: true
    },
  }) {
     automaticAppDiscount {
      discountId
     }
     userErrors {
      field
      message
     }
  }
}

The combinesWith options, as well as the explanation for why only the greater of 2 product discounts will be applied to one product, can be found in the “Discount Combinations” article I linked in an earlier message.