Offering local pricing

Gain a better understanding of how to set up local pricing for use in a Prebuilt Checkout

If you'd like to pair Prebuilt Checkout with local pricing, this page contains information on:

All of the local pricing functionality exists within DigitalRiverCheckout.js.

Setting up the shopping experience

When building your shopping experience, one possible solution is to wait until the document loads and then, at a minimum, define containerId. Digital River needs this value to determine where to display the local pricing selector. Although it's not a hard requirement, you should also populate priceElement so we know which of your DOM elements contain product prices.

You also have the option to define how you want to handle various selector events. These events can be useful for testing, analytics, and triggering redirections. For example, you might handle onSave by checking the value of country, and then, if it's US or CA, redirect to an experience or store that's customized for shoppers in those countries.

document.addEventListener('DOMContentLoaded', () => {
  const config = {
    countrySelector: {
      containerId: 'country-selector',
      priceElement: ['div.price', 'span.price'],
      autoOpen: true,
      onReady: () => {},
      onOpen: () => {},
      onSelect: (data) => {},
      onSave: (data) => {},
      onCancel: () => {}
    }
  };
  ...

You can then use this configuration object to initialize DigitalRiverCheckout.js.

  ...
  const digitalRiverCheckout = new DigitalRiverCheckout('Your public API key', config);
  ...

If you want Digital River to create a checkout button, call renderButton().

  ...
  digitalRiverCheckout.renderButton(buttonContainer, buttonOptions);
  ...

The function's first parameter is the id of the element where you want the button to display.

 <div id="button-container"></div>
 ...
 const buttonContainer = '#button-container';
 ...

The second parameter is a configuration object that, among other things, allows you to (1) style the button, (2) modify its text, and (3) hide your elements.

  ...
  const buttonOptions = {
    style: {
      backgroundColor: '#B52',
      borderRadius: '100px',
      color: '#5C6',
      fontSize: '2rem',
      fontWeight: '800',
      fontFamily: 'Montserrat,Arial,Helvetica,sans-serif',
      ':hover': {
        color: 'rgb(0, 167, 225)'
      }
    },
    buttonText: 'Proceed to checkout',
    hiddenElement: ['#checkout-btn'],
    afterRender: true,
    onInit: (actions) => {
      console.log('The button has rendered');
    },
    ...
    onCancel: () => {
      console.log('The checkout window has been closed');
    }
  };
  ...
});

This object also contains an onClick property to which you can assign an async event-handling procedure. One way to define it is by using a try...catch block that first calls actions.loading.start() and then your own create checkout-session function. Make sure to use await with this expression so that the handler pauses until a promise is returned.

  ...
  const buttonOptions = {
    ...
    onClick: async (actions) => {
      console.log('The button has been clicked');
      try {
        actions.loading.start();
        const checkoutSessionId = await createCheckoutSession();
        actions.loading.stop();
        if (!checkoutSessionId) {
          return;
        }
        const config = getConfigObj();
        actions.checkout.modal.open(checkoutSessionId, config);
      } catch (error) {
        actions.loading.stop();
      }
    },
    ...
  };
  ...
});

On your front-end, in onClick, call actions.loading.stop() and then check the value of the promise. If it's falsy, your procedure should reject it and halt execution. Otherwise, pass the returned identifier and, optionally, a configuration object to actions.checkout.modal.open().

Configuring the checkout-session for local pricing

When defining the checkout-session:

  • Call digitalRiver.getCountry() and digitalRiver.getCurrency() and then assign the returned values to the shoppingCountry and currency parameters, respectively.

  • For each product in the customer's cart, retrieve its original, unconverted price and assign it to items[].price.

  • If you're discounting an entire transaction or individual line items within that transaction, use discount.percentOff or items[].discount.percentOff. In both cases, don't define amountOff.

In your server-side POST to /drop-in/checkout-sessions, make sure to send your secret API key.

Product prices during the shopping experience

Digital River uses the checkout-session's shoppingCountry, currency, and items[].price to perform another currency conversion and then applies the same rounding and formatting rules used to display prices on your site. As a result, the currency-denominated prices customers see on your storefront and in your cart are identical to those in the checkout experience.

Access price formatting rules

Once customers provide payment, complete their purchase, and Digital River converts the checkout-session to an order, we add pricingFormat to the event with a type of checkout_session.order.created.

checkout_session.order.created
{
    "id": "dacc88d7-3f88-469b-9764-35a15681e6c9",
    ...
            "pricingFormat": {
                "currencyNumberFormat": "#,###.##",
                "symbol": "₩",
                "decimalPlaces": 0,
                "currencySymbolBeforePrice": true,
                "useCurrencySymbolSpace": false
            },
            "liveMode": false
        }
    },
    ...
}

This object contains the rules Digital River used to format prices throughout the shopping experience. To maintain a consistent format, you can apply these rules to the prices in your customer notifications and your site's order management pages.

You can also access pricingFormat by assigning a handler to onCheckoutComplete.

{
    "id": "764ddbdd-0f7e-448d-b044-196f67dd1781",
    "type": "checkout_session.order.created",
    "data": {
        "object": {
            ...
            "pricingFormat": {
                "currencyNumberFormat": "#,###.##",
                "symbol": "¥",
                "decimalPlaces": 0,
                "currencySymbolBeforePrice": true,
                "useCurrencySymbolSpace": false
            },
            ...
        }
    },
    ...
}

If you don't want to build your formatter, many server-side languages have pre-built functions that roughly approximate the formatter Digital River uses. Depending on your application, you might find some of the following pages useful:

The following objects are nested in pricingFormat:

currencyNumberFormat

You can use currencyNumberFormat to determine how to display the integer and fractional parts of a price.

Its value indicates whether the character that groups digits in the integer part should be a comma (,), a point (.), an apostrophe ('), a whitespace( ), or some other character. It also dictates the correct spacing of this character.

Additionally, currencyNumberFormat allows you to determine whether the character that separates the price's integer part from its fractional part should be a point or a comma.

In the following example, currencyNumberFormat indicates that the digits in the integer part should be grouped by a comma placed every third digit to the left of a point, which acts as the separator between the price's integer and fractional parts.

"currencyNumberFormat": "#,###.##"

Target output in UI

symbol

The graphic symbol that should be used to denote the price's currency.

The following is the symbol for Swiss Francs:

"symbol": "CHF"

Target output in UI

decimalPlaces

This stipulates the number of digits that should be displayed to the right of the character (whether it's a point or comma) that divides a price's integer part from its fractional part.

If decimalPlaces is 0 and currencyNumberFormat indicates that a character should be placed between the integer and fractional parts, then that character shouldn't be displayed.

{
    ...
    "pricingFormat": {
        "currencyNumberFormat": "#,###.##",
        ...
        "decimalPlaces": 0,
        ...
    },
    ...
}

currencySymbolBeforePrice

The currencySymbolBeforePrice indicates whether symbol should be placed before or after a price's numeric amount.

useCurrencySymbolSpace

The useCurrencySymbolSpace indicates whether or not to insert a space between symbol and the price's numeric amount.

Last updated