skills/rytass/utils/invoice-adapters

invoice-adapters

SKILL.md

Taiwan E-Invoice Adapters

This skill provides guidance for using @rytass/invoice-adapter-* packages to integrate Taiwan e-invoice services.

Overview

All adapters implement the InvoiceGateway interface from @rytass/invoice, providing a unified API across different providers:

Package Provider Description
@rytass/invoice-adapter-ecpay ECPay (綠界科技) Most popular Taiwan payment gateway
@rytass/invoice-adapter-ezpay EZPay (藍新科技) Also known as NewebPay
@rytass/invoice-adapter-bank-pro BankPro (金財通) Bank-integrated invoice service
@rytass/invoice-adapter-amego Amego (光貿) Enterprise invoice platform

Installation

# Choose the adapter for your provider
npm install @rytass/invoice-adapter-ecpay
npm install @rytass/invoice-adapter-ezpay
npm install @rytass/invoice-adapter-bank-pro
npm install @rytass/invoice-adapter-amego

Quick Start

ECPay

import { ECPayInvoiceGateway } from '@rytass/invoice-adapter-ecpay';
import { TaxType, InvoiceCarriers } from '@rytass/invoice';

const gateway = new ECPayInvoiceGateway({
  merchantId: 'YOUR_MERCHANT_ID',
  aesKey: 'YOUR_AES_KEY',
  aesIv: 'YOUR_AES_IV',
  // 可選: 跳過手機條碼/愛心碼驗證
  // skipMobileBarcodeValidation: true,
  // skipLoveCodeValidation: true,
});

// Issue an invoice
const invoice = await gateway.issue({
  orderId: 'ORDER001',  // alphanumeric only, max 30 chars
  customer: {
    email: 'customer@example.com',  // must provide email or mobile
  },
  carrier: InvoiceCarriers.MOBILE('/ABC+123'),
  items: [
    { name: 'Product A', quantity: 2, unitPrice: 100, unit: 'pcs' },
  ],
});

console.log(invoice.invoiceNumber); // e.g., "AB12345678"

EZPay

import { EZPayInvoiceGateway } from '@rytass/invoice-adapter-ezpay';
import { TaxType, InvoiceCarrierType } from '@rytass/invoice';

const gateway = new EZPayInvoiceGateway({
  merchantId: 'YOUR_MERCHANT_ID',
  hashKey: 'YOUR_HASH_KEY',
  hashIv: 'YOUR_HASH_IV',
});

// Issue a B2C invoice
const invoice = await gateway.issue({
  orderId: 'ORDER_001',  // alphanumeric + underscore, max 20 chars
  buyerName: '測試買家',  // required, max 30 chars for B2C
  carrier: { type: InvoiceCarrierType.MOBILE, code: '/ABC+123' },
  items: [
    { name: 'Product A', quantity: 2, unitPrice: 100, unit: 'pcs' },
  ],
});

BankPro

import { BankProInvoiceGateway } from '@rytass/invoice-adapter-bank-pro';

const gateway = new BankProInvoiceGateway({
  user: 'YOUR_USER',
  password: 'YOUR_PASSWORD',
  systemOID: 12345,
  sellerBAN: '12345678',
});

// Issue an invoice
const invoice = await gateway.issue({
  orderId: 'ORDER-001',
  buyerEmail: 'customer@example.com',
  items: [
    { name: 'Product A', quantity: 2, unitPrice: 100, unit: 'pcs' },
  ],
});

Amego

import { AmegoInvoiceGateway, AMEGO_CONSTANTS } from '@rytass/invoice-adapter-amego';

const gateway = new AmegoInvoiceGateway({
  appKey: 'YOUR_APP_KEY',
  vatNumber: '12345678', // 賣方統一編號(必填)
});

// Issue a B2C invoice (消費者發票)
// 注意: Amego 的 taxType 和 detailVat 為必填,item 的 taxType 也是必填
import { TaxType } from '@rytass/invoice';

const b2cInvoice = await gateway.issue({
  orderId: 'ORDER-001',
  taxType: TaxType.TAXED,  // 必填: 課稅別
  detailVat: true,          // 必填: 單價含稅
  items: [
    {
      name: 'Product A',
      quantity: 2,
      unitPrice: 100,
      unit: 'pcs',
      taxType: TaxType.TAXED,  // 必填: 商品課稅別
    },
  ],
  // vatNumber 不填則為 B2C 發票(預設 '0000000000')
});

// Issue a B2B invoice (公司發票)
const b2bInvoice = await gateway.issue({
  orderId: 'ORDER-002',
  taxType: TaxType.TAXED,  // 必填
  detailVat: true,         // 必填: 明細單價類型: true=含稅, false=未稅
  items: [
    {
      name: 'Product A',
      quantity: 2,
      unitPrice: 100,
      unit: 'pcs',
      taxType: TaxType.TAXED,  // 必填
    },
  ],
  vatNumber: '55880710',   // 買方統一編號
  buyerName: '買方公司名稱',
  taxRate: 0.05,           // 稅率,預設 5%
});

// Invoice 物件包含 taxRate 和 vatNumber
console.log(b2bInvoice.vatNumber); // '55880710'
console.log(b2bInvoice.taxRate);   // 0.05

AMEGO_CONSTANTS 常數:

import { AMEGO_CONSTANTS } from '@rytass/invoice-adapter-amego';

// 欄位長度限制
AMEGO_CONSTANTS.MAX_ORDER_ID_LENGTH;    // 40 字元
AMEGO_CONSTANTS.MAX_ITEM_NAME_LENGTH;   // 256 字元
AMEGO_CONSTANTS.MAX_ITEM_UNIT_LENGTH;   // 6 字元
AMEGO_CONSTANTS.MAX_ITEM_REMARK_LENGTH; // 40 字元

// 預設值
AMEGO_CONSTANTS.DEFAULT_TAX_RATE;       // 0.05 (5%)
AMEGO_CONSTANTS.LOVE_CODE_MIN_LENGTH;   // 3
AMEGO_CONSTANTS.LOVE_CODE_MAX_LENGTH;   // 7

Common Operations

Void an Invoice

注意: 各 adapter 的 void 參數不同:

  • ECPay/EZPay: 需要 reason 參數
  • BankPro: options 為可選,只有 sellerCode 參數
  • Amego: 完全不需要 options 參數
// ECPay / EZPay
const voidedInvoice = await gateway.void(invoice, {
  reason: 'Customer requested cancellation',
});

// BankPro
const voidedInvoice = await gateway.void(invoice);
// 或
const voidedInvoice = await gateway.void(invoice, { sellerCode: 'SELLER01' });

// Amego
const voidedInvoice = await gateway.void(invoice);

Create an Allowance (Partial Refund)

const updatedInvoice = await gateway.allowance(invoice, [
  { name: 'Product A', quantity: 1, unitPrice: 100, unit: 'pcs' },
]);

Query an Invoice

// By order ID (ECPay, BankPro, Amego)
const invoice = await gateway.query({ orderId: 'ORDER-001' });

// By invoice number (ECPay requires issuedOn date)
const invoice = await gateway.query({
  invoiceNumber: 'AB12345678',
  issuedOn: new Date('2024-01-15'),
});

// EZPay: By order ID (需要 amount 參數)
const ezpayInvoice = await ezpayGateway.query({
  orderId: 'ORDER-001',
  amount: 1000,  // 發票金額(必填)
});

// EZPay: By invoice number
const ezpayInvoice = await ezpayGateway.query({
  invoiceNumber: 'AB12345678',
  randomCode: '1234',  // 隨機碼(必填)
});

// Amego: By invoice number
const amegoInvoice = await amegoGateway.query({
  invoiceNumber: 'AB12345678',
});

Validate Carrier Codes

// Check mobile barcode validity
const isValid = await gateway.isMobileBarcodeValid('/ABC1234');

// Check love code validity
const isValid = await gateway.isLoveCodeValid('168001');

ECPay: List Invoices (分頁查詢)

import { ECPayInvoiceGateway, ECPayInvoiceListQueryOptions } from '@rytass/invoice-adapter-ecpay';

// 列出指定日期範圍內的發票
const invoices = await gateway.list({
  startDate: '2024-01-01', // YYYY-MM-DD
  endDate: '2024-01-31',   // YYYY-MM-DD
  onlyAward: false,        // 只查詢中獎發票
  onlyInvalid: false,      // 只查詢作廢發票
});

// 自動分頁取得所有發票(每頁 200 筆)
console.log(`Found ${invoices.length} invoices`);

ECPay: Validate GUI (驗證統一編號)

import { ECPayInvoiceGateway } from '@rytass/invoice-adapter-ecpay';

// 驗證統一編號並取得公司名稱
const result = await gateway.isValidGUI('12345678');

if (result[0]) {
  // [true, 'Company Name']
  console.log(`Valid GUI, Company: ${result[1]}`);
} else {
  // [false]
  console.log('Invalid GUI');
}

// 注意:此功能為輔助驗證,無法涵蓋所有公司/組織

Feature Comparison

Feature ECPay EZPay BankPro Amego
Issue Invoice Yes Yes Yes Yes
Void Invoice Yes Yes Yes Yes
Allowance Yes Yes Yes Yes
Invalid Allowance Yes Yes Yes Yes
Query Invoice Yes Yes Yes Yes
List Invoices Yes No No No
Mobile Barcode Validation Yes Yes No Yes
Love Code Validation Yes Yes No No
GUI (VAT Number) Validation Yes No No No
B2B Invoice Yes Yes Yes Yes
B2C Invoice Yes Yes Yes Yes
Print Carrier Yes Yes Yes No
Mobile Carrier Yes Yes No Yes
MOICA Carrier Yes Yes No Yes
Love Code Donation Yes Yes No Yes
Platform Carrier No Yes No Yes

Error Handling

EZPay Error Codes

EZPay 提供詳細的錯誤碼枚舉,可用於錯誤處理:

import { ErrorCode } from '@rytass/invoice-adapter-ezpay';

// 常見錯誤碼
ErrorCode.KEY10002  // '資料解密錯誤'
ErrorCode.KEY10004  // '資料不齊全'
ErrorCode.KEY10006  // '商店未申請啟用電子發票'
ErrorCode.INV10003  // '商品資訊格式錯誤或缺少資料'
ErrorCode.INV10013  // '發票欄位資料不齊全或格式錯誤'
ErrorCode.INV20006  // '查無發票資料'
ErrorCode.LIB10003  // '商店自訂編號重覆'
ErrorCode.LIB10005  // '發票已作廢過'
ErrorCode.INV90006  // '可開立張數已用罄'
Code 說明
KEY10002 資料解密錯誤
KEY10004 資料不齊全
KEY10006 商店未申請啟用電子發票
KEY10007 頁面停留超過 30 分鐘
KEY10010 商店代號空白
KEY10011 PostData_欄位空白
KEY10012 資料傳遞錯誤
KEY10013 資料空白
KEY10014 TimeOut
KEY10015 發票金額格式錯誤
INV10003 商品資訊格式錯誤或缺少資料
INV10004 商品資訊的商品小計計算錯誤
INV10006 稅率格式錯誤
INV10012 發票金額、課稅別驗證錯誤
INV10013 發票欄位資料不齊全或格式錯誤
INV10014 自訂編號格式錯誤
INV10015 無未稅金額
INV10016 無稅金
INV10017 輸入的版本不支援混合稅率功能
INV10019 資料含有控制碼
INV10020 暫停使用
INV10021 異常終止
INV70001 欄位資料格式錯誤
INV70002 上傳失敗之發票不得作廢
INV90005 未簽定合約或合約已到期
INV90006 可開立張數已用罄
NOR10001 網路連線異常
LIB10003 商店自訂編號重覆
LIB10005 發票已作廢過
LIB10007 無法作廢
LIB10008 超過可作廢期限
LIB10009 發票已開立,但未上傳至財政部,無法作廢
IAI10001 缺少參數 作廢折讓錯誤代碼
IAI10002 查詢失敗 作廢折讓錯誤代碼
IAI10003 更新失敗 作廢折讓錯誤代碼
IAI10004 參數錯誤 作廢折讓錯誤代碼
IAI10005 新增失敗 作廢折讓錯誤代碼
IAI10006 異常終止
API10001 缺少參數
API10002 查詢失敗
API10004 參數錯誤
CBC10001 欄位資料空白
CBC10002 欄位資料格式錯誤
CBC10003 異常終止
CBC10004 財政部大平台網路連線異常

BankPro Invoice Status

BankPro 提供發票狀態枚舉:

import { BankProInvoiceStatus } from '@rytass/invoice-adapter-bank-pro';

// 發票狀態
BankProInvoiceStatus.CREATE            // '0' - 新增
BankProInvoiceStatus.UPDATE            // '1' - 更新
BankProInvoiceStatus.DELETE            // '2' - 作廢
BankProInvoiceStatus.ALLOWANCE         // '3' - 折讓
BankProInvoiceStatus.INVALID_ALLOWANCE // '4' - 作廢折讓

Additional Types

Amego Types

import {
  AmegoTaxType,
  ReverseAmegoTaxType,
  AmegoAllowanceType,
} from '@rytass/invoice-adapter-amego';
import { TaxType } from '@rytass/invoice';

// TaxType 轉 Amego API 值
AmegoTaxType[TaxType.TAXED];     // '1'
AmegoTaxType[TaxType.ZERO_TAX];  // '2'
AmegoTaxType[TaxType.TAX_FREE];  // '3'
AmegoTaxType[TaxType.SPECIAL];   // '4'
AmegoTaxType[TaxType.MIXED];     // '9'

// Amego API 值轉回 TaxType
ReverseAmegoTaxType[1];  // TaxType.TAXED
ReverseAmegoTaxType[2];  // TaxType.ZERO_TAX
ReverseAmegoTaxType[3];  // TaxType.TAX_FREE

// 折讓類型
AmegoAllowanceType.BUYER_ISSUED   // 1 - 買方開立
AmegoAllowanceType.SELLER_ISSUED  // 2 - 賣方開立

EZPay Types

import {
  EZPayInvoiceIssueStatus,
  EZPayTaxTypeCode,
} from '@rytass/invoice-adapter-ezpay';
import { TaxType } from '@rytass/invoice';

// 發票開立狀態
EZPayInvoiceIssueStatus.INSTANT  // '1' - 即時開立
EZPayInvoiceIssueStatus.WAITING  // '0' - 等待開立
EZPayInvoiceIssueStatus.DELAY    // '3' - 延遲開立

// TaxType 轉 EZPay API 值
EZPayTaxTypeCode[TaxType.TAXED];     // '1'
EZPayTaxTypeCode[TaxType.ZERO_TAX];  // '2'
EZPayTaxTypeCode[TaxType.TAX_FREE];  // '3'
EZPayTaxTypeCode[TaxType.MIXED];     // '9'

BankPro Types

import { BankProRateType } from '@rytass/invoice-adapter-bank-pro';
import { TaxType } from '@rytass/invoice';

// TaxType 轉 BankPro API 值
BankProRateType[TaxType.TAXED];     // '1'
BankProRateType[TaxType.ZERO_TAX];  // '2'
BankProRateType[TaxType.TAX_FREE];  // '3'

Environment Configuration

All adapters support development and production environments:

// ECPay
import { ECPayInvoiceGateway } from '@rytass/invoice-adapter-ecpay';
const gateway = new ECPayInvoiceGateway(); // Development by default
const prodGateway = new ECPayInvoiceGateway({
  baseUrl: 'https://einvoice.ecpay.com.tw',
  // ... credentials
});

// EZPay
import { EZPayInvoiceGateway, EZPayBaseUrls } from '@rytass/invoice-adapter-ezpay';
const gateway = new EZPayInvoiceGateway({
  baseUrl: EZPayBaseUrls.PRODUCTION,
  // ... credentials
});

// BankPro
import { BankProInvoiceGateway, BankProBaseUrls } from '@rytass/invoice-adapter-bank-pro';
const gateway = new BankProInvoiceGateway({
  baseUrl: BankProBaseUrls.PRODUCTION,
  // ... credentials
});

// Amego
import { AmegoInvoiceGateway, AmegoBaseUrls } from '@rytass/invoice-adapter-amego';
const gateway = new AmegoInvoiceGateway({
  baseUrl: AmegoBaseUrls.PRODUCTION,
  // ... credentials
});

Detailed Documentation

For complete API reference including all methods, types, and advanced usage:

Weekly Installs
7
Repository
rytass/utils
GitHub Stars
6
First Seen
Feb 5, 2026
Installed on
amp7
gemini-cli7
github-copilot7
codex7
kimi-cli7
opencode7