יצירת הזמנות (Dialogflow)

המדריך הזה ידריך אתכם בתהליך הפיתוח של פרויקט פעולה שמשתמש ב-Orders API לביצוע הזמנות.

תהליך העסקה

כשהפרויקט 'פעולות' מטפל בהזמנות, משתמשת בתהליך הבא:

  1. אימות הדרישות לגבי עסקאות (אופציונלי) – היעזרו בתוכן העזר בנושא דרישות לעסקאות בתחילת השיחה, כדי לוודא שהמשתמש יכול ביצוע עסקה.
  2. הכנת ההזמנה – הדרכת המשתמש "הרכבת עגלת קניות" שבו הם יוצרים את פרטי ההזמנה שלהם.
  3. הצעת ההזמנה – ברגע שה'עגלת קניות' הושלם, הצעת ה'הזמנה' של ההזמנה אל למשתמש, כדי שיוכלו לאשר שהיא נכונה. אם ההזמנה תאושר, לקבל תשובה עם פרטי ההזמנה.
  4. השלמת ההזמנה ושליחת קבלה – לאחר שההזמנה אושרה, מעדכנים אותה מערכת ההזמנות שלך ושליחת קבלה למשתמש.
  5. שליחת עדכונים לגבי הזמנות – במהלך משך החיים של ההזמנה, לעדכן את סטטוס ההזמנות של המשתמשים על ידי שליחת בקשות PATCH Orders API.

הנחיות בנושא הגבלות ובדיקה

חשוב לזכור שכללי מדיניות נוספים חלים על פעולות שמשתמשות ב-טרנזקציות וב-Orders API. תהליך הבדיקה של פעולות עם עסקאות עשוי להימשך עד שישה שבועות, לכן חשוב לקחת את הזמן הזה בחשבון כשמתכננים את לוח הזמנים לפרסום. כדי לקצר את תהליך הבדיקה, חשוב להקפיד לפעול בהתאם למדיניות ולהנחיות בנושא עסקאות לפני שליחת הפעולה לבדיקה.

אפשר לפרוס פעולות שמשתמשות ב-Orders API רק במדינות הבאות:

אוסטרליה
ברזיל
קנדה
אינדונזיה
יפן
מקסיקו
קטאר
רוסיה
סינגפור
שווייץ
תאילנד
טורקיה
בריטניה
ארצות הברית

בניית הפרויקט

תוכלו למצוא דוגמאות נרחבות לשיחות שקשורות לטרנזקציות ב-Node.js וב-Java.

הגדרת פרויקט

כשיוצרים את הפעולה, צריך לציין שרוצים לבצע עסקאות במסוף Actions. כמו כן, אם באמצעות ספריית הלקוח של Node.JS, מגדירים את מילוי ההזמנות כך שישתמשו של ה-Orders API.

כדי להגדיר את הפרויקט ואת מילוי ההזמנות:

  1. יוצרים פרויקט חדש או מייבאים פרויקט קיים.
  2. עוברים אל Deploy > (פריסה) >. פרטי הספרייה.
  3. בקטע מידע נוסף > עסקאות > מסמנים את התיבה שבה כתוב "ביצוע הפעולות שלך" להשתמש ב-Transactions API כדי לבצע עסקאות של מוצרים פיזיים?".

  4. אם אתם משתמשים בספריית הלקוח של Node.JS כדי ליצור את מילוי ההזמנות של הפעולה, לפתוח את קוד האספקה ולעדכן את הגבלת הגישה לאפליקציה כדי להגדיר סימון ordersv3 לערך true. קטע הקוד הבא מציג אפליקציה לדוגמה הצהרה לגרסה 3 של הזמנות.

Node.js

const {dialogflow} = require('actions-on-google');
let app = dialogflow({
  clientId, // If using account linking
  debug: true,
  ordersv3: true,
});

Node.js

const {actionssdk} = require('actions-on-google');
let app = actionssdk({
  clientId, // If using account linking
  debug: true,
  ordersv3: true,
});

1. אימות הדרישות לקבלת עסקאות (אופציונלי)

חוויית משתמש

לאחר שהמשתמש ציין שהוא רוצה לבצע הזמנה, מומלץ להפעיל את כוונה של actions.intent.TRANSACTION_REQUIREMENTS_CHECK כדי להבטיח שהם לבקש הזמנה. לדוגמה, כשהיא תופעל, הפעולה עשויה לשאול, "רוצה לשמור מקום?" אם המשתמש אומר "כן", עליכם לבקש את הכוונה הזו באופן מיידי. הפעולה הזו תבטיח שהם יוכלו להמשיך ולתת להם הזדמנות לתקן הגדרות כלשהן. ולכן הוא לא יוכל להמשיך בביצוע העסקה.

בקשת העסקאות כשבודקים את כוונת הרכישה לפי הדרישות, מתקבלות אחת מהתוצאות הבאות:

  • אם הדרישות מתקיימות, מילוי הבקשה יקבל Intent עם כדי שתוכלו להמשיך בבניית ההזמנה של המשתמש.
  • אם לא תעמדו באחת או יותר מהדרישות, מילוי ההזמנה יקבל את Intent עם תנאי של כשל. במקרה כזה, צריך לסיים את השיחה, או מעבר לתהליך ההזמנה.

    אם המשתמש יכול לתקן את השגיאה, הוא יתבקש באופן אוטומטי לפתור את הבעיות האלה. במכשיר שלהם. אם השיחה מתקיימת בפלטפורמה של קול בלבד כמו רמקול חכם, הוא מועבר לטלפון של המשתמש.

טיפול בהזמנות

כדי לוודא שמשתמש עומד ללקוחות, בקשה למלא את Intent של actions.intent.TRANSACTION_REQUIREMENTS_CHECK עם אובייקט TransactionRequirementsCheckSpec.

בדיקת הדרישות

בודקים אם משתמש עומד בדרישות לביצוע הזמנה בספריית הלקוח:

Node.js
conv.ask(new TransactionRequirements());
Java
return getResponseBuilder(request)
    .add("Placeholder for transaction requirements text")
    .add(new TransactionRequirements())
    .build();
קובץ JSON של Dialogflow

הערה: קובץ ה-JSON שבהמשך מתאר תגובת webhook.

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "systemIntent": {
        "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK",
        "data": {
          "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec"
        }
      }
    }
  }
}
JSON עם SDK לפעולות

הערה: קובץ ה-JSON שבהמשך מתאר תגובת webhook.

{
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "possibleIntents": [
        {
          "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK",
          "inputValueData": {
            "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec"
          }
        }
      ]
    }
  ]
}
קבלת התוצאה של בדיקת דרישות

אחרי ש-Assistant מגשים את הכוונה, היא שולחת בקשה למילוי הזמנות עם ה-Intent actions.intent.TRANSACTION_REQUIREMENTS_CHECK עם התוצאה של הבדיקה.

כדי לטפל כראוי בבקשה הזו, צריך להצהיר על Intent ב-Dialogflow שמופעל על ידי האירוע actions_intent_TRANSACTION_REQUIREMENTS_CHECK. כשההגדרה מופעלת, צריך ליישם את הכוונה הזו בתהליך:

Node.js
const arg = conv.arguments.get('TRANSACTION_REQUIREMENTS_CHECK_RESULT');
if (arg && arg.resultType === 'CAN_TRANSACT') {
  // Normally take the user through cart building flow
  conv.ask(`Looks like you're good to go!`);
} else {
  conv.close('Transaction failed.');
}
Java
Argument transactionCheckResult = request
    .getArgument("TRANSACTION_REQUIREMENTS_CHECK_RESULT");
boolean result = false;
if (transactionCheckResult != null) {
  Map<String, Object> map = transactionCheckResult.getExtension();
  if (map != null) {
    String resultType = (String) map.get("resultType");
    result = resultType != null && resultType.equals("CAN_TRANSACT");
  }
}
ResponseBuilder responseBuilder = getResponseBuilder(request);
if (result) {
  responseBuilder.add("Looks like you're good to go! Now say 'confirm transaction'");
} else {
  responseBuilder.add("Transaction failed");
}
return responseBuilder.build();
קובץ JSON של Dialogflow

הערה: קובץ ה-JSON שבהמשך מתאר בקשת webhook.

{
  "responseId": "",
  "queryResult": {
    "queryText": "",
    "action": "",
    "parameters": {},
    "allRequiredParamsPresent": true,
    "fulfillmentText": "",
    "fulfillmentMessages": [],
    "outputContexts": [],
    "intent": {
      "name": "reservation_transaction_check_complete_df",
      "displayName": "reservation_transaction_check_complete_df"
    },
    "intentDetectionConfidence": 1,
    "diagnosticInfo": {},
    "languageCode": ""
  },
  "originalDetectIntentRequest": {
    "source": "google",
    "version": "2",
    "payload": {
      "isInSandbox": true,
      "surface": {
        "capabilities": [
          {
            "name": "actions.capability.SCREEN_OUTPUT"
          },
          {
            "name": "actions.capability.AUDIO_OUTPUT"
          },
          {
            "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
          },
          {
            "name": "actions.capability.WEB_BROWSER"
          }
        ]
      },
      "inputs": [
        {
          "rawInputs": [],
          "intent": "",
          "arguments": [
            {
              "extension": {
                "@type": "type.googleapis.com/google.transactions.v3.TransactionRequirementsCheckResult",
                "resultType": "CAN_TRANSACT"
              },
              "name": "TRANSACTION_REQUIREMENTS_CHECK_RESULT"
            }
          ]
        }
      ],
      "user": {},
      "conversation": {},
      "availableSurfaces": [
        {
          "capabilities": [
            {
              "name": "actions.capability.SCREEN_OUTPUT"
            },
            {
              "name": "actions.capability.AUDIO_OUTPUT"
            },
            {
              "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
            },
            {
              "name": "actions.capability.WEB_BROWSER"
            }
          ]
        }
      ]
    }
  },
  "session": ""
}
JSON עם SDK לפעולות

הערה: קובץ ה-JSON שבהמשך מתאר בקשת webhook.

{
  "user": {},
  "device": {},
  "surface": {
    "capabilities": [
      {
        "name": "actions.capability.SCREEN_OUTPUT"
      },
      {
        "name": "actions.capability.AUDIO_OUTPUT"
      },
      {
        "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
      },
      {
        "name": "actions.capability.WEB_BROWSER"
      }
    ]
  },
  "conversation": {},
  "inputs": [
    {
      "rawInputs": [],
      "intent": "reservation_transaction_check_complete_asdk",
      "arguments": [
        {
          "extension": {
            "@type": "type.googleapis.com/google.transactions.v3.TransactionRequirementsCheckResult",
            "resultType": "CAN_TRANSACT"
          },
          "name": "TRANSACTION_REQUIREMENTS_CHECK_RESULT"
        }
      ]
    }
  ],
  "availableSurfaces": [
    {
      "capabilities": [
        {
          "name": "actions.capability.SCREEN_OUTPUT"
        },
        {
          "name": "actions.capability.AUDIO_OUTPUT"
        },
        {
          "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
        },
        {
          "name": "actions.capability.WEB_BROWSER"
        }
      ]
    }
  ]
}

2. יצירת ההזמנה

חוויית משתמש

ברגע שקיבלת את פרטי המשתמש הדרושים לך, צרו 'עגלת קניות' assembly" שמנחה את המשתמשים לבנות את ההזמנה שלהם. הכול תהליך הרכבת עגלת הקניות של הפעולה יהיה שונה מעט, בהתאם לאחר השיפור.

בחוויית ההרכבה הבסיסית של עגלת הקניות, המשתמש בוחר אפשרויות מתוך רשימה להוספה להזמנה שלהם, למרות שתוכלו לתכנן את השיחה כדי לפשט את חוויית המשתמש. לדוגמה, לבנות חוויה של הרכבה של עגלת קניות שמאפשרת משתמש לקבוע הזמנה חודשית עם שאלה פשוטה של כן או לא. אפשר גם להציג למשתמש קרוסלה או כרטיס רשימה עם התווית 'מומלץ'. הזמנות.

מומלץ להשתמש בטקסט עשיר תגובות להצגת האפשרויות למשתמש חזותית, אלא גם לעצב את השיחה כך שהמשתמש יוכל לבנות באמצעות הקול בלבד. לקבלת כמה שיטות מומלצות ודוגמאות בהנחיות לעיצוב עסקאות.

טיפול בהזמנות

במהלך השיחה, אוספים את פרטי ההזמנה שהמשתמש רוצה כדי לרכוש ואז ליצור אובייקט Order.

השדה Order חייב להכיל לפחות את הפריטים הבאים:

  • buyerInfo - מידע על המשתמש שקבע את ההזמנה.
  • transactionMerchant – מידע על המוֹכר שנותן מענה את ההזמנה.
  • contents - הפרטים בפועל של ההזמנה שרשומים כ-lineItems.

אפשר לעיין במסמכי העזרה בנושא תשובות של Order כדי ליצור את עגלת הקניות. לתשומת ליבכם: יכול להיות שתצטרכו לכלול שדות אחרים. בהתאם להזמנה.

הקוד לדוגמה הבא מציג הזמנת הזמנה מלאה, כולל שדות אופציונליים:

Node.js
app.intent('build_reservation_df', (conv) => {
  const now = new Date().toISOString();
  const order = {
    createTime: now,
    lastUpdateTime: now,
    merchantOrderId: 'UNIQUE_ORDER_ID',
    userVisibleOrderId: 'USER_VISIBLE_ORDER_ID',
    transactionMerchant: {
      id: 'https://www.example.com',
      name: 'Example Merchant',
    },
    contents: {
      lineItems: [
        {
          id: 'LINE_ITEM_ID',
          name: 'Dinner reservation',
          description: 'A world of flavors all in one destination.',
          reservation: {
            status: 'PENDING',
            userVisibleStatusLabel: 'Reservation is pending.',
            type: 'RESTAURANT',
            reservationTime: {
              timeIso8601: '2020-01-16T01:30:15.01Z',
            },
            userAcceptableTimeRange: {
              timeIso8601: '2020-01-15/2020-01-17',
            },
            partySize: 6,
            staffFacilitators: [
              {
                name: 'John Smith',
              },
            ],
            location: {
              zipCode: '94086',
              city: 'Sunnyvale',
              postalAddress: {
                regionCode: 'US',
                postalCode: '94086',
                administrativeArea: 'CA',
                locality: 'Sunnyvale',
                addressLines: [
                  '222, Some other Street',
                ],
              },
            },
          },
        },
      ],
    },
    buyerInfo: {
      email: 'janedoe@gmail.com',
      firstName: 'Jane',
      lastName: 'Doe',
      displayName: 'Jane Doe',
    },
    followUpActions: [
      {
        type: 'VIEW_DETAILS',
        title: 'View details',
        openUrlAction: {
          url: 'https://example.com',
        },
      },
      {
        type: 'CALL',
        title: 'Call us',
        openUrlAction: {
          url: 'tel:+16501112222',
        },
      },
      {
        type: 'EMAIL',
        title: 'Email us',
        openUrlAction: {
          url: 'mailto:person@example.com',
        },
      },
    ],
    termsOfServiceUrl: 'https://www.example.com',
  };
Java
private static OrderV3 createOrder() {
  // Transaction Merchant
  MerchantV3 transactionMerchant = new MerchantV3()
      .setId("http://www.example.com")
      .setName("Example Merchant");

  // Line Item

  // Reservation Item Extension
  ReservationItemExtension reservationItemExtension = new ReservationItemExtension()
      .setStatus("PENDING")
      .setUserVisibleStatusLabel("Reservation pending.")
      .setType("RESTAURANT")
      .setReservationTime(new TimeV3()
          .setTimeIso8601("2020-01-16T01:30:15.01Z"))
      .setUserAcceptableTimeRange(new TimeV3()
          .setTimeIso8601("2020-01-15/2020-01-17"))
      .setPartySize(6)
      .setStaffFacilitators(Collections.singletonList(new StaffFacilitator()
          .setName("John Smith")))
      .setLocation(new Location()
          .setZipCode("94086")
          .setCity("Sunnyvale")
          .setPostalAddress(new PostalAddress()
              .setRegionCode("US")
              .setPostalCode("94086")
              .setAdministrativeArea("CA")
              .setLocality("Sunnyvale")
              .setAddressLines(
                  Collections.singletonList("222, Some other Street"))));

  LineItemV3 lineItem = new LineItemV3()
      .setId("LINE_ITEM_ID")
      .setName("Dinner reservation")
      .setDescription("A world of flavors all in one destination.")
      .setReservation(reservationItemExtension);

  // Order Contents
  OrderContents contents = new OrderContents()
      .setLineItems(Collections.singletonList(lineItem));

  // User Info
  UserInfo buyerInfo = new UserInfo()
      .setEmail("janedoe@gmail.com")
      .setFirstName("Jane")
      .setLastName("Doe")
      .setDisplayName("Jane Doe");

  // Follow up actions
  Action viewDetails = new Action()
      .setType("VIEW_DETAILS")
      .setTitle("View details")
      .setOpenUrlAction(new OpenUrlAction()
          .setUrl("https://example.com"));

  Action call = new Action()
      .setType("CALL")
      .setTitle("Call us")
      .setOpenUrlAction(new OpenUrlAction()
          .setUrl("tel:+16501112222"));

  Action email = new Action()
      .setType("EMAIL")
      .setTitle("Email us")
      .setOpenUrlAction(new OpenUrlAction()
          .setUrl("mailto:person@example.com"));

  // Terms of service and order note
  String termsOfServiceUrl = "https://example.com";

  String now = Instant.now().toString();

  OrderV3 order = new OrderV3()
      .setCreateTime(now)
      .setLastUpdateTime(now)
      .setMerchantOrderId("UNIQUE_ORDER_ID")
      .setUserVisibleOrderId("UNIQUE_USER_VISIBLE_ORDER_ID")
      .setTransactionMerchant(transactionMerchant)
      .setContents(contents)
      .setBuyerInfo(buyerInfo)
      .setFollowUpActions(Arrays.asList(
          viewDetails,
          call,
          email
      ))
      .setTermsOfServiceUrl(termsOfServiceUrl);

  return order;
}
JSON

הערה: קובץ ה-JSON שבהמשך מתאר תגובת webhook.

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "systemIntent": {
        "intent": "actions.intent.TRANSACTION_DECISION",
        "data": {
          "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec",
          "order": {
            "createTime": "2019-07-17T18:25:30.182Z",
            "lastUpdateTime": "2019-07-17T18:25:30.182Z",
            "merchantOrderId": "UNIQUE_ORDER_ID",
            "userVisibleOrderId": "USER_VISIBLE_ORDER_ID",
            "transactionMerchant": {
              "id": "https://www.example.com",
              "name": "Example Merchant"
            },
            "contents": {
              "lineItems": [
                {
                  "id": "LINE_ITEM_ID",
                  "name": "Dinner reservation",
                  "description": "A world of flavors all in one destination.",
                  "reservation": {
                    "status": "PENDING",
                    "userVisibleStatusLabel": "Reservation is pending.",
                    "type": "RESTAURANT",
                    "reservationTime": {
                      "timeIso8601": "2020-01-16T01:30:15.01Z"
                    },
                    "userAcceptableTimeRange": {
                      "timeIso8601": "2020-01-15/2020-01-17"
                    },
                    "partySize": 6,
                    "staffFacilitators": [
                      {
                        "name": "John Smith"
                      }
                    ],
                    "location": {
                      "zipCode": "94086",
                      "city": "Sunnyvale",
                      "postalAddress": {
                        "regionCode": "US",
                        "postalCode": "94086",
                        "administrativeArea": "CA",
                        "locality": "Sunnyvale",
                        "addressLines": [
                          "222, Some other Street"
                        ]
                      }
                    }
                  }
                }
              ]
            },
            "buyerInfo": {
              "email": "janedoe@gmail.com",
              "firstName": "Jane",
              "lastName": "Doe",
              "displayName": "Jane Doe"
            },
            "followUpActions": [
              {
                "type": "VIEW_DETAILS",
                "title": "View details",
                "openUrlAction": {
                  "url": "https://example.com"
                }
              },
              {
                "type": "CALL",
                "title": "Call us",
                "openUrlAction": {
                  "url": "tel:+16501112222"
                }
              },
              {
                "type": "EMAIL",
                "title": "Email us",
                "openUrlAction": {
                  "url": "mailto:person@example.com"
                }
              }
            ],
            "termsOfServiceUrl": "https://www.example.com"
          },
          "orderOptions": {
            "requestDeliveryAddress": false,
            "userInfoOptions": {
              "userInfoProperties": [
                "EMAIL"
              ]
            }
          },
          "presentationOptions": {
            "actionDisplayName": "RESERVE"
          }
        }
      }
    }
  }
}

3. הצעת ההזמנה

להציג למשתמש את הזמנת ההזמנה כדי שהוא יצטרך לאשר או לדחות. בקשת actions.intent.TRANSACTION_DECISION בכוונה טובה, ולספק את ה-Order שבנית.

חווית משתמש

כשמבקשים את ה-Intent actions.intent.TRANSACTION_DECISION, Assistant מתחיל חוויה מובנית שבה Order מעובד ישירות ל'כרטיס תצוגה מקדימה של עגלת הקניות'. המשתמש יכול לומר "Schedule reservation" (תזמון הזמנה), לדחות את העסקה או לבקש לשנות את פרטי ההזמנה.

בשלב הזה, המשתמש גם יוכל לבקש שינויים בהזמנה. במקרה הזה, עליכם לוודא שההזמנה שלכם יכולה לטפל בבקשות לשינוי הזמנה לאחר סיום החוויה של הרכבת עגלת הקניות.

טיפול בהזמנות

כשמבקשים Intent actions.intent.TRANSACTION_DECISION, יש ליצור TransactionDecision שמכיל את Order וorderOptions

הקוד הבא מציג דוגמה ל-TransactionsDecision להזמנה:

Node.js
conv.ask(new TransactionDecision({
  orderOptions: {
    requestDeliveryAddress: 'false',
  },
  presentationOptions: {
    actionDisplayName: 'RESERVE',
  },
  order: order,
}));
Java
// Create order options
OrderOptionsV3 orderOptions = new OrderOptionsV3()
    .setRequestDeliveryAddress(false)
    .setUserInfoOptions(new UserInfoOptions()
        .setUserInfoProperties(Collections.singletonList("EMAIL")));

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

// Ask for transaction decision
return getResponseBuilder(request)
    .add("Placeholder for transaction decision text")
    .add(new TransactionDecision()
        .setOrder(order)
        .setOrderOptions(orderOptions)
        .setPresentationOptions(presentationOptions)
    )
    .build();
קובץ JSON של Dialogflow

הערה: קובץ ה-JSON שבהמשך מתאר תגובת webhook.

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "systemIntent": {
        "intent": "actions.intent.TRANSACTION_DECISION",
        "data": {
          "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec",
          "orderOptions": {
            "requestDeliveryAddress": "false"
          },
          "presentationOptions": {
            "actionDisplayName": "RESERVE"
          },
          "order": {
            "createTime": "2019-07-17T18:25:30.184Z",
            "lastUpdateTime": "2019-07-17T18:25:30.184Z",
            "merchantOrderId": "UNIQUE_ORDER_ID",
            "userVisibleOrderId": "USER_VISIBLE_ORDER_ID",
            "transactionMerchant": {
              "id": "https://www.example.com",
              "name": "Example Merchant"
            },
            "contents": {
              "lineItems": [
                {
                  "id": "LINE_ITEM_ID",
                  "name": "Dinner reservation",
                  "description": "A world of flavors all in one destination.",
                  "reservation": {
                    "status": "PENDING",
                    "userVisibleStatusLabel": "Reservation is pending.",
                    "type": "RESTAURANT",
                    "reservationTime": {
                      "timeIso8601": "2020-01-16T01:30:15.01Z"
                    },
                    "userAcceptableTimeRange": {
                      "timeIso8601": "2020-01-15/2020-01-17"
                    },
                    "partySize": 6,
                    "staffFacilitators": [
                      {
                        "name": "John Smith"
                      }
                    ],
                    "location": {
                      "zipCode": "94086",
                      "city": "Sunnyvale",
                      "postalAddress": {
                        "regionCode": "US",
                        "postalCode": "94086",
                        "administrativeArea": "CA",
                        "locality": "Sunnyvale",
                        "addressLines": [
                          "222, Some other Street"
                        ]
                      }
                    }
                  }
                }
              ]
            },
            "buyerInfo": {
              "email": "janedoe@gmail.com",
              "firstName": "Jane",
              "lastName": "Doe",
              "displayName": "Jane Doe"
            },
            "followUpActions": [
              {
                "type": "VIEW_DETAILS",
                "title": "View details",
                "openUrlAction": {
                  "url": "https://example.com"
                }
              },
              {
                "type": "CALL",
                "title": "Call us",
                "openUrlAction": {
                  "url": "tel:+16501112222"
                }
              },
              {
                "type": "EMAIL",
                "title": "Email us",
                "openUrlAction": {
                  "url": "mailto:person@example.com"
                }
              }
            ],
            "termsOfServiceUrl": "https://www.example.com"
          }
        }
      }
    }
  }
}
JSON עם SDK לפעולות

הערה: קובץ ה-JSON שבהמשך מתאר תגובת webhook.

{
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "possibleIntents": [
        {
          "intent": "actions.intent.TRANSACTION_DECISION",
          "inputValueData": {
            "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec",
            "orderOptions": {
              "requestDeliveryAddress": "false"
            },
            "presentationOptions": {
              "actionDisplayName": "RESERVE"
            },
            "order": {
              "createTime": "2019-07-17T18:25:30.057Z",
              "lastUpdateTime": "2019-07-17T18:25:30.057Z",
              "merchantOrderId": "UNIQUE_ORDER_ID",
              "userVisibleOrderId": "USER_VISIBLE_ORDER_ID",
              "transactionMerchant": {
                "id": "https://www.example.com",
                "name": "Example Merchant"
              },
              "contents": {
                "lineItems": [
                  {
                    "id": "LINE_ITEM_ID",
                    "name": "Dinner reservation",
                    "description": "A world of flavors all in one destination.",
                    "reservation": {
                      "status": "PENDING",
                      "userVisibleStatusLabel": "Reservation is pending.",
                      "type": "RESTAURANT",
                      "reservationTime": {
                        "timeIso8601": "2020-01-16T01:30:15.01Z"
                      },
                      "userAcceptableTimeRange": {
                        "timeIso8601": "2020-01-15/2020-01-17"
                      },
                      "partySize": 6,
                      "staffFacilitators": [
                        {
                          "name": "John Smith"
                        }
                      ],
                      "location": {
                        "zipCode": "94086",
                        "city": "Sunnyvale",
                        "postalAddress": {
                          "regionCode": "US",
                          "postalCode": "94086",
                          "administrativeArea": "CA",
                          "locality": "Sunnyvale",
                          "addressLines": [
                            "222, Some other Street"
                          ]
                        }
                      }
                    }
                  }
                ]
              },
              "buyerInfo": {
                "email": "janedoe@gmail.com",
                "firstName": "Jane",
                "lastName": "Doe",
                "displayName": "Jane Doe"
              },
              "followUpActions": [
                {
                  "type": "VIEW_DETAILS",
                  "title": "View details",
                  "openUrlAction": {
                    "url": "https://example.com"
                  }
                },
                {
                  "type": "CALL",
                  "title": "Call us",
                  "openUrlAction": {
                    "url": "tel:+16501112222"
                  }
                },
                {
                  "type": "EMAIL",
                  "title": "Email us",
                  "openUrlAction": {
                    "url": "mailto:person@example.com"
                  }
                }
              ],
              "termsOfServiceUrl": "https://www.example.com"
            }
          }
        }
      ]
    }
  ]
}
טיפול בהחלטה של המשתמש

לאחר שהמשתמש משיב להזמנה המוצעת, מילוי ההזמנה מקבל את Intent של actions_intent_TRANSACTION_DECISION עם ארגומנט שמכיל TransactionDecisionValue. הערך הזה יכלול את הפרטים הבאים:

  • transactionDecision - ההחלטה של המשתמש לגבי ההצעה הזמנה. הערכים האפשריים הם ORDER_ACCEPTED, ORDER_REJECTED, CART_CHANGE_REQUESTED ו-USER_CANNOT_TRANSACT.

כדי לטפל בבקשה, צריך להצהיר על Intent של Dialogflow שמופעל על ידי האירוע actions_intent_TRANSACTION_DECISION. צריך לטפל בכוונה הזו של מילוי ההזמנה:

Node.js
const arg = conv.arguments.get('TRANSACTION_DECISION_VALUE');
if (arg && arg.transactionDecision === 'ORDER_ACCEPTED') {
  console.log('order accepted');
  const order = arg.order;
}
Java
Argument transactionDecisionValue = request
    .getArgument("TRANSACTION_DECISION_VALUE");
Map<String, Object> extension = null;
if (transactionDecisionValue != null) {
  extension = transactionDecisionValue.getExtension();
}

String transactionDecision = null;
if (extension != null) {
  transactionDecision = (String) extension.get("transactionDecision");
}
if ((transactionDecision != null && transactionDecision.equals("ORDER_ACCEPTED"))) {
  OrderV3 order = ((OrderV3) extension.get("order"));
}
קובץ JSON של Dialogflow

הערה: קובץ ה-JSON שבהמשך מתאר בקשת webhook.

{
  "responseId": "",
  "queryResult": {
    "queryText": "",
    "action": "",
    "parameters": {},
    "allRequiredParamsPresent": true,
    "fulfillmentText": "",
    "fulfillmentMessages": [],
    "outputContexts": [],
    "intent": {
      "name": "reservation_get_transaction_decision_df",
      "displayName": "reservation_get_transaction_decision_df"
    },
    "intentDetectionConfidence": 1,
    "diagnosticInfo": {},
    "languageCode": ""
  },
  "originalDetectIntentRequest": {
    "source": "google",
    "version": "2",
    "payload": {
      "isInSandbox": true,
      "surface": {
        "capabilities": [
          {
            "name": "actions.capability.SCREEN_OUTPUT"
          },
          {
            "name": "actions.capability.AUDIO_OUTPUT"
          },
          {
            "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
          },
          {
            "name": "actions.capability.WEB_BROWSER"
          }
        ]
      },
      "inputs": [
        {
          "rawInputs": [],
          "intent": "",
          "arguments": []
        }
      ],
      "user": {},
      "conversation": {},
      "availableSurfaces": [
        {
          "capabilities": [
            {
              "name": "actions.capability.SCREEN_OUTPUT"
            },
            {
              "name": "actions.capability.AUDIO_OUTPUT"
            },
            {
              "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
            },
            {
              "name": "actions.capability.WEB_BROWSER"
            }
          ]
        }
      ]
    }
  },
  "session": ""
}
JSON עם SDK לפעולות

הערה: קובץ ה-JSON שבהמשך מתאר בקשת webhook.

{
  "user": {},
  "device": {},
  "surface": {
    "capabilities": [
      {
        "name": "actions.capability.SCREEN_OUTPUT"
      },
      {
        "name": "actions.capability.AUDIO_OUTPUT"
      },
      {
        "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
      },
      {
        "name": "actions.capability.WEB_BROWSER"
      }
    ]
  },
  "conversation": {},
  "inputs": [
    {
      "rawInputs": [],
      "intent": "reservation_get_transaction_decision_asdk",
      "arguments": []
    }
  ],
  "availableSurfaces": [
    {
      "capabilities": [
        {
          "name": "actions.capability.SCREEN_OUTPUT"
        },
        {
          "name": "actions.capability.AUDIO_OUTPUT"
        },
        {
          "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
        },
        {
          "name": "actions.capability.WEB_BROWSER"
        }
      ]
    }
  ]
}

4. השלמת ההזמנה ושליחת קבלה

כשה-Intent actions.intent.TRANSACTION_DECISION חוזר עם transactionDecision מתוך ORDER_ACCEPTED, לבצע את הפעולה הרצויה נדרש עיבוד כדי לתזמן את ההזמנה (למשל, להשאיר אותה מסד נתונים משלכם).

שליחת תשובה פשוטה כדי להמשיך את השיחה. המשתמש מקבל 'כרטיס קבלה מכווץ' יחד עם התשובה שלך.

טיפול בהזמנות

Node.js
// Set lastUpdateTime and update status of reservation
order.lastUpdateTime = new Date().toISOString();
order.reservation.status = 'CONFIRMED';
order.reservation.userVisibleStatusLabel = 'Reservation confirmed';
order.reservation.confirmationCode = '123ABCDEFGXYZ';

// Send synchronous order update
conv.ask(`Transaction completed! You're all set!`);
conv.ask(new OrderUpdate({
  type: 'SNAPSHOT',
  reason: 'Reason string',
  order: order,
}));
Java
ResponseBuilder responseBuilder = getResponseBuilder(request);
order.setLastUpdateTime(Instant.now().toString());

// Set reservation status to confirmed and provide confirmation code
LineItemV3 lineItem = order.getContents().getLineItems().get(0);
ReservationItemExtension reservationItemExtension = lineItem.getReservation();
reservationItemExtension.setStatus("CONFIRMED");
reservationItemExtension.setUserVisibleStatusLabel("Reservation confirmed.");
reservationItemExtension.setConfirmationCode("123ABCDEFGXYZ");
lineItem.setReservation(reservationItemExtension);
order.getContents().getLineItems().set(0, lineItem);

// Order update
OrderUpdateV3 orderUpdate = new OrderUpdateV3()
    .setType("SNAPSHOT")
    .setReason("Reason string")
    .setOrder(order);

responseBuilder
    .add("Transaction completed! You're all set! Would you like to do anything else?")
    .add(new StructuredResponse().setOrderUpdateV3(orderUpdate));
return responseBuilder.build();
קובץ JSON של Dialogflow

הערה: קובץ ה-JSON שבהמשך מתאר תגובת webhook.

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "richResponse": {
        "items": [
          {
            "simpleResponse": {
              "textToSpeech": "Transaction completed! You're all set!"
            }
          },
          {
            "structuredResponse": {
              "orderUpdateV3": {
                "type": "SNAPSHOT",
                "reason": "Reason string",
                "order": {
                  "merchantOrderId": "UNIQUE_ORDER_ID",
                  "reservation": {
                    "status": "CONFIRMED",
                    "userVisibleStatusLabel": "Reservation confirmed",
                    "confirmationCode": "123ABCDEFGXYZ"
                  },
                  "lastUpdateTime": "2019-07-17T18:25:30.187Z"
                }
              }
            }
          }
        ]
      }
    }
  }
}
JSON עם SDK לפעולות

הערה: קובץ ה-JSON שבהמשך מתאר תגובת webhook.

{
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "possibleIntents": [
        {
          "intent": "actions.intent.TEXT"
        }
      ],
      "inputPrompt": {
        "richInitialPrompt": {
          "items": [
            {
              "simpleResponse": {
                "textToSpeech": "Transaction completed! You're all set!"
              }
            },
            {
              "structuredResponse": {
                "orderUpdateV3": {
                  "type": "SNAPSHOT",
                  "reason": "Reason string",
                  "order": {
                    "merchantOrderId": "UNIQUE_ORDER_ID",
                    "reservation": {
                      "status": "CONFIRMED",
                      "userVisibleStatusLabel": "Reservation confirmed",
                      "confirmationCode": "123ABCDEFGXYZ"
                    },
                    "lastUpdateTime": "2019-07-17T18:25:30.059Z"
                  }
                }
              }
            }
          ]
        }
      }
    }
  ]
}

5. שליחת עדכונים לגבי ההזמנה

סטטוס ההזמנה ישתנה במהלך כל משך החיים שלו. שליחת עדכונים של הזמנות משתמשים באמצעות HTTP בקשות PATCH ל-Orders API, שכוללות את סטטוס ההזמנה והפרטים שלה.

הגדרת בקשות אסינכרוניות ל-Orders API

בקשות לעדכון הזמנות ל-Orders API מורשות על ידי גישה ב-Assistant. כדי PATCH עדכון הזמנה ל-Orders API, צריך להוריד קובץ JSON מפתח של חשבון שירות שמשויך לפרויקט ב-Actions Console, ולאחר מכן החלפה את המפתח של חשבון השירות לאסימון למוכ"ז שניתן להעביר אל הכותרת Authorization של בקשת ה-HTTP.

כדי לאחזר את המפתח של חשבון השירות, מבצעים את השלבים הבאים:

  1. במסוף Google Cloud, צריך לעבור לתפריט TODO > ממשקי API שירותים > פרטי כניסה > יצירת פרטי כניסה > מפתח לחשבון השירות.
  2. בקטע Service Account (חשבון שירות), בוחרים באפשרות New Service Account (חשבון שירות חדש).
  3. מגדירים את חשבון השירות בתור service-account.
  4. מגדירים את Role לערך Project > בעלים.
  5. צריך להגדיר את סוג המפתח כ-JSON.
  6. בוחרים באפשרות יצירה.
  7. תתבצע הורדה של מפתח חשבון שירות פרטי בפורמט JSON למחשב המקומי שלך.

בקוד לעדכון ההזמנה, מחליפים את מפתח השירות באסימון למוכ"ז באמצעות ספריית הלקוח של Google APIs וההיקף &quot;https://www.googleapis.com/auth/actions.order.developer&quot;. אפשר למצוא את שלבי ההתקנה דוגמאות בדף GitHub של ספריית הלקוח של ה-API.

הפניה אל order-update.js בדוגמאות של Node.js ו-Java עבור דוגמה להחלפת מפתחות.

שליחת עדכונים לגבי ההזמנה

לאחר שהחלפת את המפתח של חשבון השירות באסימון למוכ"ז של OAuth, יש לשלוח מתעדכנת כבקשות מורשות של PATCH ל-Orders API.

כתובת ה-URL של Orders API: PATCH https://actions.googleapis.com/v3/orders/${orderId}

צריך לכלול בבקשה את הכותרות הבאות:

  • "Authorization: Bearer token" עם האסימון למוכ"ז OAuth החלפתם את המפתח של חשבון השירות.
  • "Content-Type: application/json".

בקשת PATCH צריכה לקחת גוף JSON בפורמט הבא:

{ "orderUpdate": OrderUpdate }

OrderUpdate האובייקט מורכב מהשדות הבאים ברמה העליונה:

  • updateMask - השדות בהזמנה שמעדכנים. כדי לעדכן את סטטוס הזמנה, מגדירים את הערך כ-reservation.status, reservation.userVisibleStatusLabel.
  • order – תוכן העדכון. אם אתם מעדכנים את תוכן ההזמנה, מגדירים את הערך לאובייקט Order המעודכן. אם אתם רק מעדכנים את סטטוס ההזמנה (לדוגמה, מ- "PENDING" עד "FULFILLED"), האובייקט מכיל את הפונקציה השדות הבאים:

    • merchantOrderId – אותו המזהה שהגדרתם באובייקט Order.
    • lastUpdateTime – חותמת הזמן של העדכון הזה.
    • purchase – אובייקט שמכיל את הפרטים הבאים:
      • status – סטטוס ההזמנה כReservationStatus, כמו "CONFIRMED" או 'CANCELLED'.
      • userVisibleStatusLabel – תווית שגלויה למשתמשים לגביה פרטים לגבי סטטוס ההזמנה, למשל 'ההזמנה שלך אושרה'.
  • userNotification (אופציונלי)userNotification אובייקט שיכול להופיע במכשיר של המשתמש כשהעדכון הזה נשלח. הערה שהכללה של האובייקט הזה לא מבטיחה שתופיע התראה במכשיר של המשתמש.

הקוד לדוגמה הבא מציג OrderUpdate לדוגמה שמעדכן את סטטוס של הזמנת ההזמנה אל FULFILLED:

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 orderUpdateJson = new OrderUpdate({
        updateMask: [
          'lastUpdateTime',
          'contents.lineItems.reservation.status',
          'contents.lineItems.reservation.userVisibleStatusLabel',
      ].join(','),
        order: {
          merchantOrderId: orderId,
          lastUpdateTime: new Date().toISOString(),
          contents: {
            lineItems: [
              {
                reservation: {
                  status: 'FULFILLED',
                  userVisibleStatusLabel: 'Reservation fulfilled',
                },
              }
            ]
          }
        },
        reason: 'Reservation status was updated to fulfilled.',
    });

    // 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: orderUpdateJson,
        },
        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;
        }
    });
});
Java
// Create order update
FieldMask fieldMask = FieldMask.newBuilder().addAllPaths(Arrays.asList(
    "lastUpdateTime",
    "contents.lineItems.reservation.status",
    "contents.lineItems.reservation.userVisibleStatusLabel"))
    .build();

OrderUpdateV3 orderUpdate = new OrderUpdateV3()
    .setOrder(new OrderV3()
        .setMerchantOrderId(orderId)
        .setLastUpdateTime(Instant.now().toString())
        .setContents(new OrderContents()
        .setLineItems(Collections.singletonList(new LineItemV3()
            .setReservation(new ReservationItemExtension()
                .setStatus("FULFILLED")
                .setUserVisibleStatusLabel("Reservation fulfilled."))))))
    .setUpdateMask(FieldMaskUtil.toString(fieldMask))
    .setReason("Reservation status was updated to fulfilled.");

// 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);
הגדרת סטטוס ההזמנה

ReservationStatus של עדכון הזמנה חייב לתאר את המצב הנוכחי של הצו. בorder.ReservationStatus של העדכון צריך להשתמש באחד מהערכים הבאים:

  • PENDING - ההזמנה "נוצרה" על ידי הפעולה שלך, אבל נדרש עיבוד נוסף בקצה העורפי.
  • CONFIRMED – ההזמנה אושרה בקצה העורפי של לוח הזמנים.
  • CANCELLED - המשתמש ביטל את ההזמנה.
  • FULFILLED – השירות מילא את ההזמנה של המשתמש.
  • CHANGE_REQUESTED - המשתמש ביקש לשנות את ההזמנה, והשינוי בתהליך עיבוד.
  • REJECTED – אם לא הצלחת לעבד את זה מאשרים את ההזמנה.

שליחת עדכונים של הזמנות לכל סטטוס שרלוונטי בהזמנה. לדוגמה, אם ההזמנה מחייבת עיבוד ידני מאשרים את ההזמנה לאחר שליחת הבקשה, שולחים עדכון להזמנה ב-PENDING עד שנדרש עיבוד נוסף. לא לכל הזמנה נדרש כל ערכי סטטוס.

פתרון בעיות

נתקלתם בבעיות במהלך הבדיקה? כדאי לקרוא את השלבים לפתרון בעיות. לעסקאות.