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

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

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

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

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

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

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

העברות של מצב ההזמנה

כשלקוח שולח הזמנה בפעם הראשונה, ההזמנה מתחילה במצב 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. 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"
      }
    }
  }
}
  

מוכנה

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

{
  "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"
            }
          }
        }
      ]
    }
  }
}
    

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

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

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

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

  1. כדי ליצור אסימון הרשאה:
    1. משתמשים בספריית האימות של Google כדי לקרוא את פרטי הכניסה מקובץ חשבון השירות.
    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 עבור 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 עבור 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 עם מטען ייעודי (payload) ריק. אם יש בעיה, למשל שגיאה בפורמט העדכון, Google מחזירה שגיאה.