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 tính nă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 từ 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ổ đó).

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

"Thay đổi thông số thanh toán trong thời gian chạy" là 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 tin nhắn 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 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 web của bạn và người bán gọi PaymentRequest.show(), trình chạy dịch vụ 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 nhận thanh toán). 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. Điều này có thể giống như 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 một bên thứ ba gọi từ bên trong iframe, chẳng hạn như cổng thanh toán.
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ã đượ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 mã 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 mã 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 thanh toán.
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ỳ 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 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. Tại đây, họ có thể xác thực, chọn địa chỉ và tuỳ chọn giao hàng cũng như cho phép 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ý khoản 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.

Truyền một lời hứa đã lưu lại cho PaymentRequestEvent.respondWith() để bạn có thể giải quyết bằng cách đưa ra 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 để phân giải 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

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ẽ 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. Trình chạy 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.

Giao diện người dùng [thanh toán]:

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 thông tin 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ố 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;
…

Giao diện người dùng [thanh toán]:

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 thông báo bài đăng đến 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 mà bạ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.

Giao diện người dùng [thanh toán]:

  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 thông báo bài đăng tới trình chạy dịch vụ để thực hiện việc này. Sau đó, trình chạy dịch vụ này 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ỷ.

Giao diện người dùng [thanh toán]:

  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 mà bạn thấy trong tài liệu này đều được trích dẫn từ ứng dụng mẫu hoạt động sau đây:

https://paymenthandler-demo.glitch.me

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

[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 Thêm nút 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 ta đã tìm hiểu cách sắp xếp một giao dịch thanh toán qua 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 hơn vào trình chạy dịch vụ.