Chuyển tới nội dung chính

Thanh toán tập trung (MiniApp)

Tài liệu này mô tả luồng thanh toán tập trung cho MiniApp – một cải tiến so với luồng thanh toán MiniApp chuẩn nhằm tăng trải nghiệm người dùngđơn giản hóa phần tích hợp promotion/VPoint ở phía MiniApp, trong đó:

  • MiniApp vẫn tích hợp qua JS API của V-App SDK (không gọi trực tiếp Payment Hub).
  • SDK mở một màn hình thanh toán tập trung nơi user có thể:
    • Apply/tiêu VPoint.
    • Apply voucher/khuyến mãi.
    • Chọn và thực hiện thanh toán online (thẻ, ví, v.v.).
  • MiniApp Backend vẫn là nơi tạo và quản lý đơn hàng, nhận IPN từ Payment Service và cập nhật trạng thái đơn.

Luồng này là một cải tiến của luồng thanh toán MiniApp chuẩn trong Tích hợp thanh toán, nhưng centralize việc xử lý promotion/VPoint/thanh toán về phía SDK để mang lại trải nghiệm thống nhất và giảm phức tạp cho MiniApp.

Mô hình kiến trúc

Luồng thanh toán tập trung được thiết kế theo mô hình Centralized Payment Domain with Embedded Benefit Engine: miền thanh toán tập trung (Payment Session, gọi provider, IPN) và (Benefit Engine) — tính toán/áp dụng VPoint, voucher, khuyến mãi. MiniApp chỉ cần truyền order + amount gốc; việc áp dụng benefit và quyết định số tiền cuối thuộc Payment/SDK, đảm bảo logic thống nhất và giảm trùng lặp giữa các PnL.

Yêu cầu tích hợp & quy trình onboard

Quy trình onboard MiniApp, cấp paymentApiKey / secretKey, cấu hình webhook và DevCenter cho luồng thanh toán tập trung này HOÀN TOÀN GIỐNG với tài liệu Tích hợp thanh toán:

  • Không có bước onboard riêng hoặc thêm tham số đặc biệt cho luồng tập trung.
  • Các thông tin:
    • Merchant, Terminal.
    • paymentApiKey, secretKey.
    • Webhook/IPN endpoint.
    • Cấu hình DevCenter.

được dùng chung cho cả luồng MiniApp hiện tại và luồng thanh toán tập trung.

  • Header X-MiniApp-Id: Giống luồng thanh toán chuẩn, khi MiniApp Backend gọi các API Payment Hub (bao gồm API liên quan payment session) có thể gửi header X-MiniApp-Id với giá trị miniAppId (MiniApp ID trong SuperApp). Hiện tại optional (khuyến nghị gửi khi tích hợp mới).

Khái niệm Payment Session

Trong luồng thanh toán tập trung, hệ thống tạo và quản lý một thực thể trung tâm là Payment Session:

  • paymentSessionId: ID duy nhất đại diện cho phiên thanh toán.
  • Liên kết với order: orderId, referenceId.
  • Trạng thái:
    • PENDING: Session vừa tạo, user đang thao tác (chọn phương thức, tiêu VPoint, chọn voucher…).
    • PROCESSING: Đang thực hiện thanh toán online với provider.
    • COMPLETED: Thanh toán thành công, số tiền cuối cùng được xác nhận.
    • CANCELLED: User huỷ hoặc session bị huỷ (timeout/hủy thao tác).
    • EXPIRED: Session hết hạn do user không thao tác trong thời gian cho phép.
  • Dữ liệu trong session (minh hoạ):
    • Số VPoint khả dụng & số VPoint đã tiêu trong session.
    • Danh sách voucher có thể áp dụng & voucher user đã chọn.
    • Phương thức thanh toán online được chọn (card/wallet/QR…).
    • Số tiền gốc, số tiền giảm giá, số tiền phải trả cuối cùng.

SDK sẽ nhận paymentSessionId (hoặc tạo ngầm) và mọi thao tác:

  • Tiêu/bỏ tiêu VPoint.
  • Chọn/bỏ voucher.
  • Chọn phương thức thanh toán online.

đều tương ứng với việc update Payment Session trên backend Payment. Khi user confirm thanh toán:

  1. Payment tính toán số tiền cuối cùng dựa trên session (VPoint, voucher, phương thức thanh toán).
  2. Payment thực hiện thanh toán với provider.
  3. Sau khi có kết quả cuối cùng, Payment:
    • Cập nhật trạng thái paymentSession sang COMPLETED / FAILED / CANCELLED.
    • Gửi IPN về MiniApp Backend với số tiền cuối cùng và thông tin liên quan.

Luồng tổng quan

  1. User thao tác trong MiniApp để đặt hàng.
  2. MiniApp Backend tạo order như hiện tại (bao gồm amount gốc, thông tin khách hàng, items…).
  3. MiniApp gọi JS API của SDK để khởi tạo Payment Session và mở màn hình thanh toán tập trung (init payment session):
    • SDK hiển thị thông tin đơn hàng.
    • SDK cho phép user tiêu VPoint, áp dụng voucher và chọn phương thức thanh toán online.
  4. Sau khi user xác nhận:
    • SDK thực hiện thanh toán qua hệ thống Payment (theo cấu hình merchant/terminal của MiniApp).
    • Payment Service gửi IPN về MiniApp Backend với số tiền thực thu sau khi áp dụng VPoint/voucher.
  5. MiniApp Backend cập nhật trạng thái đơn hàng và số tiền cuối cùng, sau đó MiniApp hiển thị kết quả cho user.

Chi tiết luồng xử lý (tương tự payment.md)

Luồng dưới đây giữ nguyên các bước tạo order ở MiniApp Backend, nhưng thay đổi từ bước khởi tạo thanh toán:

1. Tạo đơn hàng (MiniApp ↔ MiniApp Backend)

  • MiniApp gửi request "create order" đến MiniApp Backend với thông tin đơn hàng.
  • MiniApp Backend xử lý và tạo đơn hàng trong hệ thống:
  • MiniApp Backend trả về thông tin đơn hàng (orderId, referenceId, amount, secureHash, v.v.) cho MiniApp.

2. Khởi tạo phiên thanh toán (MiniApp ↔ SDK)

  • MiniApp gọi JS API của SDK để khởi tạo Payment Session (ví dụ initPaymentSession()), truyền thông tin order, paymentApiKey, và truyền thêm miniAppId (optional).
  • Nếu cần lưu thông tin seller phục vụ hạch toán kế toán trong mô hình marketplace/multi-seller, truyền thêm sellerMerchantId trong payload request. Trường này chỉ mang ý nghĩa metadata/accounting, không đổi luồng tiền; tiền vẫn chuyển về merchant mặc định theo X-Payment-API-Key.
  • Nếu cần giới hạn danh sách thẻ hiển thị theo BIN, có thể truyền thêm allowedCardPrefixes (optional, ví dụ ["970436", "970418"]) để SDK filter card options ngay trong màn hình thanh toán tập trung.
  • Nếu cần giới hạn số tiền VPoint tối đa user được phép tiêu trong session, truyền thêm maxVpointAmount (optional, VND minor unit, phải nhỏ hơn amount). Xem chi tiết tại initPaymentSession (JS API).
  • SDK tạo paymentSessionId (hoặc nhận lại từ Payment Service) và mở màn hình thanh toán tập trung.

3. User thao tác trên màn hình thanh toán tập trung (SDK)

Trên màn hình chung của SDK, user có thể:

  • Tiêu/bỏ tiêu VPoint (theo hạn mức và rule nội bộ).
  • Chọn/bỏ voucher/khuyến mãi khả dụng.
  • Chọn phương thức thanh toán online (thẻ/ ví/ QR/ v.v.).

Các thao tác này tương ứng với việc update Payment Session để tính ra số tiền cuối cùng.

4. Thực hiện thanh toán online & nhận kết quả

  • User bấm Confirm/Pay trên màn SDK.
  • SDK thực hiện thanh toán online qua hệ thống Payment.
  • Payment Service gửi IPN về MiniApp Backend với:
    • Trạng thái giao dịch.
    • Số tiền thực thu cuối cùng sau khi áp dụng VPoint/voucher (nếu có).
  • MiniApp Backend cập nhật trạng thái order và cung cấp trạng thái cho MiniApp (polling/API) để hiển thị cho user.

Sequence diagram (luồng thanh toán tập trung)

Diagram bên dưới giữ nguyên các bước tạo order (tương đương “step < 10” của luồng hiện tại) và thay đổi từ bước khởi tạo thanh toán:

  • Thay vì gọi initPayment(), MiniApp gọi initPaymentSession() để tạo paymentSessionId.
  • SDK mở màn hình thanh toán tập trung để user tiêu VPoint/apply voucher, sau đó mới thanh toán online.

So sánh với luồng thanh toán MiniApp hiện tại

  • Giống nhau:

    • Vẫn cần onboard MiniApp để cấp paymentApiKey / secretKey như mô tả trong Tích hợp thanh toán.
    • MiniApp Backend vẫn:
      • Tạo đơn hàng trong DB.
      • Nhận và xử lý IPN từ Payment Service.
      • Là source of truth về trạng thái và số tiền cuối cùng của order.
  • Khác nhau:

    • Luồng hiện tại (payment.md):
      • MiniApp tự điều khiển luồng chọn phương thức thanh toán và có thể tự kết hợp luật promotion/VPoint ở tầng MiniApp/MiniApp Backend.
      • SDK chủ yếu hiển thị chọn phương thức và khởi tạo thanh toán theo order đã tính toán sẵn.
    • Luồng tập trung (file này):
      • SDK chịu trách nhiệm chính trong việc:
        • Tính toán và apply VPoint.
        • Apply/cộng gộp voucher/khuyến mãi tương thích.
        • Lựa chọn provider/phương thức thanh toán online phù hợp.
      • MiniApp tập trung vào luồng nghiệp vụ chính, chuyển thông tin order sang SDK và xử lý kết quả trả về.

Trách nhiệm các thành phần

MiniApp (Frontend)

  • Thu thập thông tin order từ user.
  • Gọi JS API SDK để:
    • Mở màn hình thanh toán tập trung.
    • Nhận callback kết quả (thành công/thất bại/huỷ).
  • Hiển thị trạng thái thanh toán cuối cùng dựa trên dữ liệu từ MiniApp Backend.

MiniApp Backend

  • Tạo và lưu order trong hệ thống.
  • Nhận IPN từ Payment Service:
    • Với luồng thanh toán tập trung, chỉ có 1 IPN duy nhất được gửi sau khi kết thúc Payment Session (không gửi nhiều IPN trung gian).
    • IPN ngoài các field chuẩn còn có thể kèm breakdown (chi tiết cấu trúc: IPN — Breakdown) để biết rõ tiền qua cổng, voucher, VPoint…
    • Cập nhật trạng thái order (COMPLETED/FAILED/CANCELLED…) và số tiền thực thu.
  • Cung cấp API cho MiniApp để:
    • Lấy trạng thái hiện tại của order.
    • Hiển thị số tiền cuối cùng, số VPoint đã tiêu, khuyến mãi đã áp dụng… (nếu cần).

IPN trong luồng thanh toán tập trung

Đối với luồng thanh toán tập trung:

  • Payment Service gửi một IPN kết thúc khi payment session kết thúc (thành công / failed / cancelled). Xử lý bất đồng bộ và payload tuân Xử lý kết quả thanh toán (IPN) (verify secureHash, retry, v.v.).
  • Khi giao dịch có nhiều nguồn tiền, IPN có thể kèm breakdown. Toàn bộ định nghĩa breakdown (gồm status từng item: PENDING | SUCCESS | FAILED | CANCELLED), details, referenceId, referenceType, quy tắc amount top-level so với tổng các dòng: mục Breakdown trong IPN.
  • paymentMethod / paymentProvider trên payload là primary (VSF Promotion, Vinclub, cổng PSP…); không thay cho breakdown: mục Primary payment method và allocations.

Payment Service / SDK

  • Quản lý cấu hình merchant/terminal, mapping paymentApiKey.
  • Thực hiện:
    • Hiển thị màn hình thanh toán tập trung.
    • Tích hợp với hệ thống VPoint/voucher nội bộ.
    • Gọi Payment Provider để thực hiện thanh toán online.
  • Gửi IPN về MiniApp Backend sau khi có kết quả thanh toán cuối cùng.

Refund khi đơn hàng từ Payment Session

Khi đơn hàng được thanh toán qua luồng tập trung (Payment Session), refund có hai dạng:

  • FULL: Hoàn trả đầy đủ Promotion (voucher), VPoint và tiền. Không cần truyền chi tiết từng phần.
  • PARTIAL: Chỉ hoàn trả phần VPoint và phần tiền (money); không hoàn Promotion. Order Backend bắt buộc truyền đúng số tiền (amount) và số điểm VPoint (refundVpoint) cần hoàn khi gọi API refund.

Chi tiết API và secureHash: Quản lý giao dịch thanh toán (mục Refund Transaction, phần "Refund khi giao dịch từ Payment Session").

Liên kết liên quan