הגדרת תשלום

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

הטיפול בתשלום בשירות האינטרנט צריך להגיב לבקשות POST. כשלקוח בוחר לבצע תשלום, Google שולחת לשירות האינטרנט של Ordering End-to-End גוף בקשה בפורמט JSON בצורת CheckoutRequestMessage, שמכיל את הפרטים של Cart של הלקוח. לאחר מכן, שירות האינטרנט שלכם ישיב עם CheckoutResponseMessage. התרשים הבא מדגים את התהליך.

הפונקציה CheckoutResponseMessage מחזירה את עגלת הקניות של הלקוח ללא שינויים או הודעת שגיאה.

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

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

לפני שמתחילים להטמיע תהליך תשלום, מומלץ לעיין במסמך סקירה כללית על תהליך המילוי.

הודעת בקשה לתשלום

כדי לאמת את עגלת הקניות של הלקוח, כשהלקוח בוחר לבצע תשלום, Google שולחת בקשה לשירות האינטרנט שלכם עם גוף JSON בפורמט CheckoutRequestMessage. ההזמנה של הלקוח לא נשלחת עד שלב מאוחר יותר בתהליך Ordering End-to-End.

הנתונים שמופיעים ב-CheckoutRequestMessage כוללים את הפרטים הבאים:

  • כוונה: השדה inputs[0].intent בכל גוף בקשה של תשלום מכיל את ערך המחרוזת actions.foodordering.intent.CHECKOUT.
  • עגלת קניות: השדה inputs[0].arguments[0].extension בבקשת תשלום מכיל אובייקט Cart שמייצג את עגלת הקניות של הלקוח.
  • משלוח או איסוף עצמי: שדה התוסף של האובייקט Cart מכיל אובייקט FoodCartExtension שמציין מאפיינים של משלוח או איסוף עצמי:
    • בהזמנות למשלוח, האובייקט FoodCartExtension כולל את הכתובת למשלוח.
    • בהזמנות לאיסוף או להזמנות ממסעדה, האובייקט FoodCartExtension לא מכיל פרטי מיקום.
  • ארגז חול: השדה isInSandbox בבקשת תשלום מכיל ערך בוליאני שמציין אם בעסקה נעשה שימוש בתשלומים בארגז חול.

דוגמה לבקשת תשלום

דוגמה ל-CheckoutRequestMessage:

{
    "user": {},
    "conversation": {
        "conversationId": "CTZbZfUlHCybEdcz_5PB3Ttf"
    },
    "inputs": [
        {
            "intent": "actions.foodordering.intent.CHECKOUT",
            "arguments": [
                {
                    "extension": {
                        "@type": "type.googleapis.com/google.actions.v2.orders.Cart",
                        "merchant": {
                            "id": "restaurant/Restaurant/QWERTY",
                            "name": "Tep Tep Chicken Club"
                        },
                        "lineItems": [
                            {
                                "name": "Spicy Fried Chicken",
                                "type": "REGULAR",
                                "id": "299977679",
                                "quantity": 2,
                                "price": {
                                    "type": "ESTIMATE",
                                    "amount": {
                                        "currencyCode": "AUD",
                                        "units": "39",
                                        "nanos": 600000000
                                    }
                                },
                                "offerId": "MenuItemOffer/QWERTY/scheduleId/496/itemId/143",
                                "extension": {
                                    "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension"
                                }
                            }
                        ],
                        "extension": {
                            "@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension",
                            "fulfillmentPreference": {
                                "fulfillmentInfo": {
                                    "delivery": {
                                        "deliveryTimeIso8601": "P0M"
                                    }
                                }
                            },
                            "location": {
                                "coordinates": {
                                    "latitude": -33.8376441,
                                    "longitude": 151.0868736
                                },
                                "formattedAddress": "Killoola St, 1, Concord West NSW 2138",
                                "zipCode": "2138",
                                "city": "Concord West",
                                "postalAddress": {
                                    "regionCode": "AU",
                                    "postalCode": "2138",
                                    "administrativeArea": "NSW",
                                    "locality": "Concord West",
                                    "addressLines": [
                                        "Killoola St",
                                        "1"
                                    ]
                                }
                            }
                        }
                    }
                }
            ]
        }
    ],
    "directActionOnly": true,
    "isInSandbox": true
}

הודעת תגובה בקופה

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

בקשה שהושבה בהצלחה

אם בקשת היציאה תאושר, השדה CheckoutResponseMessage צריך לכלול את הערכים ProposedOrder ו-PaymentOptions:

  • ProposedOrder

    • cart: אובייקט cart זהה לעגלה שצוינה ב-CheckoutRequestMessage. אם צריך לשנות את אחד מהפריטים בעגלה, ה-CheckoutResponseMessage צריך לכלול במקום זאת FoodErrorExtension עם ProposedOrder מתוקן.
    • otherItems: פריטים שנוספו על ידי הספק, כמו חיובים על משלוח, מיסים ועמלות אחרות. יכול להיות שיכלול גם תשר שהמשתמש הוסיף.
    • totalPrice: המחיר הכולל של ההזמנה.
    • extension: FoodOrderExtension שמגדיר את פרטי האספקה של ההזמנה, כמו זמן האספקה.
  • PaymentOptions

    • בהמשך המאמר, בקטע הגדרת Google Pay, מוסבר איך מגדירים את עיבוד התשלומים. אפשר להשתמש ב-JSON של placeholder ב-CheckoutResponseMessage עד שתהיה לכם אפשרות להטמיע עיבוד תשלומים.
    • כדי להוסיף אפשרויות תשלום למעקב אחרי CheckoutResponseMessage, אפשר להיעזר בדוגמה שבהמשך, שבה נעשה שימוש בשער תשלום לדוגמה ל-PaymentOptions.

דוגמה לתגובה מוצלחת

{
    "finalResponse": {
        "richResponse": {
            "items": [
                {
                    "structuredResponse": {
                        "checkoutResponse": {
                            "proposedOrder": {
                                "cart": {
                                    "merchant": {
                                        "id": "restaurant/Restaurant/QWERTY",
                                        "name": "Tep Tep Chicken Club"
                                    },
                                    "lineItems": [
                                        {
                                            "name": "Spicy Fried Chicken",
                                            "type": "REGULAR",
                                            "id": "299977679",
                                            "quantity": 2,
                                            "price": {
                                                "type": "ESTIMATE",
                                                "amount": {
                                                    "currencyCode": "AUD",
                                                    "units": "39",
                                                    "nanos": 600000000
                                                }
                                            },
                                            "offerId": "MenuItemOffer/QWERTY/scheduleId/496/itemId/143",
                                            "extension": {
                                                "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension"
                                            }
                                        }
                                    ],
                                    "extension": {
                                        "@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension",
                                        "fulfillmentPreference": {
                                            "fulfillmentInfo": {
                                                "delivery": {
                                                    "deliveryTimeIso8601": "P0M"
                                                }
                                            }
                                        },
                                        "location": {
                                            "coordinates": {
                                                "latitude": -33.8376441,
                                                "longitude": 151.0868736
                                            },
                                            "formattedAddress": "Killoola St, 1, Concord West NSW 2138",
                                            "zipCode": "2138",
                                            "city": "Concord West",
                                            "postalAddress": {
                                                "regionCode": "AU",
                                                "postalCode": "2138",
                                                "administrativeArea": "NSW",
                                                "locality": "Concord West",
                                                "addressLines": [
                                                    "Killoola St",
                                                    "1"
                                                ]
                                            }
                                        }
                                    }
                                },
                                "totalPrice": {
                                    "type": "ESTIMATE",
                                    "amount": {
                                        "currencyCode": "AUD",
                                        "units": "43",
                                        "nanos": 100000000
                                    }
                                },
                                "extension": {
                                    "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderExtension",
                                    "availableFulfillmentOptions": [
                                        {
                                            "fulfillmentInfo": {
                                                "delivery": {
                                                    "deliveryTimeIso8601": "P0M"
                                                }
                                            }
                                        }
                                    ]
                                },
                                "otherItems": [
                                    {
                                        "name": "Delivery fee",
                                        "price": {
                                            "type": "ESTIMATE",
                                            "amount": {
                                                "currencyCode": "AUD",
                                                "units": "3",
                                                "nanos": 500000000
                                            }
                                        },
                                        "type": "DELIVERY"
                                    }
                                ]
                            },
                            "paymentOptions": {
                                "googleProvidedOptions": {
                                    "facilitationSpecification": "{\"apiVersion\":2,\"apiVersionMinor\":0,\"merchantInfo\":{\"merchantName\":\"merchantName\"},\"allowedPaymentMethods\":[{\"type\":\"CARD\",\"parameters\":{\"allowedAuthMethods\":[\"PAN_ONLY\"],\"allowedCardNetworks\":[\"VISA\",\"MASTERCARD\"],\"billingAddressRequired\":true,\"cvcRequired\":false},\"tokenizationSpecification\":{\"type\":\"PAYMENT_GATEWAY\",\"parameters\":{\"gatewayMerchantId\":\"YOUR_MERCHANT_ID\",\"gateway\":\"cybersource\"}}}],\"transactionInfo\":{\"currencyCode\":\"AUD\",\"totalPriceStatus\":\"ESTIMATED\",\"totalPrice\":\"43.1\"}} "
                                }
                            },
                            "additionalPaymentOptions": [
                                {
                                    "actionProvidedOptions": {
                                        "paymentType": "ON_FULFILLMENT",
                                        "displayName": "Pay when you get your food.",
                                        "onFulfillmentPaymentData": {
                                            "supportedPaymentOptions": []
                                        }
                                    }
                                }
                            ]
                        }
                    }
                }
            ]
        }
    }
}

בקשה שנכשלה

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

דוגמה לתגובה לא מוצלחת

{
  "expectUserResponse": false,
  "finalResponse": {
    "richResponse": {
      "items": [
        {
          "structuredResponse": {
            "error": {
              "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension",
              "foodOrderErrors": [
                {
                  "error": "CLOSED",
                  "description": "The restaurant is closed."
                }
              ]
            }
          }
        }
      ]
    }
  }
}

הטמעת תהליך התשלום

כשמטמיעים את התשלום בקופה, צריך לבצע את השלבים הבאים.

אימות השירות

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

  1. קוראים את המאפיין FulfillmentOptionInfo בבקשה כדי לקבוע אם סוג המילוי הוא ל-delivery או ל-pickup.
  2. אם צריך, מחזירים את סוגי השגיאות הבאים:

    סוג השגיאה תרחיש לדוגמה
    INVALID סוג המילוי לא חוקי.
    NOT_FOUND סוג המילוי לא נמצא.
    סגור
    • אין חלונות OperationHours להזמנה.
    • ההזמנה היא בהקדם האפשרי ואין ServiceHours זמינות בהקדם האפשרי בשלב הזה.
    • יש חסימה זמנית מסיבות חירום או שהשירות isDisabled נכון.
    לתשומת ליבכם: חלונות מיוחדים מקבלים עדיפות על פני חלונות רגילים. דוגמאות מפורטות זמינות במאמרים אימות חלון ההזמנה והסרה זמנית של ישויות שירות.
    UNAVAILABLE_SLOT לא ניתן למלא את ההזמנה מראש.
    NO_CAPACITY המסעדה עמוסה ולא מקבלת כרגע הזמנות.
    OUT_OF_SERVICE_AREA לא ניתן לשלוח את ההזמנה לכתובת של המשתמש. דוגמה לכך מופיעה במאמר אימות כתובת למשלוח.
    NO_COURIER_AVAILABLE לא ניתן לבצע את המשלוח כי מספר צוות השליחויות מוגבל.

אימות ועריכת המחיר של עגלת הקניות

  1. מחפשים כל עגלת קניות.lineItems ומאמתים עם הנתונים הנוכחיים במערכת שלכם או במערכת של המוכר. הערך MenuItemOffer.sku מהישות בפיד נכלל בתור LineItem.offerId. אם צריך, יוצרים אירוע FoodOrderError לכל פריט. אפשר ליצור שגיאה אחת לכל פריט לכל היותר. אם צריך, מחזירים את סוגי השגיאות הבאים:

    סוג השגיאה תרחיש לדוגמה ניתן לשחזור
    INVALID נתוני הפריט או נתוני אחת מהאפשרויות לא תקינים. לא
    NOT_FOUND הפריט או אף אחת מהאפשרויות לא נמצאים. לא
    PRICE_CHANGED המחיר של פריט או שילוב של תוספים השתנה. אפשר להתייחס לשגיאה הזו כאל שגיאה שניתן לשחזור. כן
    AVAILABILITY_CHANGED הסכום המבוקש עבור הפריטים או אחת מהאפשרויות לא זמין. כן
    REQUIREMENTS_NOT_MET לא הגעתם לסכום ההזמנה המינימלי או המקסימלי. אפשר לקבוע זאת על ידי בדיקה אם מחיר עגלת הקניות נמוך מ-Fee.eligibleTransactionVolumeMin או גבוה מ-Fee.eligibleTransactionVolumeMax. אפשר לעיין בדוגמה בקטע אימות ערך הזמנה מינימלי. לא
  2. החזרת הרשימה המאומתת של הפריטים עם LineItemType REGULAR. הסכום של כל המחירים של הפריטים בעגלת הקניות הוא מחיר עגלת הקניות, או SUBTOTAL.

דוגמאות מפורטות זמינות במאמר אימות פריטים בעגלת הקניות.

חישוב עמלות השירות

  1. מחפשים את הישות Fee המתאימה לשירות על סמך הערכים של eligibleRegion, ‏ validFrom, ‏ validThrough ו-priority.
  2. חישוב סכום העמלה על סמך הגדרת הישות באמצעות מאפיין price,‏ percentageOfCart או pricePerMeter.
  3. מחזירים את עמלת השירות של המשלוח או של ההזמנה ממסעדה בתור LineItem עם LineItemType DELIVERY או FEE, בהתאמה. מוסיפים את העמלה לרשימת הכרטיסים.otherItems

החלת מבצעים

  1. חיפוש הישות Deal על סמך התאמה של הערך Promotion.coupon לערך Deal.dealCode.
  2. מאמתים את המבצע ומחזירים FoodOrderError במקרה הצורך. אפשר להתייחס לשגיאות האלה כאל שגיאות שניתן לשחזר. אם צריך, מחזירים את סוגי השגיאות הבאים:

    סוג השגיאה תרחיש לדוגמה
    PROMO_NOT_RECOGNIZED קוד השובר לא זוהה.
    PROMO_EXPIRED פג התוקף של המבצע.
    PROMO_ORDER_INELIGIBLE ההזמנה לא עומדת בדרישות של השובר.
    PROMO_NOT_APPLICABLE סיבה אחרת.
  3. מחשבים את סכום מחיר המבצע על סמך Deal.discount או Deal.discountPercentage.

  4. מחילים את סכום המבצע על סמך הסכום הכולל בעגלת הקניות או הסכום הכולל של העמלות, בהתאם למבצע.dealType.

  5. חוזרים אל עגלת הקניות.promotions עם המבצע שמומש.

  6. מחזירים את קידום המכירות כ-LineItem עם LineItemTypeDISCOUNT. מוסיפים את ההנחה לרשימה Cart.otherItems עם מחיר שלילי.

החזרת התשובה

  1. יוצרים את ProposedOrder.cart, עגלת התשובה זהה לעגלת הבקשה אם לא נתקלים בשגיאות במהלך האימות.
  2. מחזירים את הרשימה ProposedOrder.otherItems, כולל המס, העמלות, התשר וההנחה, אם חלה. במאמר תשריף מוסבר בהרחבה איך מגדירים את הפריט 'תשריף'.
  3. מוסיפים את ProposedOrder.totalPrice על ידי הוספת המחיר של עגלת הקניות, העמלות, ההנחות, המיסים והטיפ.
  4. מחזירים את FoodOrderExtension.availableFulfillmentOptions עם FulfillmentOption המתאים. מעדכנים את זמן האיסוף או המסירה המשוער לפי הזמן הצפוי.
  5. אם יש שגיאות מסוג FoodOrderErrors שנוצרו מבדיקות האימות הקודמות:
    • כוללים את StructuredResponse.error ואת רשימת השגיאות ב-FoodErrorExtension.foodOrderErrors.
    • מחזירים את ProposedOrder בשדה correctedProposedOrder אם ניתן לשחזר את כל השגיאות.
    • מחזירים את PaymentOptions בשדה paymentOptions אם ניתן לשחזר את כל השגיאות.
    • אפשר לכלול את הערך additionalPaymentOptions אם יש אפשרויות תשלום אחרות ואפשר לשחזר את כל השגיאות.
  6. אם אין שגיאות אימות, מחזירים את הערכים proposedOrder,‏ paymentOptions באובייקט CheckoutResponse. אם יש אפשרויות תשלום אחרות, אפשר לכלול את additionalPaymentOptions.