Upselling Products

You may recall from Chapter 4, Creating Multi-Turn Dialogs that ScheduleTripIntent doesn’t complete until the user has specified the destination, departure date, and return date and those slots are validated. Until then the dialog is considered “in progress”, enabling us to step into the dialog to do custom validation.

In fact, we took advantage of this to validate that the return date is after the departure date in the ScheduleTripIntentHandler_InProgress.js module. We’ll apply a similar technique to verify that the user has purchased the Magnificent Moons package before allowing them to plan a trip to one of those premium destinations.

To start, let’s create a local helper function that checks to see if the user is requesting a trip to a moon and, if so, that they have bought the “Magnificent Moons” package:

 const​ ProductUtils = require(​'./productUtils'​);
 async​ ​function​ validateMoonsDestination(handlerInput) {
 const​ destinationSlot =
  Alexa.getSlot(handlerInput.requestEnvelope, ​'destination'​);
 if​ (destinationSlot.resolutions) {
 const​ resolution =
  destinationSlot.resolutions.resolutionsPerAuthority[0];
 const​ destination = resolution.status.code === ​'ER_SUCCESS_MATCH'​ ?
  resolution.values[0].value.id :
  destinationSlot.value;
 const​ destinationName = resolution.status.code === ​'ER_SUCCESS_MATCH'​ ?
  resolution.values[0].value.name :
  destinationSlot.value;
 
 if​ (destination && [​'LUNA'​,​'IO'​,​'EUROPA'​,​'CALLISTO'​,​'GANYMEDE'​,​'TITAN'​]
  .includes(destination)) {
 const​ product =
 await​ ProductUtils.getProduct(handlerInput, ​'MAGNIFICENT_MOONS'​);
 if​ (!product || product.entitled !== ​'ENTITLED'​) {
 throw​ {
  message: handlerInput.t(​'UPSELL_MOONS_PACK'​,
  { destination: destinationName }),
  productId: product.productId
  };
  }
  }
  }
 }

The first thing that validateMoonsDestination() does is fetch the resolved entity value from the “destination” slot and then compare it with a set of destination IDs known to be part of the add-on package. If the “destination” slot’s value is one of those premium destinations, then the function checks whether the product has been purchased by the user.

To check whether the product has been purchased or not, the validateMoonsDestination() calls getProduct() to fetch the product whose reference name is “MAGNIFICENT_MOONS”. Then, it’ll inspect the product’s entitled property. If the user has purchased the package, then entitled will be set to “ENTITLED”. Otherwise, the user hasn’t purchased the product and the function will throw an error containing the localized “UPSELL_MOONS_PACK” message and the product ID. The error’s localized message is in languageStrings.js, like this:

 UPSELL_MOONS_PACK: ​'Travel to {{destination}} is only available '​ +
 'with the "Magnificent Moons" add-on. Do you want to learn more '​ +
 'about this option?'​,

Within the intent handler’s handle() function, we’ll call the validateMoonsDestination() function, passing in the handlerInput:

 try​ {
 await​ validateMoonsDestination(handlerInput);
 } ​catch​ (error) {
  console.error(error);
 return​ handlerInput.responseBuilder
  .addDirective({
  type: ​"Connections.SendRequest"​,
  name: ​"Upsell"​,
  payload: {
  InSkillProduct: {
  productId: error.productId,
  },
  upsellMessage: error.message,
  },
  token: ​"correlationToken"​,
  })
  .getResponse();
 }

If validateMoonsDestination() returns successfully, then either the destination is not a moon or the user must have purchased the Magnificent Moons package. In that case, the request handler’s handle() method moves on, validating the dates and continuing through the dialog.

But if validateMoonsDestination() throws an error, then the handle() message ends by returning a Connections.SendRequest directive, much like how the handler for BuyIntent works. What’s different, however, is that the name property is set to “Upsell” instead of “Buy”. This causes Alexa to pause the dialog flow and enter into an upsell sub-flow.

In the upsell sub-flow, Alexa will first ask if the user wants to learn more about the product and, if the user replies “yes,” then it will describe the product and ask if they want buy it. If the user chooses to buy the product, Alexa will handle the transaction automatically. The flow then resumes with a special Connections.Response request.

Assuming the user hasn’t already purchased the Magnificent Moons package, the conversation flow with the upsell sub-flow looks like the screenshot.

images/sell/upsell.png

If you were to deploy the skill at this point, the skill should work as it always has. But if the user were to try to plan a trip to Titan, Callisto, or any other moons in the “Magnificent Moons” package, the flow will be redirected through the upsell sub-flow, offering the user the option of buying the package. And, if the user chooses to do so, the flow will automatically handle the purchase.

Now that we’ve enabled our skill to offer and sell in-skill products, let’s see how to reverse the purchase to allow a refund.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset