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 nền tảng web cho phù hợp với hệ thống Thanh toán trên web và cung cấp trải nghiệm 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 sắp xếp một giao dịch thanh toán từ một trình chạy 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 với một nhân viên dịch vụ
Điều phối các giao dịch thanh toán với một trình chạy dịch vụ

"Thay đổi về thông số thanh toán trong thời gian chạy" là một nhóm các sự kiện cho phép người bán và trình xử lý khoản thanh toán trao đổi thông báo trong khi người dùng tương tác với trình xử lý thanh toán. Tìm hiểu thêm qua bài viết Xử lý thông tin thanh toán không bắt buộc với trình chạy 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 nền tảng web và người bán gọi PaymentRequest.show(), thì nhân viên dịch vụ của bạn sẽ nhận được một sự kiện paymentrequest. Thêm trình nghe sự kiện vào trình chạy dịch vụ để ghi lại sự kiện và chuẩn bị cho hành động tiếp theo.

[trình xử lý thanh toán] 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 Nội dung mô tả
topOrigin Một 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 có nhận thanh toán). Hãy sử dụng thông tin 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. API 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ừ bên trong 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ột mã nhận dạng được tạo tự động.
methodData Dữ liệu cụ thể về 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 của 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 hàm này để xây dựng giao diện người dùng và cho khách hàng biết tổng số tiền cần thanh toán.
instrumentKey Khoá xác định xuất phát điểm do người dùng chọn. Thông tin 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ỳ nhạc 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 nền tảng web

Khi nhận được sự kiện paymentrequest, ứng dụng thanh toán có thể mở cửa sổ xử lý thanh toán bằng cách gọi PaymentRequestEvent.openWindow(). Cửa sổ 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 để họ có thể xác thực, chọn địa chỉ và lựa chọn giao hàng, cũng như uỷ quyền thanh toán. Chúng tôi sẽ đề cập đến cách viết mã giao diện người dùng trong bài viết 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 nền tảng web.

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

[trình xử lý thanh toán] 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 lời hứa bất cứ lúc nào.

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

Trình chạy dịch vụ của ứng dụng thanh toán có thể trao đổi tin nhắn 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.

[trình xử lý thanh toán] 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ẽ đợi 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. Trình chạy dịch vụ có thể truyền thông tin quan trọng vào 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'
});

[trình xử lý thanh toán] 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 chi tiết giao dịch vào 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ố tiền của yêu cầu thanh toán, nhưng bạn có thể chuyển thêm thông tin chi tiết nếu muốn.

[trình xử lý thanh toán] 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ả lại thông tin thanh toán của khách hàng

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

Tên tài sản Nội dung mô tả
methodName Mã 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ý khoản 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
  });

[trình xử lý thanh toán] 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 một thông báo sau để trình chạy dịch vụ thực hiện việc này. Sau đó, trình chạy dịch vụ có thể giải quyết lời hứa được chuyể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');

[trình xử lý thanh toán] 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 bạn thấy trong tài liệu này đều được trích từ ứng dụng mẫu hoạt động sau đây:

https://paymenthandler-demo.glitch.me

[trình xử lý thanh toán] trình chạy dịch vụ

[trình xử lý thanh toán] 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 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 vào 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 tôi đã tìm hiểu cách sắp xếp một giao dịch thanh toán từ một trình chạy 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 khác vào trình chạy dịch vụ.