Delivery Options mapping issue in checkout

Hi, I have been working a shopify app development. I have used Shopify Functions to apply discounts at checkout. When there are multiple shipping methods, in the deliveryGroups[0] index, the discount values are not correctly mapped to respective deliveryOptions. Could someone help me with this??

Hi! Can you share more info, such as an example input and output from your Shipping Discount Function and what you’re observing vs what you’re expecting? For reference, when you want to target specific delivery options you should be using the deliveryOption target, documented here.

1 Like

@Jonathan-Shopify Thanks for responding. I’ll let you know the complete flow how I have done and what issue I’m facing.

I have developed a functionality using Shopify Functions to apply discounts at checkout for shipping. Every time I capture the selectedDeliveryOption and use its shipping cost and compare the discount value and shipping cost and sends back the minimum value among them. This would ensure no negative values are shown in the checkout UI.

Let me give you an example scenario.

Say I have a discount value of $120. I have three shipping methods available in checkout namely, standard at $100, express at $500, mina fast at $1000. The below screenshots would give a better understanding of problem I’m facing.

In the above screenshot you can see by default the selectedDeliveryOption will be the first one and in this case, it sends the Math.min( 120, 100 ) which is $100 and that is applied to all the shipping methods shown in the left panel of checkout UI. Whereas when user selects any other shipping method,

the above screenshot can show the correct discount value to be applied both on left panel as well as in the right panel.

This is what I’m facing. tThis shouldn’t be happen right. The correct values should be show in the UI so that user will not feel any discomfort.

export function run(input) {
  //console.log('Shipping Discount Function Input:', JSON.stringify(input, null, 2));
  
  const cart = input.cart;
  const selectedOption = cart.deliveryGroups[0]?.selectedDeliveryOption;
  const selectedCost = selectedOption?.cost?.amount || 0;

  const shippingCost = selectedCost || 0;

  if (!shippingCost) {
    return { discounts: [] };
  }

  // Parse configuration from metafield
  let configuration;
  try {
    configuration = JSON.parse(
      input?.discountNode?.metafield?.value ?? "[]"
    );
    // Ensure configuration is always an array
    configuration = Array.isArray(configuration) ? configuration : [configuration];

    // Log the parsed configuration and cart contents for debugging
    console.log('Parsed configuration:', JSON.stringify(configuration, null, 2));
    console.log('Cart contents:', JSON.stringify(cart.lines, null, 2));
  } catch (error) {
    console.error('Error parsing configuration:', error);
    return { discounts: [] };
  }

  // Get valid offers based on cart contents and conditions
  const validOffers = getValidOffers(configuration, cart);
  console.log('Valid offers:', JSON.stringify(validOffers, null, 2));
  
  // Select the best offer based on discount value and priority
  const bestOffer = selectBestOffer(validOffers, shippingCost);

  if (!bestOffer) {
    return { discounts: [] };
  }

  // Calculate final discount amount
  const discountAmount = calculateDiscountAmount(
    bestOffer.discountType,
    bestOffer.discountValue,
    shippingCost
  );

  // Return the discount configuration
  return {
    discounts: [
      {
        targets: [
          {
            deliveryGroup: {
              id: cart.deliveryGroups[0].id
            }
          }
        ],
        value: {
          fixedAmount: {
            amount: discountAmount
          }
        }
      }
    ]
  };
}

The above provided code is my main run function which will send the final amount to be applied for shipping cost.

Let me know if I’m doing correct or is there anything to be changed from my end.

We can definitely improve this aspect of our docs - I’ll make a ticket for us to do that.

In the meantime, instead of producing the discount for the selected delivery option, your function should produce the discounts for each delivery option if you want different values per option, or a single value if you want it to apply to all options.

In your description, it sounds like you want to make the cheapest delivery option free and reduce all the others by the same amount, but instead of using the cheapest delivery option’s price you’re using the selected option’s price.

Something along these lines, instead of using the selectedDeliveryOption, should do what you’re describing.

const cheapestOptionCost = input.cart.deliveryGroups
  .flatMap((group) => group.deliveryOptions)
  .reduce((min, option) => Math.min(min, option.cost.amount), Infinity);

Alternately, you could output a discount per option using the configured max discount amount (120 in your example):

// output a discount for each delivery option, using the configured max discount amount
const discounts = input.cart.deliveryGroups
  .flatMap((group) => group.deliveryOptions)
  .map((option) => ({
    targets: [
      {
        deliveryOption: {
          id: option.id,
        },
      },
    ],
    value: {
      fixedAmount: {
        amount: Math.min(maxDiscountAmount, option.cost.amount),
      },
    },
  }));

@Jonathan-Shopify Thanks for detailed response. Will try out and let you know. Thanks again.

@Jonathan-Shopify Both the solutions you provided didn’t work out. The discount is not getting applied in the checkout.

The first solution you provided won’t work, because it is taking the cheapest cost among the multiple deliverOption cost. Anyhow the same scenario will be occurred again right?.

In the alternate method you told, it seems like, I need to return a group of values. Tried out that method already, and got an error which is now showing on.

❌ Function export "run" failed to execute with error: InvalidOutputError

I want to know how does the Shopify handles in this case. It can return only a single value at a time right ( as per my knowledge ). How does it handles returning of group of values?

Without seeing your actual function output, it’ll be hard for me to comment on why you’re getting an invalid output error.

The behaviour when multiple discounts are returned for shipping discount functions is documented here: Shipping Discount API reference