| name | invoice-adapters |
| description | Taiwan e-invoice integration (台灣電子發票整合). Use when working with ECPay (綠界), EZPay (藍新), BankPro (金財通), or Amego (光貿) invoice services. Covers issuing invoices (開立發票), voiding (作廢), allowances (折讓), and querying invoice data. |
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
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',
});
const invoice = await gateway.issue({
orderId: 'ORDER001',
customer: {
email: 'customer@example.com',
},
carrier: InvoiceCarriers.MOBILE('/ABC+123'),
items: [
{ name: 'Product A', quantity: 2, unitPrice: 100, unit: 'pcs' },
],
});
console.log(invoice.invoiceNumber);
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',
});
const invoice = await gateway.issue({
orderId: 'ORDER_001',
buyerName: '測試買家',
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',
});
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',
});
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,
},
],
});
const b2bInvoice = await gateway.issue({
orderId: 'ORDER-002',
taxType: TaxType.TAXED,
detailVat: true,
items: [
{
name: 'Product A',
quantity: 2,
unitPrice: 100,
unit: 'pcs',
taxType: TaxType.TAXED,
},
],
vatNumber: '55880710',
buyerName: '買方公司名稱',
taxRate: 0.05,
});
console.log(b2bInvoice.vatNumber);
console.log(b2bInvoice.taxRate);
AMEGO_CONSTANTS 常數:
import { AMEGO_CONSTANTS } from '@rytass/invoice-adapter-amego';
AMEGO_CONSTANTS.MAX_ORDER_ID_LENGTH;
AMEGO_CONSTANTS.MAX_ITEM_NAME_LENGTH;
AMEGO_CONSTANTS.MAX_ITEM_UNIT_LENGTH;
AMEGO_CONSTANTS.MAX_ITEM_REMARK_LENGTH;
AMEGO_CONSTANTS.DEFAULT_TAX_RATE;
AMEGO_CONSTANTS.LOVE_CODE_MIN_LENGTH;
AMEGO_CONSTANTS.LOVE_CODE_MAX_LENGTH;
Common Operations
Void an Invoice
注意: 各 adapter 的 void 參數不同:
- ECPay/EZPay: 需要
reason 參數
- BankPro: options 為可選,只有
sellerCode 參數
- Amego: 完全不需要 options 參數
const voidedInvoice = await gateway.void(invoice, {
reason: 'Customer requested cancellation',
});
const voidedInvoice = await gateway.void(invoice);
const voidedInvoice = await gateway.void(invoice, { sellerCode: 'SELLER01' });
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
const invoice = await gateway.query({ orderId: 'ORDER-001' });
const invoice = await gateway.query({
invoiceNumber: 'AB12345678',
issuedOn: new Date('2024-01-15'),
});
const ezpayInvoice = await ezpayGateway.query({
orderId: 'ORDER-001',
amount: 1000,
});
const ezpayInvoice = await ezpayGateway.query({
invoiceNumber: 'AB12345678',
randomCode: '1234',
});
const amegoInvoice = await amegoGateway.query({
invoiceNumber: 'AB12345678',
});
Validate Carrier Codes
const isValid = await gateway.isMobileBarcodeValid('/ABC1234');
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',
endDate: '2024-01-31',
onlyAward: false,
onlyInvalid: false,
});
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]) {
console.log(`Valid GUI, Company: ${result[1]}`);
} else {
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
完整 EZPay ErrorCode 列表
| 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
BankProInvoiceStatus.UPDATE
BankProInvoiceStatus.DELETE
BankProInvoiceStatus.ALLOWANCE
BankProInvoiceStatus.INVALID_ALLOWANCE
Additional Types
Amego Types
import {
AmegoTaxType,
ReverseAmegoTaxType,
AmegoAllowanceType,
} from '@rytass/invoice-adapter-amego';
import { TaxType } from '@rytass/invoice';
AmegoTaxType[TaxType.TAXED];
AmegoTaxType[TaxType.ZERO_TAX];
AmegoTaxType[TaxType.TAX_FREE];
AmegoTaxType[TaxType.SPECIAL];
AmegoTaxType[TaxType.MIXED];
ReverseAmegoTaxType[1];
ReverseAmegoTaxType[2];
ReverseAmegoTaxType[3];
AmegoAllowanceType.BUYER_ISSUED
AmegoAllowanceType.SELLER_ISSUED
EZPay Types
import {
EZPayInvoiceIssueStatus,
EZPayTaxTypeCode,
} from '@rytass/invoice-adapter-ezpay';
import { TaxType } from '@rytass/invoice';
EZPayInvoiceIssueStatus.INSTANT
EZPayInvoiceIssueStatus.WAITING
EZPayInvoiceIssueStatus.DELAY
EZPayTaxTypeCode[TaxType.TAXED];
EZPayTaxTypeCode[TaxType.ZERO_TAX];
EZPayTaxTypeCode[TaxType.TAX_FREE];
EZPayTaxTypeCode[TaxType.MIXED];
BankPro Types
import { BankProRateType } from '@rytass/invoice-adapter-bank-pro';
import { TaxType } from '@rytass/invoice';
BankProRateType[TaxType.TAXED];
BankProRateType[TaxType.ZERO_TAX];
BankProRateType[TaxType.TAX_FREE];
Environment Configuration
All adapters support development and production environments:
import { ECPayInvoiceGateway } from '@rytass/invoice-adapter-ecpay';
const gateway = new ECPayInvoiceGateway();
const prodGateway = new ECPayInvoiceGateway({
baseUrl: 'https://einvoice.ecpay.com.tw',
});
import { EZPayInvoiceGateway, EZPayBaseUrls } from '@rytass/invoice-adapter-ezpay';
const gateway = new EZPayInvoiceGateway({
baseUrl: EZPayBaseUrls.PRODUCTION,
});
import { BankProInvoiceGateway, BankProBaseUrls } from '@rytass/invoice-adapter-bank-pro';
const gateway = new BankProInvoiceGateway({
baseUrl: BankProBaseUrls.PRODUCTION,
});
import { AmegoInvoiceGateway, AmegoBaseUrls } from '@rytass/invoice-adapter-amego';
const gateway = new AmegoInvoiceGateway({
baseUrl: AmegoBaseUrls.PRODUCTION,
});
Detailed Documentation
For complete API reference including all methods, types, and advanced usage: