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

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

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

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

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

מצבי הזמנה עוברים

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

מעברים בין מצבי הזמנה

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