תזמור עסקאות תשלום עם קובץ שירות (service worker)

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

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

תיאום עסקאות תשלום עם Service Worker
תיאום עסקאות תשלום עם קובץ שירות (service worker)

'שינויים בפרמטר תשלום בזמן ריצה' מתייחס לקבוצת אירועים שמאפשרת למוכר ול-handler של התשלומים להחליף הודעות בזמן שהמשתמש מבצע אינטראקציה עם ה-handler של התשלומים. איך מטפלים בפרטי תשלום אופציונליים עם Service Worker

לקבל אירוע של בקשת תשלום מהמוכר

כשלקוח בוחר לשלם באמצעות אפליקציית התשלום שלכם מבוססת-אינטרנט והמוכר מפעיל את PaymentRequest.show(), ה-Service Worker יקבל אירוע paymentrequest. הוספת event listener ל-Service Worker כדי לתעד את האירוע ולהתכונן לפעולה הבאה.

[payment handler] service-worker.js:

…
let payment_request_event;
let resolver;
let client;

// `self` is the global object in service worker
self.addEventListener('paymentrequest', async e => {
  if (payment_request_event) {
    // If there's an ongoing payment transaction, reject it.
    resolver.reject();
  }
  // Preserve the event for future use
  payment_request_event = e;
…

השדה PaymentRequestEvent שנשמר מכיל מידע חשוב על העסקה הזו:

שם הנכס תיאור
topOrigin מחרוזת שמציינת את המקור של דף האינטרנט ברמה העליונה (בדרך כלל סוחר מקבל התשלום). משמש לזיהוי מקור המוכר.
paymentRequestOrigin מחרוזת שמציינת את מקור החשבונית. הערך הזה יכול להיות זהה לערך topOrigin כשהמוכר מפעיל את Payment Request API ישירות, אבל הוא יכול להיות שונה אם ה-API מופעל מתוך iframe על ידי צד שלישי, כמו שער תשלומים.
paymentRequestId המאפיין id של PaymentDetailsInit שסופק ל-Payment Request API. אם המוכר לא ישלים את ההזמנה, הדפדפן יספק תעודה מזהה שנוצרה באופן אוטומטי.
methodData הנתונים הספציפיים לאמצעי תשלום שסופקו על ידי המוכר כחלק מPaymentMethodData. יש להשתמש במדד הזה כדי לקבוע את פרטי עסקת התשלום.
total הסכום הכולל שהמוכר סיפק כחלק מPaymentDetailsInit. ניתן להשתמש בכך כדי ליצור ממשק משתמש שיציג ללקוח את הסכום הכולל שצריך לשלם.
instrumentKey מפתח האמצעי שנבחר על ידי המשתמש. הערך הזה משקף את instrumentKey שסיפקת מראש. מחרוזת ריקה מציינת שהמשתמש לא ציין אמצעי תשלום.

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

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

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

מעבירים הבטחה שנשמרה ל-PaymentRequestEvent.respondWith() כדי שתוכלו לפתור אותה עם תוצאת תשלום בעתיד.

[payment handler] service-worker.js:

…
self.addEventListener('paymentrequest', async e => {
…
  // Retain a promise for future resolution
  // Polyfill for PromiseResolver is provided below.
  resolver = new PromiseResolver();

  // Pass a promise that resolves when payment is done.
  e.respondWith(resolver.promise);
  // Open the checkout page.
  try {
    // Open the window and preserve the client
    client = await e.openWindow(checkoutURL);
    if (!client) {
      // Reject if the window fails to open
      throw 'Failed to open window';
    }
  } catch (err) {
    // Reject the promise on failure
    resolver.reject(err);
  };
});
…

תוכלו להשתמש ב-Polyfill נוח של PromiseResolver כדי לפתור הבטחה בתזמון שרירותי.

class PromiseResolver {
  constructor() {
    this.promise_ = new Promise((resolve, reject) => {
      this.resolve_ = resolve;
      this.reject_ = reject;
    })
  }
  get promise() { return this.promise_ }
  get resolve() { return this.resolve_ }
  get reject() { return this.reject_ }
}

החלפת מידע עם ממשק הקצה

קובץ השירות (service worker) של אפליקציית התשלום יכול להחליף הודעות עם הקצה של אפליקציית התשלום באמצעות ServiceWorkerController.postMessage(). כדי לקבל הודעות בממשק הקצה, צריך להאזין לאירועים של message.

[payment handler] service-worker.js:

// Define a convenient `postMessage()` method
const postMessage = (type, contents = {}) => {
  if (client) client.postMessage({ type, ...contents });
}

קבלת אות מוכן מהממשק

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

ממשק המשתמש של [Payment handler]:

navigator.serviceWorker.controller.postMessage({
  type: 'WINDOW_IS_READY'
});

[payment handler] service-worker.js:

…
// Received a message from the frontend
self.addEventListener('message', async e => {
  let details;
  try {
    switch (e.data.type) {
      // `WINDOW_IS_READY` is a frontend's ready state signal
      case 'WINDOW_IS_READY':
        const { total } = payment_request_event;
…

העברה של פרטי העסקה לממשק הקצה

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

[payment handler] service-worker.js:

…
        // Pass the payment details to the frontend
        postMessage('PAYMENT_IS_READY', { total });
        break;
…

ממשק המשתמש של [Payment handler]:

let total;

navigator.serviceWorker.addEventListener('message', async e => {
  switch (e.data.type) {
      case 'PAYMENT_IS_READY':
        ({ total } = e.data);
        // Update the UI
        renderHTML(total);
        break;
…

החזרת פרטי הכניסה של הלקוח לתשלום

כשהלקוח מאשר את התשלום, ממשק הקצה יכול לשלוח הודעה ל-Service Worker כדי להמשיך. אפשר לפתור את ההבטחה שהועברה ל-PaymentRequestEvent.respondWith() כדי לשלוח את התוצאה בחזרה למוכר. מעבירים אובייקט PaymentHandlerResponse.

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

ממשק המשתמש של [Payment handler]:

  const paymentMethod = …

  postMessage('PAYMENT_AUTHORIZED', {
    paymentMethod,              // Payment method identifier
  });

[payment handler] service-worker.js:

…
// Received a message from the frontend
self.addEventListener('message', async e => {
  let details;
  try {
    switch (e.data.type) {
      …
      case 'PAYMENT_AUTHORIZED':
        // Resolve the payment request event promise
        // with a payment response object
        const response = {
          methodName: e.data.paymentMethod,
          details: { id: 'put payment credential here' },
        }
        resolver.resolve(response);
        // Don't forget to initialize.
        payment_request_event = null;
        break;
      …

ביטול עסקת התשלום

כדי לאפשר ללקוח לבטל את העסקה, חזית השירות יכולה לשלוח הודעה ל-Service Worker כדי שיבטל את ההבטחה שהועברה ל-PaymentRequestEvent.respondWith() עם null, על מנת לציין למוכר שהעסקה בוטלה.

ממשק המשתמש של [Payment handler]:

  postMessage('CANCEL_PAYMENT');

[payment handler] service-worker.js:

…
// Received a message from the frontend
self.addEventListener('message', async e => {
  let details;
  try {
    switch (e.data.type) {
      …
      case 'CANCEL_PAYMENT':
        // Resolve the payment request event promise
        // with null
        resolver.resolve(null);
        // Don't forget to initialize.
        payment_request_event = null;
        break;
      …

קוד לדוגמה

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

https://paymenthandler-demo.glitch.me

[handler של תשלום] Service Worker

[handler של תשלום]

כדי לנסות:

  1. נכנסים לכתובת https://paymentrequest-demo.glitch.me/.
  2. עבור לתחתית הדף.
  3. לוחצים על הוספת לחצן תשלום.
  4. מזינים https://paymenthandler-demo.glitch.me בשדה מזהה אמצעי תשלום.
  5. מקישים על הלחצן תשלום לצד השדה.

השלבים הבאים

במאמר הזה למדנו איך לתזמר עסקת תשלום מ-Service Worker. השלב הבא הוא ללמוד איך להוסיף עוד תכונות מתקדמות ל-Service Worker.