skills/rytass/utils/payment-development

payment-development

SKILL.md

Payment Development Guide

This skill provides guidance for developers working with the @rytass/payments base package, including creating new payment adapters.

Overview

The @rytass/payments package defines the core interfaces and types that all payment adapters must implement. It follows the adapter pattern to provide a unified API across different Taiwan payment providers.

Architecture

@rytass/payments (Base Package)
    ├── PaymentGateway<OCM, O>        # Gateway interface
    ├── Order<OCM>                    # Order entity interface
    ├── BindCardPaymentGateway<...>   # Card binding interface (optional)
    ├── Enums & Types                 # Shared types
    └── Event System                  # EventEmitter-based callbacks

@rytass/payments-adapter-*           # Provider implementations
    ├── [Provider]Payment             # Implements PaymentGateway
    ├── [Provider]Order               # Implements Order
    └── [Provider]BindCard            # Implements card binding (optional)

Installation

npm install @rytass/payments

Core Interfaces

PaymentItem

Item included in an order:

interface PaymentItem {
  name: string;
  unitPrice: number;
  quantity: number;
}

PaymentGateway

The main interface that all adapters must implement:

interface PaymentGateway<
  OCM extends OrderCommitMessage = OrderCommitMessage,
  O extends Order<OCM> = Order<OCM>,
> {
  emitter: EventEmitter;
  prepare<N extends OCM>(input: InputFromOrderCommitMessage<N>): Promise<Order<N>>;
  query<OO extends O>(id: string, options?: unknown): Promise<OO>;
}

PrepareOrderInput

Base input interface for orders:

interface PrepareOrderInput<I extends PaymentItem = PaymentItem> {
  items: I[];
}

Order

The order entity interface:

interface Order<OCM extends OrderCommitMessage> extends PrepareOrderInput {
  state: OrderState;
  createdAt: Date | null;
  committedAt: Date | null;
  additionalInfo?: AdditionalInfo<OCM>;
  asyncInfo?: AsyncOrderInformation<OCM>;
  failedMessage: OrderFailMessage | null;
  id: string;
  items: PaymentItem[];
  committable: boolean;

  infoRetrieved<T extends OCM>(asyncInformation: AsyncOrderInformation<T>): void;
  fail(code: string, message: string): void;
  commit<T extends OCM>(message: T, additionalInfo?: AdditionalInfo<T>): void;
  refund(amount?: number, options?: unknown): Promise<void>;
}

InputFromOrderCommitMessage

Input type for creating orders via prepare():

interface InputFromOrderCommitMessage<OCM extends OrderCommitMessage> extends PrepareOrderInput {
  id?: string;
  shopName?: string;
  clientBackUrl?: string;
  cardType?: CardType;
}

BindCardRequest

Card binding request interface:

interface BindCardRequest {
  cardId: string | undefined;
  memberId: string;
}

CheckoutWithBoundCardOptions

Options for checkout with bound card:

interface CheckoutWithBoundCardOptions {
  cardId: string;       // 綁定的卡片 ID
  memberId: string;     // 綁定會員 ID
  items: PaymentItem[];
  orderId?: string;     // 可選的訂單 ID,若未提供則自動生成
}

BindCardPaymentGateway (Optional)

For adapters supporting card binding:

interface BindCardPaymentGateway<
  CM extends OrderCommitMessage = OrderCommitMessage,
  R extends BindCardRequest = BindCardRequest,
  O extends Order<CM> = Order<CM>,
> {
  prepareBindCard(memberId: string): Promise<R>;
  checkoutWithBoundCard(options: CheckoutWithBoundCardOptions): Promise<O>;
}

Quick Reference

Order Lifecycle

INITED
  ↓ prepare()
PRE_COMMIT (Created - form/URL ready)
  ↓ User completes payment
ASYNC_INFO_RETRIEVED (for ATM/CVS - virtual account/code ready)
  ↓ User pays at bank/CVS
COMMITTED (Payment successful)
  ↓ OR
FAILED (Payment failed)
  ↓ (optional)
REFUNDED (Refund processed)

Channel Enum (支付通道)

import { Channel } from '@rytass/payments';

enum Channel {
  CREDIT_CARD = 'CREDIT_CARD',      // 信用卡
  WEB_ATM = 'WEB_ATM',              // 網路 ATM
  VIRTUAL_ACCOUNT = 'VIRTUAL_ACCOUNT', // 虛擬帳號
  CVS_KIOSK = 'CVS_KIOSK',          // 超商代碼繳費
  CVS_BARCODE = 'CVS_BARCODE',      // 超商條碼繳費
  APPLE_PAY = 'APPLE_PAY',          // Apple Pay
  LINE_PAY = 'LINE_PAY',            // LINE Pay
}

Payment Channels

Channel Description Commit Type
CREDIT_CARD Credit/Debit Card Sync
VIRTUAL_ACCOUNT ATM Virtual Account Async
WEB_ATM Online ATM Async
CVS_KIOSK Convenience Store Code Async
CVS_BARCODE Convenience Store Barcode Async
APPLE_PAY Apple Pay Sync
LINE_PAY LINE Pay Sync

OrderState Enum

enum OrderState {
  INITED = 'INITED',
  PRE_COMMIT = 'PRE_COMMIT',                 // Created
  ASYNC_INFO_RETRIEVED = 'ASYNC_INFO_RETRIEVED', // Async Payment Information Retrieved (ATM/CVS/Barcode...)
  COMMITTED = 'COMMITTED',                   // Fulfilled
  FAILED = 'FAILED',
  REFUNDED = 'REFUNDED',
}
State Description
INITED Order initialized
PRE_COMMIT Order created, awaiting payment
ASYNC_INFO_RETRIEVED Async payment info ready (ATM/CVS)
COMMITTED Payment successful
FAILED Payment failed
REFUNDED Order refunded

OrderFailMessage

interface OrderFailMessage {
  code: string;
  message: string;
}

Card Types

import { CardType } from '@rytass/payments';

enum CardType {
  VMJ = 'VMJ',  // Visa, MasterCard, JCB
  AE = 'AE',    // American Express
}

CVS (便利商店)

import { CVS } from '@rytass/payments';

enum CVS {
  FAMILY_MART = 'FAMILY_MART',    // 全家
  HILIFE = 'HILIFE',              // 萊爾富
  OK_MART = 'OK_MART',            // OK 超商
  SEVEN_ELEVEN = 'SEVEN_ELEVEN',  // 7-11
}

CreditCardECI (3D 驗證結果)

import { CreditCardECI } from '@rytass/payments';

enum CreditCardECI {
  MASTER_3D = '2',           // MasterCard 3D 驗證成功
  MASTER_3D_PART = '1',      // MasterCard 部分驗證
  MASTER_3D_FAILED = '0',    // MasterCard 驗證失敗
  VISA_AE_JCB_3D = '5',      // Visa/AE/JCB 3D 驗證成功
  VISA_AE_JCB_3D_PART = '6', // Visa/AE/JCB 部分驗證
  VISA_AE_JCB_3D_FAILED = '7', // Visa/AE/JCB 驗證失敗
}

PaymentPeriod (定期定額)

import { PaymentPeriod, PaymentPeriodType } from '@rytass/payments';

enum PaymentPeriodType {
  DAY = 'DAY',     // 每日
  MONTH = 'MONTH', // 每月
  YEAR = 'YEAR',   // 每年
}

interface PaymentPeriod {
  amountPerPeriod: number;  // 每期金額
  type: PaymentPeriodType;  // 週期類型
  frequency?: number;       // 頻率(可選)
  times: number;            // 扣款次數
}

Payment Events

enum PaymentEvents {
  SERVER_LISTENED = 'LISTENED',
  ORDER_INFO_RETRIEVED = 'INFO_RETRIEVED',
  ORDER_PRE_COMMIT = 'PRE_COMMIT',
  ORDER_COMMITTED = 'COMMITTED',
  ORDER_FAILED = 'FAILED',
  CARD_BOUND = 'CARD_BOUND',
  CARD_BINDING_FAILED = 'CARD_BINDING_FAILED',
}
Event When Triggered
SERVER_LISTENED Built-in server started
ORDER_PRE_COMMIT Order created (form/URL ready)
ORDER_INFO_RETRIEVED Async payment info ready
ORDER_COMMITTED Payment successful
ORDER_FAILED Payment failed
CARD_BOUND Card bound successfully
CARD_BINDING_FAILED Card binding failed

Event Usage

import { PaymentEvents } from '@rytass/payments';

payment.emitter.on(PaymentEvents.ORDER_COMMITTED, (order) => {
  console.log('Payment successful:', order.id);
});

payment.emitter.on(PaymentEvents.ORDER_FAILED, (order) => {
  console.error('Payment failed:', order.failedMessage);
});

OrderCommitMessage Types

Base commit message and channel-specific types:

// Base commit message
interface OrderCommitMessage {
  id: string;
  totalPrice: number;
  committedAt: Date | null;
}

// Credit Card
interface OrderCreditCardCommitMessage extends OrderCommitMessage {
  type?: Channel.CREDIT_CARD;
  id: string;
  totalPrice: number;
  committedAt: Date;
  cardType?: CardType;
}

// Virtual Account (ATM)
interface OrderVirtualAccountCommitMessage extends OrderCommitMessage {
  type?: Channel.VIRTUAL_ACCOUNT;
  id: string;
  totalPrice: number;
  committedAt: Date | null;
}

// CVS Kiosk
interface OrderCVSCommitMessage extends OrderCommitMessage {
  type?: Channel.CVS_KIOSK;
  id: string;
  totalPrice: number;
  committedAt: Date | null;
}

// CVS Barcode
interface OrderBarcodeCommitMessage extends OrderCommitMessage {
  type?: Channel.CVS_BARCODE;
  id: string;
  totalPrice: number;
  committedAt: Date | null;
}

// Apple Pay
interface OrderApplePayCommitMessage extends OrderCommitMessage {
  type?: Channel.APPLE_PAY;
  id: string;
  totalPrice: number;
  committedAt: Date | null;
}

// LINE Pay
interface OrderLinePayCommitMessage extends OrderCommitMessage {
  type?: Channel.LINE_PAY;
  id: string;
  totalPrice: number;
  committedAt: Date | null;
}

// WebATM
interface OrderWebATMCommitMessage extends OrderCommitMessage {
  type?: Channel.WEB_ATM;
  id: string;
  totalPrice: number;
  committedAt: Date | null;
}

AsyncOrderInformation Type

Conditional type for async payment info based on commit message type:

type AsyncOrderInformation<OCM extends OrderCommitMessage> =
  OCM extends OrderVirtualAccountCommitMessage
    ? VirtualAccountInfo
    : OCM extends OrderCVSCommitMessage
      ? CVSInfo
      : OCM extends OrderBarcodeCommitMessage
        ? BarcodeInfo
        : never;

AdditionalInfo Type

Conditional type for additional payment info based on commit message type:

type AdditionalInfo<OCM extends OrderCommitMessage> =
  OCM extends OrderCreditCardCommitMessage
    ? CreditCardAuthInfo
    : OCM extends OrderVirtualAccountCommitMessage
      ? VirtualAccountPaymentInfo
      : OCM extends OrderWebATMCommitMessage
        ? WebATMPaymentInfo
        : OCM extends OrderCVSCommitMessage
          ? CVSPaymentInfo
          : OCM extends OrderBarcodeCommitMessage
            ? BarcodeInfo
            : OCM extends OrderApplePayCommitMessage
              ? undefined
              : never;

Info Types

For async payment channels:

// Virtual Account (ATM)
interface VirtualAccountInfo {
  channel: Channel.VIRTUAL_ACCOUNT;
  bankCode: string;
  account: string;
  expiredAt: Date;
}

// CVS Kiosk
interface CVSInfo {
  channel: Channel.CVS_KIOSK;
  paymentCode: string;
  expiredAt: Date;
}

// CVS Barcode
interface BarcodeInfo {
  channel: Channel.CVS_BARCODE;
  barcodes: [string, string, string];
  expiredAt: Date;
}

For credit card authorization:

interface CreditCardAuthInfo {
  channel: Channel.CREDIT_CARD;
  processDate: Date;
  authCode: string;       // 信用卡授權碼 (6 碼)
  amount: number;
  eci: CreditCardECI;     // 3D 驗證結果
  card4Number: string;    // 卡號末 4 碼
  card6Number: string;    // 卡號前 6 碼
  gwsr?: string;          // 閘道序號(可選)
  xid?: string;           // 交易 ID(可選)
  aetId?: string;         // AE 交易 ID(可選)
}

For WebATM payment:

interface WebATMPaymentInfo {
  channel: Channel.WEB_ATM;
  buyerAccountNumber: string;  // 付款人帳號
  buyerBankCode: string;       // 付款人銀行代碼
}

For Virtual Account payment (付款後):

interface VirtualAccountPaymentInfo {
  channel: Channel.VIRTUAL_ACCOUNT;
  buyerAccountNumber: string;  // 付款人帳號
  buyerBankCode: string;       // 付款人銀行代碼
}

For CVS payment:

interface CVSPaymentInfo {
  channel: Channel.CVS_KIOSK;
  cvsPayFrom: CVS;  // 付款超商
}

Detailed Documentation

For complete interface specifications and implementation guide:

Weekly Installs
6
Repository
rytass/utils
GitHub Stars
6
First Seen
Feb 5, 2026
Installed on
amp6
gemini-cli6
replit6
github-copilot6
codex6
kimi-cli6