@paid-tw/einvoice-ezpay
v0.4.0
Published
ezPay (ezpay.com.tw) adapter for @paid-tw/einvoice — implements InvoiceProvider over the ezPay e-invoice API.
Readme
@paid-tw/einvoice-ezpay
English | 繁體中文
ezPay(簡單行動支付 / 藍新)用於
@paid-tw/einvoice 的轉接器。
在 ezPay 電子發票 API 之上實作統一的 InvoiceProvider 介面。
pnpm add @paid-tw/einvoice @paid-tw/einvoice-ezpayimport { createEzpayProvider } from "@paid-tw/einvoice-ezpay";
const invoices = createEzpayProvider({
merchantId: process.env.EZPAY_MERCHANT_ID!,
hashKey: process.env.EZPAY_HASH_KEY!, // 32 chars
hashIV: process.env.EZPAY_HASH_IV!, // 16 chars
mode: "TEST", // cinv host; "PRODUCTION" → inv host
});
const result = await invoices.issue({ /* IssueInvoiceInput */ });由於它與 Amego 轉接器實作相同的 InvoiceProvider 介面,切換供應商只需修改一行設定,
你的商業邏輯完全不需要更動。
與 Amego 的差異
| 項目 | ezPay |
| --- | --- |
| 驗證 | AES-256-CBC 加密的 PostData_(HashKey/HashIV),而非 MD5 簽章 |
| 補位 | PKCS7 補位至 32 位元組 的倍數(ezPay 慣例),小寫十六進位 |
| 主機 | 測試 cinv.ezpay.com.tw,正式 inv.ezpay.com.tw(由 mode 選擇) |
| 回應 | 純文字 JSON { Status, Message, Result }(Result 為 JSON 字串) |
| 商品項目 | 以管線符號 \| 串接的 ItemName/ItemCount/ItemUnit/ItemPrice/ItemAmt |
| 驗證碼 | 回應的 CheckCode = 以 HashIV/HashKey 包夾 5 個排序欄位後的 SHA256 |
設定
| 選項 | 必填 | 說明 |
| --- | --- | --- |
| merchantId | ✅ | 商店代號 (MerchantID_) |
| hashKey | ✅ | 32 字元的 AES HashKey(僅限伺服器端) |
| hashIV | ✅ | 16 字元的 AES HashIV(僅限伺服器端) |
| mode | | "TEST"(預設,cinv)或 "PRODUCTION"(inv) |
| respondType | | "JSON"(預設)或 "String" |
| validatePayload | | 在本地端驗證開立的資料內容(預設 true) |
觸發開立 / 觸發折讓(兩階段,ezPay 特有)
除了即時開立之外,ezPay 還支援先保留發票/折讓,之後再觸發。這些功能無法對應到統一介面,
因此以 EzpayProvider 上的額外方法提供:
// Hold an invoice (Status=0) — stored on the platform, not yet issued.
const pending = await invoices.issuePending({ /* IssueInvoiceInput */ });
// Trigger it → real invoice number.
const issued = await invoices.triggerIssue({
invoiceTransNo: pending.invoiceTransNo,
orderId: pending.orderId,
totalAmount: pending.totalAmount,
});
// Confirm / cancel a held allowance (opened with providerOptions: { status: "0" }).
await invoices.triggerAllowance({
allowanceNumber,
orderId,
totalAmount,
action: "CONFIRM", // or "CANCEL"
});保留中(Status=3)的預約發票也可以用 triggerIssue 提前開立。已確認的折讓會在隔天上傳,
之後就無法再取消,若要作廢已上傳的折讓,請改用 voidAllowance。
載具驗證(手機條碼 / 愛心碼)
在開立前先檢查手機條碼載具或捐贈碼是否已於財政部登錄,
背後使用 ezPay 的 /Api_inv_application/ 查詢:
await invoices.validateMobileBarcode("/ABC1234"); // → boolean (IsExist)
await invoices.validateLoveCode("8585"); // → boolean格式會先在本地端檢查(手機條碼 / + 7 個 [0-9A-Z.+-];愛心碼 3–7 位數字)。
宣告為 CARRIER_VALIDATION 能力。
瀏覽器表單 POST(僅建立而不送出)
對於瀏覽器直接 POST 至 ezPay 的流程——例如結果頁面由 ezPay 渲染的查詢(DisplayFlag=1)——
可在不實際發出請求的情況下,建立加密後的表單欄位:
// Generic: encrypt any params for a chosen endpoint.
const { MerchantID_, PostData_ } = invoices.buildPostData({ /* ... */ });
// Query-specific: pass providerOptions.displayFlag to hand the result page to ezPay.
const fields = invoices.buildQueryPostData({
invoiceNumber: "BB00000001",
providerOptions: { randomNum: "4253", displayFlag: "1" },
});
// POST { MerchantID_, PostData_ } as a form to the matching endpoint URL.注意事項
- ezPay 查詢除了統一的
invoiceNumber/orderId之外,還需要一個額外的鍵值: 傳入providerOptions: { randomNum }(SearchType 0)或{ totalAmt }(SearchType 1)。 - 即時生命週期測試會在設定
EZPAY_LIVE=1並提供環境變數憑證的情況下,於測試環境執行: 即時(issue → query → void)、折讓 (issue → allowance → void)、觸發開立(issuePending → triggerIssue → void), 以及觸發折讓(held allowance → cancel)。
授權
MIT
