עדכון אסינכרוני של הזמנה

אחרי שלקוח שולח הזמנה של אוכל, אתם יכולים לשלוח הודעה על עדכון ההזמנה לשירות 'הזמנות מקצה לקצה' כדי להודיע לנו על השינוי.

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

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

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

מעבר בין מצבי ההזמנות

להזמנה יש שישה מצבים אפשריים. המצבים האלה והמעברים האפשריים ביניהם מפורטים בתרשים הבא:

מעברים של מצב ההזמנה

כשלקוח שולח הזמנה בפעם הראשונה, ההזמנה מתחילה במצב CREATED, ‏CONFIRMED או REJECTED. אתם יכולים לשלוח הודעה עם עדכון לגבי ההזמנה כדי לעדכן את הסטטוס שלה, כל עוד המעבר בין הסטטוסים תקין. המצב CREATED משמש כשפלטפורמת השותף לא יכולה לאשר או לדחות את ההזמנה באופן מיידי. דוגמה לתרחישים לדוגמה היא כשלקוח מבצע הזמנה דרך שירות אגרגטור של משלוחים. שירות האגרגטור של המשלוחים מקבל את המשלוח מ-Google, ואז שולח את המידע למסעדה. אחרי שהמסעדה קיבלה את הזמנה ואישרה את הזמינות שלה, המצב יכול להיות עכשיו CONFIRMED, אחרת REJECTED.

הזמנה במצב CONFIRMED עוברת למצב IN_PREPARATION. בהתאם לאופן האספקה (איסוף עצמי או משלוח), משתמשים בסטטוס READY_FOR_PICKUP או בסטטוס IN_TRANSIT. כשהאוכל נמסר או נאסף, ההזמנה מוגדרת למצב FULFILLED.

אם אתם מאפשרים ללקוחות לבטל הזמנות, אתם יכולים להשתמש במצב CANCELLED. אפשר לבטל הזמנה בסטטוסים CREATED,‏ CONFIRMED,‏ IN_PREPARATION,‏ READY_FOR_PICKUP או IN_TRANSIT. שירות ההזמנות מקצה לקצה אמור להנפיק החזרים כספיים בהתאם למדיניות הביטולים ולסטטוס התשלומים בזמן הביטול.

שירות ההזמנות מקצה לקצה לא חייב לתמוך בכל המצבים והמעברים הזמינים. עם זאת, המצב הסופי של ההזמנה חייב להיות FULFILLED,‏ REJECTED או CANCELLED.

מתן מועד טיפול משוער

אתם יכולים לספק למשתמשים טווח זמן משוער שבו ההזמנה שלהם תהיה מוכנה לאיסוף (או תימסר). משתמשים בשדה estimatedFulfillmentTimeIso8601 של FoodOrderUpdateExtension כדי לציין טווח זמן משוער שבו ההזמנה של הלקוח תהיה מוכנה לאיסוף או תימסר.

שולחים את estimatedFulfillmentTimeIso8601 במועדים הבאים:

  • כשהזמן המשוער יהיה זמין, רצוי במצב ההזמנה CREATED או CONFIRMED.
  • כשהזמן המשוער משתנה, למשל כשמעדכנים את הזמן המשוער כדי שיהיה מדויק יותר כשההזמנה בסטטוס IN_TRANSIT.

כדי לנהל את הציפיות של המשתמשים בצורה יעילה, כדאי להעריך בזהירות ולציין טווח תאריכים ושעות במקום תאריך ושעה קבועים. כשהדבר אפשרי, כדאי להביא בחשבון גורמים משתנים כמו תנאי התנועה. לדוגמה, אפשר לשלוח הערכה של 12:45 (גבול תחתון) עד 13:15 (גבול עליון) להזמנה שבה זמן האספקה המשוער הוא 13:00.

מתן פעולות לניהול הזמנות

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

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

פעולות ניהול ההזמנות כוללות את הסוגים הבאים:

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

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

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

משתמשים בסוג ההודעה AsyncOrderUpdateRequestMessage כדי לשלוח עדכון של הזמנה לשירות Ordering End-to-End. Google תחזיר AsyncOrderUpdateResponseMessage. לדוגמה, אם רוצים להודיע ללקוח שההזמנה שלו תקפה ונתקבלה, אפשר לשלוח AsyncOrderUpdateRequestMessage כדי לשנות את סטטוס ההזמנה ל-CONFIRMED עם התווית Accepted by restaurant.

תרשים של עדכון ההזמנה

הגדרת ההודעה על עדכון ההזמנה

כששולחים AsyncOrderUpdateRequestMessage אל Google, צריך לכלול מידע על סטטוס ההזמנה באמצעות השדה OrderUpdate.

בדוגמאות הבאות מוצגת AsyncOrderUpdateRequestMessage לדוגמה לכל מצב הזמנה:

אושר

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

{
  "isInSandbox": true,
  "customPushMessage": {
    "orderUpdate": {
      "actionOrderId": "sample_action_order_id",
      "orderState": {
        "state": "CONFIRMED",
        "label": "Provider confirmed"
      },
      "receipt": {
        "userVisibleOrderId": "userVisibleId1234"
      },
      "updateTime": "2017-07-17T12:00:00Z",
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ],
      "infoExtension": {
        "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
        "estimatedFulfillmentTimeIso8601": "2017-07-17T13:00:00Z/2017-07-17T13:30:00Z"
      }
    }
  }
}
    

נדחה

בדוגמה הזו מוצגת בקשה לדוגמה לעדכון הזמנה, שבה המשתמש מקבל הודעה על כך שההזמנה נדחתה עם הסיבה לדחייה.

{
  "isInSandbox": true,
  "customPushMessage": {
    "orderUpdate": {
      "actionOrderId": "sample_action_order_id",
      "orderState": {
        "state": "REJECTED",
        "label": "Order rejected"
      },
      "updateTime": "2017-05-10T02:30:00.000Z",
      "rejectionInfo": {
        "type": "UNKNOWN",
        "reason": "Sorry, the restaurant cannot take your order right now."
      },
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ],
      "infoExtension": {
      "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
      "foodOrderErrors": [
        {
        "error": "NO_CAPACITY",
        "description": "Sorry, the restaurant cannot take your order right now."
        }
      ]
      }
    }
  }
}
    

בוטלה

בדוגמה הזו מוצגת בקשה לדוגמה לעדכון הזמנה, שבה המשתמש מקבל הודעה על ביטול ההזמנה עם הסיבה לביטול.

{
  "isInSandbox": true,
  "customPushMessage": {
    "orderUpdate": {
      "actionOrderId": "sample_action_order_id",
      "orderState": {
        "state": "CANCELLED",
        "label": "Order cancelled"
      },
      "updateTime": "2017-05-10T02:30:00.000Z",
      "cancellationInfo": {
        "reason": "Customer requested"
      },
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ]
    }
  }
}
    

IN_PREPARATION

בדוגמה הזו מוצגת בקשה לדוגמה לעדכון הזמנה, שבה המשתמש מודיע שהוא מכין את האוכל.

{
  "isInSandbox":true,
  "customPushMessage":{
    "orderUpdate":{
      "actionOrderId":"sample_action_order_id",
      "orderState":{
        "state":"IN_PREPARATION",
        "label":"Order is being prepared"
      },
      "receipt": {
        "userVisibleOrderId": "userVisibleId1234"
      },
      "updateTime":"2018-04-15T11:30:00Z",
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ],
      "infoExtension":{
        "@type":"type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
        "estimatedFulfillmentTimeIso8601":"PT20M"
      }
    }
  }
}
    

READY_FOR_PICKUP

בדוגמה הזו מוצגת בקשה לדוגמה לעדכון הזמנה, שבה מודיע למשתמש שהאוכל מוכן לאיסוף.

{
  "isInSandbox": true,
  "customPushMessage": {
    "orderUpdate": {
      "actionOrderId": "sample_action_order_id",
      "orderState": {
        "state": "READY_FOR_PICKUP",
        "label": "Order is ready for pickup"
      },
      "receipt": {
        "userVisibleOrderId": "userVisibleId1234"
      },
      "updateTime": "2018-04-15T12:00:00Z",
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ],
      "infoExtension": {
        "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
        "estimatedFulfillmentTimeIso8601": "PT20M"
      }
    }
  }
}
    

IN_TRANSIT

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

{
  "isInSandbox": true,
  "customPushMessage": {
    "orderUpdate": {
      "actionOrderId": "sample_action_order_id",
      "orderState": {
        "state": "IN_TRANSIT",
        "label": "Order is on the way"
      },
      "inTransitInfo": {
        "updatedTime": "2017-07-17T12:00:00Z"
      },
      "updateTime": "2017-07-17T12:00:00Z",
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ],
      "infoExtension": {
        "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
        "estimatedFulfillmentTimeIso8601": "PT20M"
      }
    }
  }
}
  

FULFILLED

בדוגמה הזו מוצגת בקשה לדוגמה לעדכון הזמנה, שמעדכנת את המשתמש שההזמנה נאספה או נמסרה:

{
  "isInSandbox": true,
  "customPushMessage": {
    "orderUpdate": {
      "actionOrderId": "sample_action_order_id",
      "orderState": {
      "state": "FULFILLED",
      "label": "Order delivered"
      },
      "updateTime": "2017-05-10T02:30:00.000Z",
      "fulfillmentInfo": {
        "deliveryTime": "2017-05-10T02:30:00.000Z"
      },
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ]
    }
  }
}
    

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

יצירת אסימון הרשאה ושליחת ההודעה

כדי לעדכן הזמנות, נדרש אסימון הרשאה כדי ששירות Ordering End-to-End יוכל לאמת שההודעה מגיעה משירות האינטרנט של Ordering End-to-End.

כדי להטמיע עדכוני הזמנות בפרויקט:

  1. כדי ליצור אסימון הרשאה:
    1. משתמשים ב-Google Auth Library כדי לקרוא את פרטי הכניסה מקובץ חשבון השירות.
    2. מבקשים אסימון באמצעות היקף ה-API הבא: https://www.googleapis.com/auth/actions.fulfillment.conversation
  2. משתמשים באסימון הזה כדי לשלוח בקשת HTTP POST מאומתת לנקודת הקצה הבאה: https://actions.googleapis.com/v2/conversations:send
  3. מגדירים את הכותרת Content-Type ל-application/json כחלק מהבקשה.

בדוגמאות הבאות מוסבר איך מטמיעים עדכוני הזמנות:

Node.js

הקוד הזה משתמש ב-Google Auth Library ל-Node.js.

const {auth} = require('google-auth-library')
const request = require('request');
// The service account client secret file downloaded from the Google Cloud Console
const serviceAccountJson = require('./service-account.json')
// order-update.json is a file that contains the payload
const jsonBody = require('./order-update.json')

/**
 * Get the authorization token using a service account.
 */
async function getAuthToken() {
  let client = auth.fromJSON(serviceAccountJson)
  client.scopes = ['https://www.googleapis.com/auth/actions.fulfillment.conversation']
  const tokens = await client.authorize()
  return tokens.access_token;
}

/**
 * Send an order update request
 */
async function sendOrderUpdate() {
  const token = await getAuthToken()
  request.post({
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${token}`
    },
    url: 'https://actions.googleapis.com/v2/conversations:send',
    body: jsonBody,
    json: true
  },
  (err, res, body) => {
    if (err) { return console.log(err); }
    console.log(`Response: ${JSON.stringify(res)}`)
  })
}
    

Python

הקוד הזה משתמש בספריית Google Auth ל-Python.

from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession
import json

# service-account.json is the service account client secret file downloaded from the
# Google Cloud Console
credentials = service_account.Credentials.from_service_account_file(
    'service-account.json')

scoped_credentials = credentials.with_scopes(
    ['https://www.googleapis.com/auth/actions.fulfillment.conversation'])

authed_session = AuthorizedSession(scoped_credentials)

# order-update.json is a file that contains the payload
json_payload=json.load(open('order-update.json'))

response = authed_session.post(
    'https://actions.googleapis.com/v2/conversations:send',
    json=json_payload)
    

Java

הקוד הזה משתמש ב-Google Auth Library ל-Java.

/**
 * Get the authorization token using a service account.
 */
private static String getAuthToken() {
  InputStream serviceAccountFile = Example.class.getClassLoader().getResourceAsStream("service-account.json");
  ServiceAccountCredentials.Builder credentialsSimpleBuilder =
      ServiceAccountCredentials.fromStream(serviceAccountFile).toBuilder();
  credentialsSimpleBuilder.setScopes(ImmutableList.of("https://www.googleapis.com/auth/actions.fulfillment.conversation"));
  AccessToken accessToken = credentialsSimpleBuilder.build().refreshAccessToken();
  return accessToken.getTokenValue();
}

/**
 * Send an order update request
 */
public void sendOrderUpdate() {
  String authToken = getAuthToken();
  // Execute POST request
  executePostRequest("https://actions.googleapis.com/v2/conversations:send",
      authToken, "update_order_example.json",);
}
    

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