Sắp xếp các giao dịch thanh toán với nhân viên dịch vụ

Cách điều chỉnh ứng dụng thanh toán dựa trên web để phù hợp với tính năng Thanh toán trên web và mang đến trải nghiệm người dùng tốt hơn cho khách hàng.

Sau khi đăng ký ứng dụng thanh toán, bạn có thể chấp nhận yêu cầu thanh toán của người bán. Bài đăng này giải thích cách điều phối giao dịch thanh toán từ một worker dịch vụ trong thời gian chạy (tức là khi một cửa sổ hiển thị và người dùng đang tương tác với cửa sổ đó).

Điều phối các giao dịch thanh toán bằng worker dịch vụ
Điều phối các giao dịch thanh toán bằng trình chạy dịch vụ

"Thay đổi tham số thanh toán trong thời gian chạy" đề cập đến một tập hợp các sự kiện cho phép người bán và trình xử lý thanh toán trao đổi thông báo trong khi người dùng đang tương tác với trình xử lý thanh toán. Tìm hiểu thêm trong phần Xử lý thông tin thanh toán không bắt buộc bằng worker dịch vụ.

Nhận sự kiện yêu cầu thanh toán từ người bán

Khi khách hàng chọn thanh toán bằng ứng dụng thanh toán dựa trên web và người bán gọi PaymentRequest.show(), worker dịch vụ của bạn sẽ nhận được sự kiện paymentrequest. Thêm trình nghe sự kiện vào worker dịch vụ để ghi lại sự kiện và chuẩn bị cho hành động tiếp theo.

[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 được lưu giữ chứa thông tin quan trọng về giao dịch này:

Tên tài sản Mô tả
topOrigin Chuỗi cho biết nguồn gốc của trang web cấp cao nhất (thường là người bán nhận thanh toán). Sử dụng thuộc tính này để xác định nguồn gốc của người bán.
paymentRequestOrigin Một chuỗi cho biết nguồn gốc của phương thức gọi. Giá trị này có thể giống với topOrigin khi người bán gọi trực tiếp API Yêu cầu thanh toán, nhưng có thể khác nếu API được bên thứ ba (chẳng hạn như cổng thanh toán) gọi từ trong một iframe.
paymentRequestId Thuộc tính id của PaymentDetailsInit được cung cấp cho API Yêu cầu thanh toán. Nếu người bán bỏ qua, trình duyệt sẽ cung cấp mã nhận dạng được tạo tự động.
methodData Dữ liệu dành riêng cho phương thức thanh toán do người bán cung cấp trong PaymentMethodData. Sử dụng thông tin này để xác định thông tin giao dịch thanh toán.
total Tổng số tiền do người bán cung cấp trong PaymentDetailsInit. Sử dụng thông tin này để tạo giao diện người dùng cho khách hàng biết tổng số tiền phải trả.
instrumentKey Khoá xác định xuất phát điểm do người dùng chọn. Giá trị này phản ánh instrumentKey mà bạn đã cung cấp trước. Chuỗi trống cho biết người dùng không chỉ định bất kỳ công cụ nào.

Mở cửa sổ trình xử lý thanh toán để hiển thị giao diện người dùng của ứng dụng thanh toán dựa trên web

Khi nhận được sự kiện paymentrequest, ứng dụng thanh toán có thể mở cửa sổ trình xử lý thanh toán bằng cách gọi PaymentRequestEvent.openWindow(). Cửa sổ trình xử lý thanh toán sẽ hiển thị cho khách hàng giao diện của ứng dụng thanh toán, nơi họ có thể xác thực, chọn địa chỉ giao hàng và các lựa chọn cũng như uỷ quyền thanh toán. Chúng ta sẽ đề cập đến cách viết mã giao diện người dùng trong phần Xử lý thanh toán trên giao diện người dùng thanh toán (sắp ra mắt).

Quy trình thanh toán bằng ứng dụng thanh toán dựa trên web.

Truyền một lời hứa được lưu giữ vào PaymentRequestEvent.respondWith() để bạn có thể giải quyết lời hứa đó bằng kết quả thanh toán trong tương lai.

[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);
  };
});
…

Bạn có thể sử dụng một polyfill PromiseResolver thuận tiện để giải quyết một lời hứa tại thời điểm tuỳ ý.

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_ }
}

Trao đổi thông tin với giao diện người dùng

Worker dịch vụ của ứng dụng thanh toán có thể trao đổi thông báo với giao diện người dùng của ứng dụng thanh toán thông qua ServiceWorkerController.postMessage(). Để nhận thông báo từ giao diện người dùng, hãy theo dõi các sự kiện message.

[payment handler] service-worker.js:

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

Nhận tín hiệu sẵn sàng từ giao diện người dùng

Sau khi cửa sổ trình xử lý thanh toán mở ra, trình chạy dịch vụ sẽ chờ tín hiệu trạng thái sẵn sàng từ giao diện người dùng của ứng dụng thanh toán. Worker dịch vụ có thể truyền thông tin quan trọng đến giao diện người dùng khi đã sẵn sàng.

[trình xử lý thanh toán] giao diện người dùng:

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;
…

Truyền thông tin chi tiết về giao dịch đến giao diện người dùng

Bây giờ, hãy gửi lại thông tin thanh toán. Trong trường hợp này, bạn chỉ gửi tổng số của yêu cầu thanh toán, nhưng bạn có thể truyền thêm thông tin chi tiết nếu muốn.

[payment handler] service-worker.js:

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

[trình xử lý thanh toán] giao diện người dùng:

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;
…

Trả về thông tin thanh toán của khách hàng

Khi khách hàng uỷ quyền thanh toán, giao diện người dùng có thể gửi một thông báo đăng lên worker dịch vụ để tiếp tục. Bạn có thể giải quyết lời hứa được truyền đến PaymentRequestEvent.respondWith() để gửi kết quả lại cho người bán. Truyền một đối tượng PaymentHandlerResponse.

Tên tài sản Mô tả
methodName Giá trị nhận dạng phương thức thanh toán dùng để thanh toán.
details Dữ liệu cụ thể về phương thức thanh toán cung cấp thông tin cần thiết để người bán xử lý thanh toán.

[trình xử lý thanh toán] giao diện người dùng:

  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;
      …

Huỷ giao dịch thanh toán

Để cho phép khách hàng huỷ giao dịch, giao diện người dùng có thể gửi thông báo đăng lên worker dịch vụ để thực hiện việc này. Sau đó, worker dịch vụ có thể phân giải lời hứa được truyền đến PaymentRequestEvent.respondWith() bằng null để cho người bán biết rằng giao dịch đã bị huỷ.

[trình xử lý thanh toán] giao diện người dùng:

  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;
      …

Mã mẫu

Tất cả mã mẫu mà bạn thấy trong tài liệu này đều được trích từ ứng dụng mẫu đang hoạt động sau đây:

https://paymenthandler-demo.glitch.me

[payment handler] worker

[payment handler] giao diện người dùng

Cách dùng thử:

  1. Truy cập vào https://paymentrequest-demo.glitch.me/.
  2. Chuyển tới cuối trang.
  3. Nhấn vào Nút Thêm phương thức thanh toán.
  4. Nhập https://paymenthandler-demo.glitch.me vào trường Mã nhận dạng phương thức thanh toán.
  5. Nhấn nút Thanh toán bên cạnh trường này.

Các bước tiếp theo

Trong bài viết này, chúng ta đã tìm hiểu cách điều phối giao dịch thanh toán từ một worker dịch vụ. Bước tiếp theo là tìm hiểu cách thêm một số tính năng nâng cao hơn vào worker dịch vụ.