Create the widget

To obtain prices from an external pricing system, you write a custom widget to include on your storefront’s pages.

The custom widget’s JavaScript file extends the storefront’s CartViewModel class by implementing a prepricing callback function. When a shopper modifies the shopping cart by adding or removing products or changing quantities, this function makes a call to the external pricing system to obtain prices for the items in the cart.

In addition to an externalPrice property for storing the external price of a product, the CartViewModel has an externalPriceQuantity property that determines the maximum quantity that the external price can be applied to. For example, suppose the list price of a product is $10.00, but the external pricing system returns an externalPrice value of $7.00 and an externalPriceQuantity value of 3. If a shopper selects this product and specifies a quantity of 2, the price in the cart for the two items is $14.00, because the external price is applied to both items. However, if the shopper specifies a quantity of 5, the external price is applied to only three of the items, so the total is $41.00 (three items at $7.00 each, and two items at $10.00 each).

If the value of externalPriceQuantity for a specific product is -1, there is no maximum quantity, so the external price is applied to all of the items of the product.

Create the widget structure

Create your widget as a global widget. Global widgets are automatically loaded for all pages; you do not need to add them explicitly to page layouts. Global widgets cannot include any user interface elements, so you should omit any display templates. The following shows an example of the files and directories in a global widget:

External Pricing/
    ext.json
    widget/
        external-pricing/
            widget.json
            js/
                external-pricing.js

To make the widget global, set the global property in the widget.json file to true:

"global": true

For more information about the widget structure and the contents of the ext.json and widget.json files, see Create a Widget.

Write the JavaScript

The JavaScript code you write extends the CartViewModel class by implementing a callback function that executes during prepricing. The following example shows sample JavaScript that implements a prepricing function:

define(

  ['jquery', 'knockout', 'ccLogger'],

  function($, ko, CCLogger) {

    'use strict';
    return {

      onLoad: function(widget) {
      CCLogger.info("Loading external pricing widget");
      var callbackMap = new Object();
      var performPrepricing = function()
      {
      // sample code to invoke external system
        $.ajax({
          type: 'POST',
          dataType: 'json',
          url: EXTERNAL_SYSTEM_SERVICE_URL,
          data: widget.cart().items(),
          success: function(data) {
            // update the cart items with external price details,
            // assuming data has item details with external prices
            if (data.items && data.items.length > 0) {
              for (var i = 0; i < widget.cart().items().length; i++) {
                for (var j = 0; j < data.items.length; j++) {
                  if (widget.cart().items()[i].productId ==
                    data.items[j].productId &&
                    widget.cart().items()[i].catRefId ==
                    data.items[j].catRefId &&
                    data.items[i].externalPrice &&
                    data.items[j].externalPriceQuantity) {
                    widget.cart().items()[i].externalPrice
                      (data.items[j].externalPrice);
                    widget.cart().items()[i].externalPriceQuantity
                      (data.items[j].externalPriceQuantity);
                   }
                 }
               }
            // invoke pricing in this success callback
            widget.cart().markDirty();
          }
        },
        error: function() {}
      });
    };
    callbackMap['prepricing'] = performPrepricing;
    widget.cart().setCallbackFunctions(callbackMap);
    }
   }
  }
);

Note that because the asynchronous call to the external pricing system may complete after a pricing operation has already taken place on the Oracle Commerce server, the code explicitly marks the cart as having been modified after applying the external price information. This forces another pricing operation to be invoked using the external prices.

Some other considerations to take into account when you create your widget:

  • To avoid making unnecessary calls, it is a good idea for your code to check whether external prices have already been applied to the cart items, and if so, skip calling the external system.
  • If the external system does not impose a quantity limit on a specific product, your code should set externalPriceQuantity to -1, so that the external price is applied to all of the items of the product.

Install the widget

To install the widget, do the following in the administration interface:

  1. Click the menu icon, then click Settings.
  2. Click Extensions and display the Developer tab.
  3. Click Generate ID to generate an extension ID for the widget.
  4. Edit the widget’s ext.json file and set the extensionID property to the value generated in the previous step.
  5. Package the widget as a ZIP file. Use the structure described in Create the widget structure.
  6. Display the Installed tab and click Upload Extension. Select the ZIP file.
  7. Publish your changes.

Price the cart items

The custom widget alters the logic for pricing the shopping cart. This section describes how the pricing of the cart behaves when external pricing is enabled.

When a shopper views the product detail page for a specific product, the page displays the internal price that Oracle Commerce stores for the product. When the shopper modifies the shopping cart (adds or remove an item, or changes the quantity of an item), the custom widget makes a call to the external pricing service, and applies any external prices it receives to the items in the cart. Note that this means that the price of a product in the cart may differ from the price displayed on the product detail page.

After obtaining prices from the external pricing service, the storefront sends the current contents of the cart to the Oracle Commerce server to calculate pricing (for example, to apply promotions). This call includes externalPrice and externalPriceQuantity values for any products in the cart that have external prices.

The following shows an example of the data sent to the server:

{
  "shoppingCart": {
    "items": [
      {
        "productId": "xprod1003",
        "quantity": 3,
        "catRefId": "xsku1013",
        "stockStatus": true,
        "discountInfo": [],
        "externalPrice": "21.00",
        "externalPriceQuantity": "1",
        "invalid": false
      },
      {
        "productId": "xprod1002",
        "quantity": 5,
        "catRefId": "xsku1007",
        "stockStatus": true,
        "externalPrice": "18.00",
        "externalPriceQuantity": "-1",
        "invalid": false,
        "currentPrice": 0
      }
    ],
    "coupons": []
  }
}

In the example above, the cart contains two products, xprod1003 and xprod1002. The quantity of xprod1003 is 3, but only one of those items will have the external price applied to it ($21.00), because the externalPriceQuantity value for xprod1003 is 1. The other two items will have the internal price applied.

The quantity of xprod1002 is 5, and all of these items will have the external price applied ($18.00), because the externalPriceQuantity value for xprod1002 is -1.

When the server receives the data above, it performs a pricing operation, using the external prices for any items that have them, and applying internal prices to the rest. The repriced cart data is returned to the storefront for display.

The following example shows part of the data returned to the storefront after a pricing operation:

{
  "shoppingCart": {
    "numberOfItems": 8,
    "items": [
      {
        "onSale": false,
        "catRefId": "xsku1013",
        "shippingSurchargeValue": 0,
        "externalPrice": 21,
        "unitPrice": 36,
        "discountAmount": 0,
        "productId": "xprod1003",
        "externalPriceQuantity": 1,
        "rawTotalPrice": 93,
        "price": 93,
        "discountInfo": [],
        "listPrice": 36,
        "detailedItemPriceInfo": [
          {
            "amount": 21,
            "currencyCode": "USD",
            "tax": 0,
            "discounted": false,
            "orderDiscountShare": 0,
            "quantity": 1,
            "detailedUnitPrice": 21
          },
          {
            "amount": 72,
            "currencyCode": "USD",
            "tax": 0,
            "discounted": false,
            "orderDiscountShare": 0,
            "quantity": 2,
            "detailedUnitPrice": 36
          }
        ],
        "salePrice": 0,
        "quantity": 3
      },
      {
        "onSale": false,
        "catRefId": "xsku1007",
        "shippingSurchargeValue": 0,
        "externalPrice": 18,
        "unitPrice": 24,
        "discountAmount": 0,
        "productId": "xprod1002",
        "externalPriceQuantity": -1,
        "rawTotalPrice": 90,
        "price": 90,
        "discountInfo": [],
        "listPrice": 24,
        "detailedItemPriceInfo": [
          {
            "amount": 90,
            "currencyCode": "USD",
            "tax": 0,
            "discounted": false,
            "orderDiscountShare": 0,
            "quantity": 5,
            "detailedUnitPrice": 18
          }
        ],
        "salePrice": 0,
        "quantity": 5
      }
    ]
  },
  "discountInfo": {
    "orderCouponsMap": {},
    "orderDiscount": 0,
    "orderImplicitDiscountList": [],
    "unclaimedCouponsMap": {},
    "shippingDiscount": 0
  },
  "priceInfo": {
    "amount": 183,
    "total": 183,
    "shipping": 0,
    "totalWithoutTax": 183,
    "currencyCode": "USD",
    "shippingSurchargeValue": 0,
    "tax": 0,
    "subTotal": 183
  },
...

The response shows the effect of the external pricing. For example, the detailedItemPriceInfo object for xprod1003 shows that one item is priced at $21.00 (the external price) and the other two are priced at $36.00 each (the internal price). The total price of the three items is $93.00.