Migra transacciones de bienes físicos a la v3 (Dialogflow)

A partir del 7 de agosto de 2019, la API de Orders v2 dejó de estar disponible y se reemplazó por Orders versión 3. Si creaste una acción que procesa transacciones físicas antes de esta fecha, sigue esta guía para actualizar tu Acción y usar Orders v3.

Cambios en la API

La versión 3 de la API de Orders incluye los siguientes cambios clave respecto de la versión 2:

  • Estructura de la solicitud: La estructura de orden de la versión 3 contiene todos los los detalles del pedido, en lugar de incluir solo el contenido del carrito.
  • Actualizaciones de pedidos: La versión 3 de la API de Orders controla las actualizaciones de pedidos en además de controlar la realización del pedido, por lo que el extremo no necesita usar la API de Actions para enviar a los usuarios actualizaciones sobre sus pedidos. También envías como solicitudes PATCH a la API de Orders que actualizan el estado order, en lugar de solicitudes POST para enviar actualizaciones de estado.
  • Facilitación de pagos: Acciones que usan Google Pay con la versión 3 La API de Orders anida sus detalles de la puerta de enlace de pago en una nueva estructura JSON que permite una mayor extensibilidad y cumplimiento de las leyes de la UE.

Migra Node.JS a v3

Sigue estos pasos para migrar una acción que use la biblioteca cliente de Node.JS.

1. Agrega la marca Pedidos v3

Se actualizan las funciones de la biblioteca cliente que usaste para administrar transacciones. Para la versión 3 de Pedidos, solo debes agregar una marca a tu código de entrega. que actualiza las funciones para enviar la versión 3 de JSON.

Agrega el siguiente código a tu entrega:

Node.js
const {dialogflow} = require('actions-on-google');
const app = dialogflow({ordersv3: true});

2. Actualiza la estructura de tu carrito

El ProposedOrder se reemplazó el tipo de elemento por el Order, que es más detallado. . Consulta la referencia de JSON para convertir tu carrito de ProposedOrder en un carrito de Order.

3. Actualiza los parámetros de pago

La estructura de la información de pago en el paso de propuesta de pedido es diferente entre las versiones de la API.

En la solicitud de intent actions.intent.TRANSACTION_DECISION, reemplaza el anterior Un objeto paymentOptions con el nuevo objeto paymentParameters. La mayoría de todos los campos contenidos son los mismos, guarde algunos cambios en el archivo JSON en la nube.

En los siguientes fragmentos de código, se muestra un ejemplo de actions.intent.TRANSACTION_DECISION intent de Google Pay con la versión 3 y una solicitud de versión 2 anterior para comparación.

Node.JS nuevo (v3)
conv.ask(new TransactionDecision({
  orderOptions: {
    requestDeliveryAddress: false,
    userInfoOptions: {
      userInfoProperties: [
        'EMAIL',
      ],
    },
  },
  paymentParameters: {
    googlePaymentOption: {
      // facilitationSpec is expected to be a serialized JSON string
      facilitationSpec: JSON.stringify({
        apiVersion: 2,
        apiVersionMinor: 0,
        merchantInfo: {
          merchantName: 'Example Merchant',
        },
        allowedPaymentMethods: [
          {
            type: 'CARD',
            parameters: {
              allowedAuthMethods: ['PAN_ONLY', 'CRYPTOGRAM_3DS'],
              allowedCardNetworks: [
                'AMEX', 'DISCOVER', 'JCB', 'MASTERCARD', 'VISA'],
            },
            tokenizationSpecification: {
              type: 'PAYMENT_GATEWAY',
              parameters: {
                gateway: 'example',
                gatewayMerchantId: 'exampleGatewayMerchantId',
              },
            },
          },
        ],
        transactionInfo: {
          totalPriceStatus: 'FINAL',
          totalPrice: '10.00',
          currencyCode: 'USD',
        },
      }),
    },
  },
  presentationOptions: {
    actionDisplayName: 'PLACE_ORDER',
  },
  order: order,
}));
Node.JS anterior (v2)
conv.ask(new TransactionDecision({
  orderOptions: {
    requestDeliveryAddress: false,
  },
  paymentOptions: {
    googleProvidedOptions: {
      prepaidCardDisallowed: false,
      supportedCardNetworks: ['VISA', 'AMEX', 'DISCOVER', 'MASTERCARD'],
      tokenizationParameters: {
        tokenizationType: 'PAYMENT_GATEWAY',
        // These will be provided by payment processor,
        // like Stripe, Braintree, Vantiv, Ayden, etc.
        parameters: {
          'gateway': 'stripe',
          'stripe:publishableKey': (conv.sandbox ? 'pk_test_key' : 'pk_live_key'),
          'stripe:version': '2018-11-08'
        },
      },
    },
  },
  proposedOrder: order,
}));
JSON nuevo (v3)

Ten en cuenta que el siguiente JSON de Dialogflow describe una respuesta de webhook.

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "systemIntent": {
        "intent": "actions.intent.TRANSACTION_DECISION",
        "data": {
          "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec",
          "orderOptions": {
            "requestDeliveryAddress": "false"
          },
          "paymentParameters": {
            "googlePaymentOption": {
              "facilitationSpec": "{\"apiVersion\":2,\"apiVersionMinor\":0,\"merchantInfo\":{\"merchantName\":\"Example Merchant\"},\"allowedPaymentMethods\":[{\"type\":\"CARD\",\"parameters\":{\"allowedAuthMethods\":[\"PAN_ONLY\",\"CRYPTOGRAM_3DS\"],\"allowedCardNetworks\":[\"AMEX\",\"DISCOVER\",\"JCB\",\"MASTERCARD\",\"VISA\"]},\"tokenizationSpecification\":{\"type\":\"PAYMENT_GATEWAY\",\"parameters\":{\"gateway\":\"example\",\"gatewayMerchantId\":\"exampleGatewayMerchantId\"}}}],\"transactionInfo\":{\"totalPriceStatus\":\"FINAL\",\"totalPrice\":\"10.00\",\"currencyCode\":\"USD\"}}"
            }
          },
          "presentationOptions": {
            "actionDisplayName": "PLACE_ORDER"
          },
          "order": {
            "createTime": "2019-08-01T17:12:13.765Z",
            "lastUpdateTime": "2019-08-01T17:12:13.765Z",
            "merchantOrderId": "UNIQUE_ORDER_ID",
            "userVisibleOrderId": "USER_VISIBLE_ORDER_ID",
            "transactionMerchant": {
              "id": "http://www.example.com",
              "name": "Example Merchant"
            },
            "contents": {
              "lineItems": [
                {
                  "id": "LINE_ITEM_ID",
                  "name": "Pizza",
                  "description": "A four cheese pizza.",
                  "priceAttributes": [
                    {
                      "type": "REGULAR",
                      "name": "Line Item Price",
                      "state": "ACTUAL",
                      "amount": {
                        "currencyCode": "USD",
                        "amountInMicros": 8990000
                      },
                      "taxIncluded": true
                    }
                  ],
                  "notes": [
                    "Extra cheese."
                  ],
                  "purchase": {
                    "quantity": 1,
                    "unitMeasure": {
                      "measure": 1,
                      "unit": "POUND"
                    },
                    "itemOptions": [
                      {
                        "id": "ITEM_OPTION_ID",
                        "name": "Pepperoni",
                        "prices": [
                          {
                            "type": "REGULAR",
                            "state": "ACTUAL",
                            "name": "Item Price",
                            "amount": {
                              "currencyCode": "USD",
                              "amountInMicros": 1000000
                            },
                            "taxIncluded": true
                          }
                        ],
                        "note": "Extra pepperoni",
                        "quantity": 1,
                        "subOptions": []
                      }
                    ]
                  }
                }
              ]
            },
            "buyerInfo": {
              "email": "janedoe@gmail.com",
              "firstName": "Jane",
              "lastName": "Doe",
              "displayName": "Jane Doe"
            },
            "priceAttributes": [
              {
                "type": "TOTAL",
                "name": "Total Price",
                "state": "ESTIMATE",
                "amount": {
                  "currencyCode": "USD",
                  "amountInMicros": 15770000
                },
                "taxIncluded": true
              },
              {
                "type": "TAX",
                "name": "Tax",
                "state": "ESTIMATE",
                "amount": {
                  "currencyCode": "USD",
                  "amountInMicros": 3780000
                },
                "taxIncluded": true
              },
              {
                "type": "SUBTOTAL",
                "name": "Subtotal",
                "state": "ESTIMATE",
                "amount": {
                  "currencyCode": "USD",
                  "amountInMicros": 9990000
                },
                "taxIncluded": true
              },
              {
                "type": "DELIVERY",
                "name": "Delivery",
                "state": "ACTUAL",
                "amount": {
                  "currencyCode": "USD",
                  "amountInMicros": 2000000
                },
                "taxIncluded": true
              }
            ],
            "followUpActions": [
              {
                "type": "VIEW_DETAILS",
                "title": "View details",
                "openUrlAction": {
                  "url": "http://example.com"
                }
              },
              {
                "type": "CALL",
                "title": "Call us",
                "openUrlAction": {
                  "url": "tel:+16501112222"
                }
              },
              {
                "type": "EMAIL",
                "title": "Email us",
                "openUrlAction": {
                  "url": "mailto:person@example.com"
                }
              }
            ],
            "termsOfServiceUrl": "www.example.com",
            "note": "Sale event",
            "promotions": [
              {
                "coupon": "COUPON_CODE"
              }
            ],
            "purchase": {
              "status": "CREATED",
              "userVisibleStatusLabel": "CREATED",
              "type": "FOOD",
              "returnsInfo": {
                "isReturnable": false,
                "daysToReturn": 1,
                "policyUrl": "http://www.example.com"
              },
              "fulfillmentInfo": {
                "id": "FULFILLMENT_SERVICE_ID",
                "fulfillmentType": "DELIVERY",
                "expectedFulfillmentTime": {
                  "timeIso8601": "2017-01-16T01:30:15.01Z"
                },
                "location": {
                  "zipCode": "94086",
                  "city": "Sunnyvale",
                  "postalAddress": {
                    "regionCode": "US",
                    "postalCode": "94086",
                    "administrativeArea": "CA",
                    "locality": "Sunnyvale",
                    "addressLines": [
                      "222, Some other Street"
                    ]
                  }
                },
                "price": {
                  "type": "REGULAR",
                  "name": "Delivery Price",
                  "state": "ACTUAL",
                  "amount": {
                    "currencyCode": "USD",
                    "amountInMicros": 2000000
                  },
                  "taxIncluded": true
                },
                "fulfillmentContact": {
                  "email": "johnjohnson@gmail.com",
                  "firstName": "John",
                  "lastName": "Johnson",
                  "displayName": "John Johnson"
                }
              },
              "purchaseLocationType": "ONLINE_PURCHASE"
            }
          }
        }
      }
    }
  }
}
JSON anterior (v2)

Ten en cuenta que el siguiente JSON de Dialogflow describe una respuesta de webhook.

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "systemIntent": {
        "intent": "actions.intent.TRANSACTION_DECISION",
        "data": {
          "@type": "type.googleapis.com/google.actions.v2.TransactionDecisionValueSpec",
          "orderOptions": {
            "requestDeliveryAddress": false
          },
          "paymentOptions": {
            "googleProvidedOptions": {
              "prepaidCardDisallowed": false,
              "supportedCardNetworks": [
                "VISA",
                "AMEX",
                "DISCOVER",
                "MASTERCARD"
              ],
              "tokenizationParameters": {
                "tokenizationType": "PAYMENT_GATEWAY",
                "parameters": {
                  "gateway": "stripe",
                  "stripe:publishableKey": "pk_test_key",
                  "stripe:version": "2018-11-08"
                }
              }
            }
          },
          "proposedOrder": {
            "id": "UNIQUE_ORDER_ID222",
            "cart": {
              "merchant": {
                "id": "book_store_id",
                "name": "A Book Store"
              },
              "lineItems": [
                {
                  "name": "My Memoirs",
                  "id": "mymemoirs_id",
                  "price": {
                    "amount": {
                      "currencyCode": "USD",
                      "nanos": 990000000,
                      "units": 8
                    },
                    "type": "ACTUAL"
                  },
                  "quantity": 1,
                  "subLines": [
                    {
                      "note": "By Bestselling Novelist"
                    }
                  ],
                  "type": "REGULAR"
                },
                {
                  "name": "Biography",
                  "id": "biography_id",
                  "price": {
                    "amount": {
                      "currencyCode": "USD",
                      "nanos": 990000000,
                      "units": 10
                    },
                    "type": "ACTUAL"
                  },
                  "quantity": 1,
                  "subLines": [
                    {
                      "note": "Signed copy"
                    }
                  ],
                  "type": "REGULAR"
                }
              ],
              "notes": "Sale event",
              "otherItems": []
            },
            "otherItems": [
              {
                "name": "Subtotal",
                "id": "subtotal",
                "price": {
                  "amount": {
                    "currencyCode": "USD",
                    "nanos": 980000000,
                    "units": 19
                  },
                  "type": "ESTIMATE"
                },
                "type": "SUBTOTAL"
              },
              {
                "name": "Tax",
                "id": "tax",
                "price": {
                  "amount": {
                    "currencyCode": "USD",
                    "nanos": 780000000,
                    "units": 2
                  },
                  "type": "ESTIMATE"
                },
                "type": "TAX"
              }
            ],
            "totalPrice": {
              "amount": {
                "currencyCode": "USD",
                "nanos": 760000000,
                "units": 22
              },
              "type": "ESTIMATE"
            }
          }
        }
      }
    }
  }
}

4. Envía actualizaciones con la API de Orders

La versión 3 de la API de Orders controla las actualizaciones de pedidos, así que ya no tendrás que enviar solicitudes POST a la API de Actions En su lugar, debes enviar una solicitud PATCH a la API de Orders que actualiza los contenidos de tu objeto Order.

Cómo recuperar un nuevo token del portador

Puedes usar la misma clave de cuenta de servicio JSON que usaste para recuperar un para la API de Actions, debes solicitar un nuevo token del portador para la API de Orders. Intercambia tu clave de servicio por un token del portador con la biblioteca cliente de las APIs de Google y la interfaz "https://www.googleapis.com/auth/actions.order.developer" del proyecto.

Puedes encontrar los pasos de instalación y ejemplos en la página de GitHub de la biblioteca cliente de la API. También puedes hacer referencia al order-update.js actualizado en nuestra muestra de Node.js para ver un ejemplo de intercambio de claves de la API de Orders.

Enviar actualizaciones

El proceso de enviar la actualización de un pedido con la API de Orders es similar al de enviar con la API de Actions, aunque envías una solicitud PATCH en lugar de una solicitud POST. La solicitud PATCH debe tomar un cuerpo JSON de la con el siguiente formato:

{ "orderUpdate": OrderUpdate" }

El formato OrderUpdate también es diferente en la versión 3. Consulta la referencia de solicitud de PATCH. y actualiza tus campos OrderUpdate según corresponda. El siguiente fragmento de código se muestra un ejemplo de solicitud PATCH que actualiza el estado de un pedido a "DELIVERED":

Node.js
// Import the 'googleapis' module for authorizing the request.
const {google} = require('googleapis');
// Import the 'request' module for sending an HTTP POST request.
const request = require('request');
// Import the OrderUpdate class from the Actions on Google client library.
const {OrderUpdate} = require('actions-on-google');
// Import the service account key used to authorize the request. Replace the string path with a path to your service account key.
const key = require('./service-account.json');
// Create a new JWT client for the Actions API using credentials from the service account key.
let jwtClient = new google.auth.JWT(
    key.client_email,
    null,
    key.private_key,
    ['https://www.googleapis.com/auth/actions.order.developer'],
    null
);
// Authorize the client asynchronously, passing in a callback to run upon authorization.
jwtClient.authorize((err, tokens) => {
    if (err) {
        console.log(err);
        return;
    }
    // Declare the ID of the order to update.
    const orderId = '<UNIQUE_MERCHANT_ORDER_ID>';

    const orderUpdate = new OrderUpdate({
        updateMask: [
          'lastUpdateTime',
          'purchase.status',
          'purchase.userVisibleStatusLabel',
        ].join(','),
        order: {
          merchantOrderId: orderId,
          lastUpdateTime: new Date().toISOString(),
          purchase: {
            status: 'DELIVERED',
            userVisibleStatusLabel: 'Order delivered',
          },
        },
        reason: 'Order status updated to delivered.',
    });

    // Set up the PATCH request header and body, including the authorized token
    // and order update.
    const bearer = 'Bearer ' + tokens.access_token;
    const options = {
        method: 'PATCH',
        url: `https://actions.googleapis.com/v3/orders/${orderId}`,
        headers: {
          'Authorization': bearer,
        },
        body: {
          header: {
            'isInSandbox': true,
          },
          orderUpdate,
        },
        json: true,
      };
    // Send the PATCH request to the Orders API.
    request.patch(options, (err, httpResponse, body) => {
        if (err) {
            console.log('There was an error...');
            console.log(err);
            return;
        }
    });
});

Cómo controlar estados de pedidos adicionales

La versión 3 de la API de Orders admite valores de estado de pedidos adicionales. que no estaban disponibles en la versión 2. Deberías enviar actualizaciones del pedido para cada estado que sea relevante para cada transacción.

Los siguientes valores de estado son nuevos para la versión 3:

  • IN_PREPARATION: El pedido se está preparando para el envío o la entrega, por ejemplo, la comida. la cocción o el empaquetado de un artículo.
  • READY_FOR_PICKUP: El pedido está disponible para que el destinatario lo retire.
  • DELIVERED: El pedido se entregó al destinatario
  • OUT_OF_STOCK: Uno o más artículos del pedido están agotados.
  • CHANGE_REQUESTED: El usuario solicitó un cambio en el pedido, y el cambio se mientras se procesan.

El estado FULFILLED dejó de estar disponible y se reemplazó por DELIVERED.

Migra Java a v3

Sigue estos pasos para migrar una acción que use la biblioteca cliente de Java.

1. Actualiza la estructura de tu carrito

El ProposedOrder se reemplazó el tipo de elemento por el Order, que es más detallado. . Consulta la referencia de JSON para convertir tu carrito de ProposedOrder en un carrito de Order.

2. Actualiza los parámetros de pago

La estructura de la información de pago en el paso de propuesta de pedido es diferente entre las versiones de la API.

En la solicitud de intent actions.intent.TRANSACTION_DECISION, reemplaza el anterior Un objeto paymentOptions con el nuevo objeto paymentParameters. La mayoría de todos los campos contenidos son los mismos, guarde algunos cambios en el archivo JSON en la nube.

En los siguientes fragmentos de código, se muestra un ejemplo de actions.intent.TRANSACTION_DECISION intent de Google Pay con la versión 3 y una solicitud de versión 2 anterior para comparación.

Java (v3)
// Create order options
OrderOptionsV3 orderOptions = new OrderOptionsV3()
    .setRequestDeliveryAddress(false)
    .setUserInfoOptions(new UserInfoOptions()
        .setUserInfoProperties(Collections.singletonList("EMAIL")));

// Create presentation options
PresentationOptionsV3 presentationOptions = new PresentationOptionsV3()
    .setActionDisplayName("PLACE_ORDER");

// Create payment parameters
JSONObject merchantInfo = new JSONObject();
merchantInfo.put("merchantName", "Example Merchant");

JSONObject facilitationSpec = new JSONObject();
facilitationSpec.put("apiVersion", 2);
facilitationSpec.put("apiVersionMinor", 0);
facilitationSpec.put("merchantInfo", merchantInfo);

JSONObject allowedPaymentMethod = new JSONObject();
allowedPaymentMethod.put("type", "CARD");

JSONArray allowedAuthMethods = new JSONArray();
allowedAuthMethods.addAll(Arrays.asList("PAN_ONLY", "CRYPTOGRAM_3DS"));
JSONArray allowedCardNetworks = new JSONArray();
allowedCardNetworks.addAll(Arrays.asList("AMEX", "DISCOVER", "JCB", "MASTERCARD", "VISA"));

JSONObject allowedPaymentMethodParameters = new JSONObject();
allowedPaymentMethodParameters.put("allowedAuthMethods", allowedAuthMethods);
allowedPaymentMethodParameters.put("allowedCardNetworks", allowedCardNetworks);

allowedPaymentMethod.put("parameters", allowedPaymentMethodParameters);

JSONObject tokenizationSpecificationParameters = new JSONObject();
tokenizationSpecificationParameters.put("gateway", "example");
tokenizationSpecificationParameters.put("gatewayMerchantId", "exampleGatewayMerchantId");

JSONObject tokenizationSpecification = new JSONObject();
tokenizationSpecification.put("type", "PAYMENT_GATEWAY");
tokenizationSpecification.put("parameters", tokenizationSpecificationParameters);
allowedPaymentMethod.put("tokenizationSpecification", tokenizationSpecification);

JSONArray allowedPaymentMethods = new JSONArray();
allowedPaymentMethods.add(allowedPaymentMethod);

facilitationSpec.put("allowedPaymentMethods", allowedPaymentMethods);

JSONObject transactionInfo = new JSONObject();
transactionInfo.put("totalPriceStatus", "FINAL");
transactionInfo.put("totalPrice", "10.00");
transactionInfo.put("currencyCode", "USD");

facilitationSpec.put("transactionInfo", transactionInfo);

GooglePaymentOption googlePaymentOption = new GooglePaymentOption()
    .setFacilitationSpec(facilitationSpec.toJSONString());

PaymentParameters paymentParameters = new PaymentParameters()
    .setGooglePaymentOption(googlePaymentOption);

// Ask for transaction decision
return getResponseBuilder(request)
    .add("Placeholder for transaction decision text")
    .add(new TransactionDecision()
        .setOrder(order)
        .setOrderOptions(orderOptions)
        .setPresentationOptions(presentationOptions)
        .setPaymentParameters(paymentParameters)
    )
    .build();
Java anterior (v2)
OrderOptions orderOptions;
PaymentOptions paymentOptions;

// Setup Google provided payment options
Map<String, String> parameters = new HashMap<>();
parameters.put("gateway", "stripe");
parameters.put("stripe:publishableKey", request.isInSandbox() ? "pk_test_key" : "pk_live_key");
parameters.put("stripe:version", "2017-04-06");
PaymentMethodTokenizationParameters tokenizationParameters =
    new PaymentMethodTokenizationParameters()
        .setTokenizationType("PAYMENT_GATEWAY")
        .setParameters(parameters);
orderOptions = new OrderOptions().setRequestDeliveryAddress(false);
GoogleProvidedPaymentOptions googleProvidedPaymentOptions =
    new GoogleProvidedPaymentOptions()
        .setPrepaidCardDisallowed(false)
        .setSupportedCardNetworks(Arrays.asList("VISA", "AMEX"))
        .setTokenizationParameters(tokenizationParameters);
paymentOptions = new PaymentOptions().setGoogleProvidedOptions(googleProvidedPaymentOptions);

return getResponseBuilder(request)
    .add("Placeholder for transaction decision text")
    .add(
        new TransactionDecision()
            .setOrderOptions(orderOptions)
            .setPaymentOptions(paymentOptions)
            .setProposedOrder(proposedOrder))
    .build();
JSON nuevo (v3)

Ten en cuenta que el siguiente JSON de Dialogflow describe una respuesta de webhook.

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "systemIntent": {
        "intent": "actions.intent.TRANSACTION_DECISION",
        "data": {
          "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec",
          "orderOptions": {
            "requestDeliveryAddress": "false"
          },
          "paymentParameters": {
            "googlePaymentOption": {
              "facilitationSpec": "{\"apiVersion\":2,\"apiVersionMinor\":0,\"merchantInfo\":{\"merchantName\":\"Example Merchant\"},\"allowedPaymentMethods\":[{\"type\":\"CARD\",\"parameters\":{\"allowedAuthMethods\":[\"PAN_ONLY\",\"CRYPTOGRAM_3DS\"],\"allowedCardNetworks\":[\"AMEX\",\"DISCOVER\",\"JCB\",\"MASTERCARD\",\"VISA\"]},\"tokenizationSpecification\":{\"type\":\"PAYMENT_GATEWAY\",\"parameters\":{\"gateway\":\"example\",\"gatewayMerchantId\":\"exampleGatewayMerchantId\"}}}],\"transactionInfo\":{\"totalPriceStatus\":\"FINAL\",\"totalPrice\":\"10.00\",\"currencyCode\":\"USD\"}}"
            }
          },
          "presentationOptions": {
            "actionDisplayName": "PLACE_ORDER"
          },
          "order": {
            "createTime": "2019-08-01T17:12:13.765Z",
            "lastUpdateTime": "2019-08-01T17:12:13.765Z",
            "merchantOrderId": "UNIQUE_ORDER_ID",
            "userVisibleOrderId": "USER_VISIBLE_ORDER_ID",
            "transactionMerchant": {
              "id": "http://www.example.com",
              "name": "Example Merchant"
            },
            "contents": {
              "lineItems": [
                {
                  "id": "LINE_ITEM_ID",
                  "name": "Pizza",
                  "description": "A four cheese pizza.",
                  "priceAttributes": [
                    {
                      "type": "REGULAR",
                      "name": "Line Item Price",
                      "state": "ACTUAL",
                      "amount": {
                        "currencyCode": "USD",
                        "amountInMicros": 8990000
                      },
                      "taxIncluded": true
                    }
                  ],
                  "notes": [
                    "Extra cheese."
                  ],
                  "purchase": {
                    "quantity": 1,
                    "unitMeasure": {
                      "measure": 1,
                      "unit": "POUND"
                    },
                    "itemOptions": [
                      {
                        "id": "ITEM_OPTION_ID",
                        "name": "Pepperoni",
                        "prices": [
                          {
                            "type": "REGULAR",
                            "state": "ACTUAL",
                            "name": "Item Price",
                            "amount": {
                              "currencyCode": "USD",
                              "amountInMicros": 1000000
                            },
                            "taxIncluded": true
                          }
                        ],
                        "note": "Extra pepperoni",
                        "quantity": 1,
                        "subOptions": []
                      }
                    ]
                  }
                }
              ]
            },
            "buyerInfo": {
              "email": "janedoe@gmail.com",
              "firstName": "Jane",
              "lastName": "Doe",
              "displayName": "Jane Doe"
            },
            "priceAttributes": [
              {
                "type": "TOTAL",
                "name": "Total Price",
                "state": "ESTIMATE",
                "amount": {
                  "currencyCode": "USD",
                  "amountInMicros": 15770000
                },
                "taxIncluded": true
              },
              {
                "type": "TAX",
                "name": "Tax",
                "state": "ESTIMATE",
                "amount": {
                  "currencyCode": "USD",
                  "amountInMicros": 3780000
                },
                "taxIncluded": true
              },
              {
                "type": "SUBTOTAL",
                "name": "Subtotal",
                "state": "ESTIMATE",
                "amount": {
                  "currencyCode": "USD",
                  "amountInMicros": 9990000
                },
                "taxIncluded": true
              },
              {
                "type": "DELIVERY",
                "name": "Delivery",
                "state": "ACTUAL",
                "amount": {
                  "currencyCode": "USD",
                  "amountInMicros": 2000000
                },
                "taxIncluded": true
              }
            ],
            "followUpActions": [
              {
                "type": "VIEW_DETAILS",
                "title": "View details",
                "openUrlAction": {
                  "url": "http://example.com"
                }
              },
              {
                "type": "CALL",
                "title": "Call us",
                "openUrlAction": {
                  "url": "tel:+16501112222"
                }
              },
              {
                "type": "EMAIL",
                "title": "Email us",
                "openUrlAction": {
                  "url": "mailto:person@example.com"
                }
              }
            ],
            "termsOfServiceUrl": "www.example.com",
            "note": "Sale event",
            "promotions": [
              {
                "coupon": "COUPON_CODE"
              }
            ],
            "purchase": {
              "status": "CREATED",
              "userVisibleStatusLabel": "CREATED",
              "type": "FOOD",
              "returnsInfo": {
                "isReturnable": false,
                "daysToReturn": 1,
                "policyUrl": "http://www.example.com"
              },
              "fulfillmentInfo": {
                "id": "FULFILLMENT_SERVICE_ID",
                "fulfillmentType": "DELIVERY",
                "expectedFulfillmentTime": {
                  "timeIso8601": "2017-01-16T01:30:15.01Z"
                },
                "location": {
                  "zipCode": "94086",
                  "city": "Sunnyvale",
                  "postalAddress": {
                    "regionCode": "US",
                    "postalCode": "94086",
                    "administrativeArea": "CA",
                    "locality": "Sunnyvale",
                    "addressLines": [
                      "222, Some other Street"
                    ]
                  }
                },
                "price": {
                  "type": "REGULAR",
                  "name": "Delivery Price",
                  "state": "ACTUAL",
                  "amount": {
                    "currencyCode": "USD",
                    "amountInMicros": 2000000
                  },
                  "taxIncluded": true
                },
                "fulfillmentContact": {
                  "email": "johnjohnson@gmail.com",
                  "firstName": "John",
                  "lastName": "Johnson",
                  "displayName": "John Johnson"
                }
              },
              "purchaseLocationType": "ONLINE_PURCHASE"
            }
          }
        }
      }
    }
  }
}
JSON anterior (v2)

Ten en cuenta que el siguiente JSON de Dialogflow describe una respuesta de webhook.

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "systemIntent": {
        "intent": "actions.intent.TRANSACTION_DECISION",
        "data": {
          "@type": "type.googleapis.com/google.actions.v2.TransactionDecisionValueSpec",
          "orderOptions": {
            "requestDeliveryAddress": false
          },
          "paymentOptions": {
            "googleProvidedOptions": {
              "prepaidCardDisallowed": false,
              "supportedCardNetworks": [
                "VISA",
                "AMEX",
                "DISCOVER",
                "MASTERCARD"
              ],
              "tokenizationParameters": {
                "tokenizationType": "PAYMENT_GATEWAY",
                "parameters": {
                  "gateway": "stripe",
                  "stripe:publishableKey": "pk_test_key",
                  "stripe:version": "2018-11-08"
                }
              }
            }
          },
          "proposedOrder": {
            "id": "UNIQUE_ORDER_ID222",
            "cart": {
              "merchant": {
                "id": "book_store_id",
                "name": "A Book Store"
              },
              "lineItems": [
                {
                  "name": "My Memoirs",
                  "id": "mymemoirs_id",
                  "price": {
                    "amount": {
                      "currencyCode": "USD",
                      "nanos": 990000000,
                      "units": 8
                    },
                    "type": "ACTUAL"
                  },
                  "quantity": 1,
                  "subLines": [
                    {
                      "note": "By Bestselling Novelist"
                    }
                  ],
                  "type": "REGULAR"
                },
                {
                  "name": "Biography",
                  "id": "biography_id",
                  "price": {
                    "amount": {
                      "currencyCode": "USD",
                      "nanos": 990000000,
                      "units": 10
                    },
                    "type": "ACTUAL"
                  },
                  "quantity": 1,
                  "subLines": [
                    {
                      "note": "Signed copy"
                    }
                  ],
                  "type": "REGULAR"
                }
              ],
              "notes": "Sale event",
              "otherItems": []
            },
            "otherItems": [
              {
                "name": "Subtotal",
                "id": "subtotal",
                "price": {
                  "amount": {
                    "currencyCode": "USD",
                    "nanos": 980000000,
                    "units": 19
                  },
                  "type": "ESTIMATE"
                },
                "type": "SUBTOTAL"
              },
              {
                "name": "Tax",
                "id": "tax",
                "price": {
                  "amount": {
                    "currencyCode": "USD",
                    "nanos": 780000000,
                    "units": 2
                  },
                  "type": "ESTIMATE"
                },
                "type": "TAX"
              }
            ],
            "totalPrice": {
              "amount": {
                "currencyCode": "USD",
                "nanos": 760000000,
                "units": 22
              },
              "type": "ESTIMATE"
            }
          }
        }
      }
    }
  }
}

3. Envía actualizaciones con la API de Orders

La versión 3 de la API de Orders controla las actualizaciones de pedidos, así que ya no tendrás que enviar solicitudes POST a la API de Actions En su lugar, debes enviar una solicitud PATCH a la API de Orders que actualiza los contenidos de tu objeto Order.

Cómo recuperar un nuevo token del portador

Puedes usar la misma clave de cuenta de servicio JSON que usaste para recuperar un para la API de Actions, debes solicitar un nuevo token del portador para la API de Orders. Intercambia tu clave de servicio por un token del portador con la biblioteca cliente de las APIs de Google y la interfaz &quot;https://www.googleapis.com/auth/actions.order.developer&quot; del proyecto.

Puedes encontrar los pasos de instalación y ejemplos en la página de GitHub de la biblioteca cliente de la API. También puedes hacer referencia al order-update.js actualizado en nuestra muestra de Java para ver un ejemplo de intercambio de claves de la API de Orders.

Enviar actualizaciones

El proceso de enviar la actualización de un pedido con la API de Orders es similar al de enviar con la API de Actions, aunque envías una solicitud PATCH en lugar de una solicitud POST. La solicitud PATCH debe tomar un cuerpo JSON de la con el siguiente formato:

{ "orderUpdate": OrderUpdate" }

El formato OrderUpdate también es diferente en la versión 3. Consulta la referencia de solicitud de PATCH. y actualiza tus campos OrderUpdate según corresponda. El siguiente fragmento de código se muestra un ejemplo de solicitud PATCH que actualiza el estado de un pedido a "DELIVERED":

Java
// Create order update
FieldMask fieldMask = FieldMask.newBuilder().addAllPaths(Arrays.asList(
    "last_update_time",
    "purchase.status",
    "purchase.userVisibleStatusLabel"))
    .build();

OrderUpdateV3 orderUpdate = new OrderUpdateV3()
    .setOrder(new OrderV3()
        .setMerchantOrderId(orderId)
        .setLastUpdateTime(Instant.now().toString())
        .setPurchase(new PurchaseOrderExtension()
            .setStatus("DELIVERED")
            .setUserVisibleStatusLabel("Order delivered.")))
    .setUpdateMask(FieldMaskUtil.toString(fieldMask))
    .setReason("Order status was updated to delivered.");

// Setup JSON body containing order update
JsonParser parser = new JsonParser();
JsonObject orderUpdateJson =
    parser.parse(new Gson().toJson(orderUpdate)).getAsJsonObject();
JsonObject body = new JsonObject();
body.add("orderUpdate", orderUpdateJson);
JsonObject header = new JsonObject();
header.addProperty("isInSandbox", true);
body.add("header", header);
StringEntity entity = new StringEntity(body.toString());
entity.setContentType(ContentType.APPLICATION_JSON.getMimeType());
request.setEntity(entity);

// Make request
HttpClient httpClient = HttpClientBuilder.create().build();
HttpResponse response = httpClient.execute(request);

Cómo controlar estados de pedidos adicionales

La versión 3 de la API de Orders admite valores de estado de pedidos adicionales. que no estaban disponibles en la versión 2. Deberías enviar actualizaciones del pedido para cada estado que sea relevante para cada transacción.

Los siguientes valores de estado son nuevos para la versión 3:

  • IN_PREPARATION: El pedido se está preparando para el envío o la entrega, por ejemplo, la comida. la cocción o el empaquetado de un artículo.
  • READY_FOR_PICKUP: El pedido está disponible para que el destinatario lo retire.
  • DELIVERED: El pedido se entregó al destinatario
  • OUT_OF_STOCK: Uno o más artículos del pedido están agotados.
  • CHANGE_REQUESTED: El usuario solicitó un cambio en el pedido, y el cambio se mientras se procesan.

El estado FULFILLED dejó de estar disponible y se reemplazó por DELIVERED.