Uh oh! We couldn’t find any match.

Please try other search keywords.

Bixby Developer Center

Guides

Basic Cart Transactional Capsule

About This Capsule

This sample capsule uses transactional features to create a shirt store. Users can search for shirts (FindShirt), which they can then add to and update in a cart using CreateOrder and UpdateOrder, respectively.

Users can then complete the transaction, by committing the order (CommitOrder) or canceling the order entirely (CancelOrder). Once users complete the transaction, they can check the status (CheckStatus) of the order, view a receipt (FindLastReceipt) that summarizes the details of the transaction, or cancel the order (CancelCommittedOrder).

Note

You should read the Simple Search Capsule and the Simple One-Step Transactional Capsule prior to reading this document, as this walkthrough builds off of those simpler documents.

These are some of the training entries included in this capsule:

  • "Check on my shirt order": No annotations.
  • "Buy a T-Shirt for me!": Annotation for shirt style.
  • "I'm Extra Large!": Annotation for shirt size.
  • "Buy a Men's Ralph Lauren Shirt": Annotation for shirt gender and brand.

Download this Capsule on GitHub

Files Included

The following folders and files are included in the sample capsule. More information about what these files do and how they interact with each other will be explained further in the walkthrough.

  • README.md - File that includes the latest updates to the sample capsule files.
  • assets - Folder of images used in the capsule. The images folder has a single icon of a t-shirt in the icons subfolder and images of all shirts available in the fictional shirt store.
  • capsule.bxb - File that contains the metadata Bixby needs to interpret capsule source code.
  • code - Folder of JavaScript files that actually execute the modeled actions.
    • lib - Additional files needed for the fictional shirt store.
      • shirts.js - JSON file of shirt objects available for purchase.
      • utils.js - Utility functions that help the core JavaScript actions.
  • models - Folder holding actions and concepts folders for the different model types. The concepts folder is divided into primitives and structures concepts.
  • resources - Folder of resources, which are organized by locale. In this case, only US-English is supported.
    • base - Folder of resources that cover all aspects of this capsule, regardless of locale.
      • *.view.bxb - Files that determine the UI for inputting and outputting information.
      • endpoints.bxb - File that specifies which JavaScript functions map to each of the action models.
    • en-US Folder of resource files related specifically to the US-English locale.
      • capsule.properties - File that contains test configuration information for the shirt store.
      • capsule-info.bxb - File that contains the capsule's general information that a user would see.
      • dialog - Folder of Dialog files that determine what Bixby tells the user.
      • layout - Folder of Layout files that determine what the user sees.
      • transactions - Folder of support files that determine transaction states.
      • training - Folder of training files that enable you to teach Bixby how to understand your users. You do not edit these files directly but instead interact with training via Bixby Developer Studio.
      • vocab - Folder of Vocabulary files that help Bixby understand variations in utterances.
  • stories - Folder containing stories, which test if Bixby is acting as expected. You normally interact with these files in Bixby Developer Studio and do not edit them directly.

Sample Capsule Goals

The example.shirt sample capsule and this guide explains the implementation of the following platform features:

Sample Capsule Walkthrough

This capsule creates a fictional shirt store. This is the usual user flow:

First, users search for a shirt they can buy by asking Bixby to find them shirts, and optionally adding parameters to what kind of shirt they want. Users can add or remove a shirt they want to buy. They can also choose to change the size or quantity of their shirt by updating their cart. When satisfied with their choices, they can confirm their order on a confirmation page.

Note

At any time prior to committing their order, users can choose to cancel their order instead.

Once the order is confirmed, Bixby makes the order. When the order is completed, Bixby creates and displays a receipt with the order information. After the order goes through, the user might want to check the status of their order or cancel it altogether.

There are three distinct phases in this transaction workflow:

  1. The transaction state, where the user prepares the cart by adding, removing, and updating items.
  2. The commit state, where the user confirms the transaction and Bixby places the order.
  3. The activity state, where the user interacts with the order after it has been committed, such as checking the order status or canceling the order.
Note

Not all transactions require three distinct phases. For more information, see transactional workflows.

Initializing the Order

Users start interacting with this capsule by asking for a shirt to buy. For example, users might say "Find shirts I can buy!" or "Buy a medium Men's Ralph Lauren shirt for me". Bixby starts the transaction with the goal CreateOrder, which is an action model of the type BeginTransaction. This set-up is similar to the bank sample capsule's Initialization of Transaction step, but with the purpose of creating a shirt order instead of a bank transaction.

During the creation of this order, the order requires an item to be created and thus calls CreateItem. CreateItem, in turn, looks for a shirt with the FindShirt. After this first item is created, the order is initialized and the intial order is displayed in a result-view.

Creating an Order

The output for the CreateOrder action is an Order structure concept, with the structure tagged with the features key in transaction. This is so Bixby can keep track of this Order throughout the transactional workflow and update it as necessary.

The Order structure has four properties:

  • items, a set of Item models. It gets them from the input process described below.
  • orderNumber, an integer to keep track of different orders. Since this is a fictional store, it is artificially set by the CreateOrder.js file:

      orderNumber: 23343,
  • totalPrice, the total price of the order, which is calculated by a function within the CreateOrder.js file:

      function calculateTotalPrice(items) {
    var totalPrice = 0
    for (var i=0; i<items.length; i++) {
    totalPrice += items[i].shirt.price.value * items[i].quantity
    }
    return {
    value: totalPrice,
    currencyType: {
    prefixSymbol: '$',
    currencyCode: 'USD'
    }
    }
    }
  • holdTime, the amount of time the cart can hold the items in the cart before the transaction times out. The JavaScript handles the amount of time:

      holdTime: dates.ZonedDateTime.now("UTC").plusSeconds(parseInt(config.get("hold_time"))).getMillisFromEpoch()

    The actual hold_time is set in the capsule.properties file:

      # hold time in seconds
    config.test.hold_time=600

Most of the Order properties are set by the JavaScript files. However, to get the items property, CreateOrder has a single input (items) that consists of one or more Item structure concepts.

For example, if a user says "Buy me a polo shirt", here is the full execution graph during this stage:

Full execution graph for "Buy me a polo shirt"

If a specific enough shirt isn't specified, then the constructor CreateItem action model is called from the default-init key:

default-init {
intent {
goal: CreateItem
value: SearchTerm ("")
}
}

Here is the corresponding execution graph, which is calling CreateItem:

Unfulfilled Plan

Creating an Item in an Order

When CreateOrder triggers CreateItem, Bixby generates a prompt with all the shirts available for purchase and users can select a shirt from the generated results.

Which shirt? Prompt

This prompt is created by the Shirt_Input.view.bxb file.

input-view {
match: Shirt (this)

message (Which shirt?)

render {
selection-of (this) {
where-each (one) {
layout-macro (shirt-image-card) {
param (shirt) {
expression (one)
}
}
}
}
}
}

From this input-view file, you can determine what information is shown to the user in the selection prompt. The where-each key is used to loop through the results, calling the shirt-image-card macro to display an image card for each shirt (as defined in the ImageCard.layout.bxb file).

Also in the default-init that was defined in CreateOrder is the goal CreateItem, which constructs the Item. CreateItem has the following optional inputs:

  • searchTerm to search for a specific shirt (using the FindShirt action model) using the terms a user might utter
  • brand to indicate a brand enum
  • style to indicate a style enum
  • gender to indicate which of the gender enums are specified
  • minPrice to indicate the minimum price the user wants to spend
  • maxPrice to indicate the maximum price the user wants to spend

In addition, it has a required computed-input of a shirt, since each Item requires a Shirt. This is computed by taking any provided optional input above and creating it with the FindShirt action. Similar to the shoe search capsule example, when users give an utterance such as "Find me a shirt", Bixby uses the FindShirt action to return a number of shirts that can be selected and added to the CreateOrder action. You can see this in the execution graph

Each Shirt structure concept has a number of properties that users can specify as well, which are mapped to primitive concepts in the primitives folder:

  • title: A hard-coded summary of the shirt with the price, brand, and style of the shirt that you can display to users
  • price: The price module uses the imported viv.money capsule
  • gender: Enum: Male or Female
  • brand: Enum: RalphLauren or TommyHilfiger
  • style: Enum: Tee, Polo, Henley, SweatShirt, and DressShirt
  • availableSizes: Enum of possible sizes
  • An input-group for item-properties which sets the size and quantity of the Item being created.
    • size determines the size of the Item being purchased. It has a default-init that defines which sizes are available to choose from and a default-select that automatically chooses Medium, unless it is not available. In that case, the first item from the list of candidates is chosen.
    • quantity determines the quantity of the Item being purchased. The default-init key sets it to 1, if a quantity is not specified.
Note

In addition to these properties, each shirt has a description and photo of the shirt.

The CreateItem action outputs an Item. The corresponding CreateItem JavaScript file creates an Item object that maps to the Item model, which has the following properties:

  • shirt: found and created by the computed-input of CreateItem
  • size: set by the input-group
  • quantity: set by the input-group
Displaying Initial Order

Once the item is created, it is added to the cart and the Order is created:

Cart with 1 V-Neck Tee

This view is determined by the result-view file, Order_Result.view.bxb. This view is similar to the input-view for choosing a shirt. It uses the item-highlight layout macro (defined in ItemHighlight.layout.bxb) to display either a single shirt in the cart or, if there are multiple shirts, to loop through them and display item-highlight for each one. This creates one or more instances of thumbnail cards in the result view. Notice that the has-details key is set to false, meaning that if the user taps on the thumbnail-card for the Item, they will not be taken to a details view.

result-view {
match {
Order (this)
}

render {
if ("size(this.items) > 1") {
list-of (this.items) {
where-each (item) {
layout-macro (item-highlight) {
param (item) {
expression (item)
}
}
}
has-details (false)
}
} else-if ("size(this.items) == 1") {
layout-macro (item-highlight) {
param (item) {
expression (this.items)
}
}
}
}

conversation-drivers {
if ("size(this.items) > 1") {
conversation-driver {
template ("Buy")
}
}
}
}

Further, Bixby informs the user that the order is ready with the items requested using custom dialog in the Order_from_CreateOrder_Result.dialog.bxb file:

dialog (Result) {
match {
Order(order) {
from-output {
CreateOrder
}
}
}
template ("#{list (order.items, 'value')} is ready for ordering")
}

This dialog uses the Expression Language formatting function list() to fully list out everything that is in the cart.

After an item is found and the order is initialized, they are taken to the confirmation screen. They can still update the order until they indicate they are ready to buy.

Updating the Order

Users might not be satisfied with their order after the initial cart creation. For example, they might choose to add different shirts to their cart or remove items from their cart. Additionally, to the shirts in the cart already, they might choose to change the size or the quantity of the shirt. Finally, they might change their mind altogether and choose to cancel their transaction. In all of these situations, the goal action is Order#commitOrder.

The UpdateOrder action takes in the existing Order as an input, as well as an input-group of updates:

  • addedItems: a new item to add to the cart
  • changedItems: a change in size or quantity of an item in the cart
  • removedItems: a removed item from the cart

Notice that the model does not distinguish between how items are being updated. The UpdateOrder.js file actually does all three, in a specific order, whenever UpdateOrder is called:

exports.function = function(order, addedItems, changedItems, removedItems) {
// remove, change and then add
order = remove(order, removedItems)
order = change(order, changedItems)
order = add(order, addedItems)
return order
}

Instead, Bixby takes the inputs that the user gives plus training to create addedItems, changedItems, and removedItems. This could mean then that, if properly trained, a user could ask something like "Remove the polo shirt and update the v-neck tee to a Large shirt".

The UpdateOrder outputs an updated version of the Order. Note that there is a throws key, in case users try to update an empty cart. This will let the user know there are no items in the cart by calling the template-macro called NoItemsInCart. Template macros are useful in re-using pieces of dialog in multiple situations. For more information on using a template-macro for dialog, see Dialog Macros.

Depending on the updates item that is inputted, the corresponding action will be called. The following sections describe how the corresponding updated items are created.

Adding Additional Items to the Cart

Users might want to buy more than one shirt. They can choose then to invoke CreateAddedItem by using an utterance such as "Add 2 medium polo shirts to my order". This is the aligned-nl:

[g:UpdateOrder:continue:Order] 
Add {[g:AddedItem] (2)[v:Quantity] 
(Medium)[v:Size:Medium] (Polo Shirts)[v:SearchTerm]} to my order

Since there is already an Order created, Bixby calls UpdateOrder and then CreateAddedItem to add these shirts.

Add item plan

CreateAddedItem takes in the existing Order from UpdateOrder and also uses CreateItem from the given inputs to output an AddedItem. This AddedItem is taken back to the UpdateOrder, which will then update the order with the new AddedItem.

This is the helper add() function in the UpdateOrder.js that updates the existing order with the new item:

function add(order, items) {
[].concat(items).forEach(function(item) {
//check if there is a shirt with same size in the order already
var index = lib.findShirtsWithSize(order, item.shirt, item.size)
if (index >= 0) {
//update old item
order.items[index].quantity += item.quantity
} else {
//add new item
item.$type = 'example.shirt.Item' //down cast from `AddedItem` to an `Item`
order.items[order.items.length] = item
}
order.totalPrice.value += item.shirt.price.value*item.quantity
})
return order
}

Bixby will redisplay the order confirmation screen, now showing the updated cart:

Add items
Removing Items from the Cart

If users change their mind and don't want a certain item in their cart, they can choose to remove it, either by using an utterance, such as "Remove the Polo Shirt from my order", or with the user interface. Here is the aligned-nl for the utterance:

[g:UpdateOrder:continue:Order] Remove {[g:RemovedItem] (Polo Shirt)[v:SearchTerm]} from my order

When users request to remove something from their cart, Bixby calls UpdateOrder and then executes the CreateRemovedItem action. This action takes in the chosen Item and the existing Order to get a RemovedItem.

Optionally, a user can specify how many of the given item they want removed and if a quantity cannot be determined, then all of that shirt type is removed:

// how many should be removed
// all will be removed if not specified
input (quantity) {
type (Quantity)
min (Optional)
}
Note

This is one situation where vocabulary is particularly useful. If "a" wasn't listed in the quantity enum, Bixby could erroneously remove all the shirts instead of a single one.

Once that RemovedItem is created, it can be passed back to UpdateOrder and the helper remove() function in UpdateOrder.js can correctly remove the given item and update the existing order:

function remove(order, removedItems) {
[].concat(removedItems).forEach(function(removedItems) {
var index = lib.findItemIndex(order, removedItems.item)
if (index >= 0) {
order.totalPrice.value -= order.items[index].shirt.price.value*order.items[index].quantity
order.items.splice(index, 1)
} else {
if (order.length) {
throw fail.checkedError("NoMatch", "NoMatch")
} else {
throw fail.checkedError("NoItems", "NoItems")
}
}
})
return order
}

Bixby will, as before, present the updated cart view, with the removed item(s) no longer displayed:

Remove item

They could also remove an item by selecting the quantity in the UI and inputting 0 as the quantity. If this happens, Bixby treats it as an update to the quantity.

Updating Items in the Cart

Sometimes, users might want to change a detail about an item in their cart. For example, a user can ask Bixby to "Change the size to Large" for the shirt that is currently a Medium. The goal of that utterance is the UpdateOrder action, which will then call CreateChangedItem in order to pass a ChangedItem back to UpdateOrder. If Bixby is unsure of which shirt that you want changed, it will prompt you to choose one, which is explained further below.

Here is a plan graph to help illustrate what is happening:

Partial plan graph

Here is the aligned-nl:

  • For a size change:

      [g:UpdateOrder:continue:Order] 
      Change the size to {[g:ChangedItem] 
      (Large)[v:Size:Large]}
    
  • For a quantity change:

      [g:UpdateOrder:continue:Order] Change that to
      {[g:ChangedItem] (3)[v:Quantity] 
      (V-Neck Tees)[v:SearchTerm]}
    

Alternatively, the user can click on the size or quantity in the UI. For example, if they want to change the quantity, they would click on the Quantity button in this cart:

Click quantity in cart

This will cause a prompt to pop up for the user. The prompts will differ depending on which Item property users want to update.

  • This is the size prompt, which is created by the Size_Input.view.bxb file:

    Size Prompt

    The view renders a selection-of, which displays all the available sizes for that shirt and upon selection, passes the choice back to the Quantity for the updated item.

  • This is the quantity prompt, which is created by the Quantity_Input.view.bxb file:

    Prompt for Quantity

    The view renders a form with a number-input, so that users can input a number of shirts they want.

Bixby knows how to handle the incoming properties and creates these prompts because of CreateChangedItem.

The CreateChangedItem action takes in the existing Order, the SelectedItem, and the group of changed-item-properties.

The SelectedItem structure also has the concept features key set to transient. This is because we don't want the system to remember these choices in the future, especially if the user decides to change the size or quantity of a different shirt in the cart.

Bixby knows which item is selected in CreateChangedItem either directly from the UI choice or from the utterance itself.

input (item) {
type (SelectedItem)
min (Required)
default-init {
intent {
goal: SelectItem
value: $expr(order.items)
}
}
}

The SelectItem action takes in the existing Order, any search terms used, and computes the selectable items from the Order to output a SelectedItem to pass back to CreateChangedItem. It matches a search term (for example, "v-neck") to the list of items in the order. There are three possible outcomes for SelectItem:

  • A single item from the Order matches the search terms and is returned by SelectItem.

  • Multiple items match, in which case a MultipleMatches exception is thrown:

       error (MultipleMatches) {
    property (matches) {
    type (Item)
    max (Many)
    }
    on-catch {
    // prompt for matched items, clear searchTerm
    replan {
    intent {
    goal { @context (Continuation) SelectItem }
    value { @prompt-behavior(AlwaysSelection) $expr(matches) }
    value-set: SearchTerm {}
    }
    }
    }
    }

    In this case, a replan is executed to create a prompt for users to choose one of the matched items:

    Select Item prompt

    Bixby knows to use the Shirt_Input.view.bxb file to create a selection prompt of shirts, since a shirt needs to be specified in this situation.

  • Nothing matches, in which case a NoMatch exception is thrown:

        error (NoMatch) {
    on-catch {
    // prompt for items, clear searchTerm
    if (exists(items)) {
    replan {
    intent {
    goal { @context (Continuation) SelectItem }
    value { @prompt-behavior(AlwaysSelection) $expr(items) }
    value-set: SearchTerm {}
    }
    }
    } else-if (size(order.items) > 0) {
    replan {
    // prompt for items, clear searchTerm
    intent {
    goal { @context (Continuation) SelectItem}
    value { @prompt-behavior(AlwaysSelection) $expr(order.items)}
    value-set: SearchTerm {}
    }
    }
    }
    }
    }

    In this case, the same prompt is created with all the items in the cart, if there is anything in the cart. Otherwise, Bixby lets the user know that the cart is empty using a dialog macro: No items in shopping cart!

As for getting the changed-item-properties, it is looking for a promptedSize from the prompt, a size directly from the utterance, a promptedQuantity from the prompt, or a quantity directly from the utterance. Notice that the size and quantity inputs have the plan-behavior key set to Direct, to indicate to the planner that the value should be passed directly from the utterance to ChangedItem, which should be instantiated with this new value.

In order for the UI to be clickable so that items are editable (and consequently, have promptedSize or promptedQuantity instantiated), several files need to be in place. This capsule uses Bixby Views, as described briefly with the prompts information above.

Both PromptedSize and PromptedQuantity have a role-of set to the concepts of Size and Quantity respectively. Notice also that they have the concept features key set to transient, similar to ChangedItem.

The corresponding JavaScript file takes in that order with the new size or quantity and updates the order object property to the new properties.

This ensures that the prompt stays consistent and doesn't assume any of the users' preferences when shopping, as users might be shopping for other people.

Once CreateChangedItem has all its required inputs, it evaluates the given inputs and outputs a ChangedItem.

Canceling the Transaction

If users decide that they don't want to order anymore, they can tell Bixby to cancel their order. This is the aligned-nl:

[g:CancelOrder:continue:Order] Cancel this order

Bixby then recognizes the goal to be the action model CancelOrder, which is of the type CancelTransaction. The JavaScript file then takes the existing Order structure to create a Receipt, with the orderState set to Cancelled, while the platform aborts the current transaction. Bixby then lets the user know that the order is canceled.

Cancel order

Confirming the Transaction

When users are satisfied with their choices, the transaction can move to the Commit state, which is handled by the CommitOrder action model. CommitOrder takes in an order from the CreateOrder action, uses the confirmed-by key in transactional mode to create a confirmation view for users and returns a receipt.

Notice that this confirmed-by key also triggers a countdown timer for users to confirm their order via the expire-after key. If the users do not confirm after the order.holdTime of 120 seconds, the transaction expires. The platform remembers the cart information prior to the user's attempt to check out, but they must re-confirm their order. In a parallel situation of a real store, the user might have to re-enter payment information if the confirmation expired before the user finishes paying. This action also handles the re-trying of confirming the order via the retry-intent key, which has the intent of CommitOrder.

Payment Selection

If the user clicks Yes, the order is handled by the Order.transactions.bxb file. Clicking activates the CommitOrder action, which moves the transaction into the Commit phase:

on-user-click {
intent {
goal {
CommitOrder
}
}
}

Placing the Order

After the order is created and confirmed, the order is automatically created and placed.

In a real scenario, the JavaScript file would use an API call to contact the store server with payment information to process the transaction and to let the user know if it's completed. In this sample capsule, all orders automatically go through, without any validation.

Similar to the Getting a Receipt stage of the One-Step sample capsule, this transaction outputs a Receipt, with the properties order, orderState, and statusRefreshTime.

The statusRefreshTime property has visibility(Private) set, so other parts of the capsule and the platform cannot call it. This property is also set by the capsule.properties file:

config.test.status_refresh_time=10

Unlike the simpler transaction capsule however, the example.shirt capsule's Receipt has a features key defined:

features { activity }

This features key ensures that once the Receipt is created, the entire transaction is moved to the last phase of activity. This state needs to be defined in any case where you plan to do something with the transaction after it was committed. Otherwise, it's not necessary, like in the bank capsule.

This is what the receipt looks like to the user:

Receipt

Interacting After Committing

All actions after committing are in the activity state. After users commit and send their order, they might choose to do something with this order, such as checking the status of their order or canceling the order. For more information on giving updates in the activity state, see the Giving Updates with Activity Cards section.

Here are some examples of interactions after committing:

  • "Check on my shirt order" in various stages:
    Check on my order, Shipped Check on my order, Delivered
  • "Cancel my latest order":
    Cancelled order

In order to do either of those things, Bixby has to find the last order. Then it can either query the order's status or cancel it.

Any actions in the activity state are partly handled by activity-support in the Receipt.activity.bxb file. The orderState determines the state of the activity transaction's life:

  • Ordered has state Scheduled. This means that the transaction has been received and processed, but the activity hasn't happened yet. In this case, the shirt package is scheduled but not yet shipped.
  • Shipped has state Relevant. This means that the order has moved to a new state that the user probably wants to know. In this case, users want to know if their package has been shipped and is on the way to them.
  • Delivered and Canceled has state Recent. This means that the activity is over, either because the shirts have reached the user or because the user cancelled the order. The Recent state also indicates to Bixby that the entire transactional workflow is over, so no other actions can or should be taken.

The point of the states is to help keep track of the different stages during the activity and enables you to continue interacting with the user after the transaction was committed.

In all three instances, Bixby reacts in the same way: it displays the order information and its current state to the user through the summary-view and the details-view . There is also an expires key, which dictates how often the status of the activity should be checked and refreshed. The statusRefreshTime is set by the Order's statusRefreshTime property, which is determined in the capsule.properties file, as mentioned earlier.

In other transactions however, you might want to do different things at each stage. Consider the example of booking a hotel. When you're booking a hotel, during the Scheduled stage, you might want to have a "days-until" countdown until the start of the reservation. When the transaction gets to the Relevant stage after they've checked in, Bixby could send an Enjoy your stay! message. And when the user has finished their stay at the hotel and the transaction has moved to the Recent stage, Bixby could ask the user to rate their stay at the hotel.

Finding the Last Receipt

Bixby stores each transaction (and the corresponding receipt) created after a Commit is made in a platform-maintained archive. If the transaction does not reach the Commit phase (for example if a user decides to check the weather and exits out of the example.shirt capsule before buying a shirt), then the transaction is not stored.

In order for Bixby to retrieve this last receipt, this capsule has a FindLastReceipt action, of type ArchiveLookup:

action (FindLastReceipt) {
output (Receipt)
type (ArchiveLookup)
}

The corresponding JavaScript file simply retrieves the last receipt:

// FindLastReceipt
exports.function = function() {
return transaction.retrieve("Receipt", "ALL", 1)
}

The FindLastReceipt action is triggered when an activity action is called because those actions require a receipt, for example when cancelling the order or checking its status. If a receipt is not provided, the default-init key finds the last receipt:

...
default-init {
intent {
goal: FindLastReceipt
}
}
...
Checking Status of the Order

If the user asks Bixby "Check on my shirt order", the goal is example.shirt.CheckStatus. The action model CheckStatus has the type RefreshActivity, meaning the action refreshes a concept that is in the activity and returns that refreshed concept. In this case, it refreshes the Receipt to get its latest status and then returns that Receipt for the user.

Check Status Execution Graph Order Status
Note

All orders start with their orderState as Ordered. The CheckStatus JavaScript file artificially increases the status of the order every time the order is checked. So if the user checks the order status twice in a row, then the second time, the order goes from Ordered to Shipped then Shipped to Delivered.

In a real transaction, you would need to call the last externally stored transaction. You would use a GET call on a remote server, where the external state of the order is stored, to refresh and get the status of the shirt package.

Canceling the Committed Order

If the order is not in shipped status, then users can cancel their order. When Bixby gets the utterance like "Cancel my last order", it first finds the last receipt, as the required input for the CancelCommittedOrder.

CancelCommittedOrder is of type CancelActivity, meaning the action will attempt to cancel a transaction. However, note that this action model has several validate statements before it can cancel the order:

...
validate {
if (!exists(receipt)) {
halt {
dialog {
template ("Not sure what to cancel. I didn't find any recent shirt orders.")
}
}
}
if (receipt.orderState != 'Ordered') {
halt {
dialog{
template ("This order is already ${value (receipt.orderState)}!")
}
}
}
}
...

The first if statement checks if a receipt exists. If it doesn't, it tells the user.

The next if statement checks if the orderState is in Shipped, Delivered, or Cancelled. In those cases, it can't cancel the shipment and tells the user the current status.

Cancel Committed Order Execution Graph

The execution graph is paused at the Goal Action because it is awaiting a response from the user through a prompt. In addition to the validation statements, Bixby ensures that you really want to cancel the order by making users confirm their cancellation.

Cancel Committed Order Prompt

This prompt is created by the confirmed-by key, of type PositiveEmphasis, in the CancelCommittedOrder action model. This confirmed-by statement also validates if a receipt exists, before it can present the cancel confirmation page. If the user chooses to cancel the order by clicking the Cancel Order button, the order is canceled.

Canceled Order

However, if the user aborts the cancellation, the capsule runs CheckStatus, as defined by the on-abort key:

...
on-abort {
intent { // The intent to execute when user aborts the confirmation
goal {CheckStatus}
}
}
...

As noted before, checking the status (even when attempting to cancel the order) artificially moves the status of the order up.

Training This Capsule

This section discusses how to train the capsule, which in turn teaches Bixby typical queries for the example.shirt capsule.

Training Entries Explained

The following training entries are not necessarily in the order found in the example.shirt capsule, but they are referred to in the rest of this section as listed. You can test these utterances in the simulator using aligned-nl.

  • Training Entry 1: "Check on my shirt order"

      [g:CheckStatus] Check on my shirt order
    

    This training example has the goal CheckStatus. It returns the current orderState of an open transaction. The example helps Bixby learn a typical utterance a user would say after completing an order.

  • Training Entry 2: "Buy a T-Shirt for me!"

      [g:CommitOrder, r:CreateOrder, r:CreateItem] Buy (a)[v:Quantity:1] (T-Shirt)[v:Style:Tee] for me!
    

    This training entry has the goal CommitOrder and a route of CreateOrder and CreateItem, with the "T-Shirt" tagged with the value Tee to indicate what style the user wants. Bixby brings up two options: the Tommy Hilfiger Men's Core Flag V-Neck Tee or the Ralph Lauren Men's Pony Logo T-Shirt. This entry helps Bixby learn how to initiate an order, as well as helping Bixby learn the different shirt styles that can be asked for by users.

  • Training Entry 3: "I'm Extra Large!"

      [g:Size:prompt] I'm (Extra Large)[v:Size:ExtraLarge]!
    

    This training entry goal is Size:prompt. This goal is specifically for the selection prompt, where the user is being asked what size shirt to choose. The entry teaches Bixby a typical utterance in response to this prompt. It also teaches Bixby an example of a shirt Size, in this case the value for Size:ExtraLarge is "Extra Large".

  • Training Entry 4: "Buy a Men's Ralph Lauren Shirt"

      [g:CommitOrder, r:CreateOrder, r:CreateItem] Buy a (Men's)[v:Gender:Male] (Ralph Lauren)[v:Brand:RalphLauren] Shirt
    

    This training example is similar to Training Entry 2, in that the goal is CommitOrder and teaches Bixby an example of initializing a transaction within the shirt capsule. It is a little more specific however, in that the utterance specifies a Gender and a Brand value for filtering. The training example returns Ralph Lauren shirts.

Vocabulary

In addition to training, shirt utilizes vocabulary to help Bixby understand utterances further. The vocab folder contains these vocabulary files:

  • Brand
  • Gender
  • Quantity
  • SearchTerm
  • Size
  • Style

All the vocabulary files contain variations on the key words that are being looked for by Bixby to map values with concepts, actions, and goals in the utterances.

The SearchTerm vocab file is different in that it does not expand upon predetermined values. Since enums and integer types are closed type vocabulary, they explicitly need a vocabulary file to expand possible iterations in utterances. Integers (in this case, Quantity) are normally handled by the platform, but this vocabulary file also includes a few utterances (such as "a" to indicate a Quantity of 1) that might be needed. SearchTerm, however, is open type vocabulary. This means that the terms included in this file, while not explicitly listed as possible values for SearchTerm, are examples of SearchTerm uses that Bixby might need in order to complete an order.

For more information on training and best practices, see The Art and Science of Training.

Caveats and Limitations

Keep the following in mind about this capsule:

  • In a realistic scenario, you might have shirts (or other items being sold) in a size that is not in stock but selectable in the capsule. You should catch this corner-case and warn the user if the item they are trying to purchase isn't available.
  • Also in a realistic scenario, you would probably use an API call to check a store server for items for purchase instead of having the list of items hard-coded in your JavaScript files.
  • Similarly, a payment method system would need to be integrated, with OAuth authorization put in place, for users to actually buy and pay for items.