Invoice Development Guide
This skill provides guidance for developers working with the @rytass/invoice base package, including creating new invoice adapters.
Overview
The @rytass/invoice package defines the core interfaces and types that all invoice adapters must implement. It follows the adapter pattern to provide a unified API across different Taiwan e-invoice providers.
Architecture
@rytass/invoice (Base Package) │ ├── Invoice<Item> # Invoice entity interface ├── InvoiceGateway<...> # Gateway interface ├── InvoiceAllowance<Item> # Allowance interface ├── Enums & Types # Shared types └── Utility Functions # Helpers
@rytass/invoice-adapter-* # Provider implementations │ ├── [Provider]InvoiceGateway # Implements InvoiceGateway ├── [Provider]Invoice # Implements Invoice └── [Provider]Allowance # Implements InvoiceAllowance
Installation
npm install @rytass/invoice
Core Interfaces
InvoiceGateway
The main interface that all adapters must implement:
interface InvoiceGateway< Item extends PaymentItem = PaymentItem, I extends Invoice<Item> = Invoice<Item>, QueryOptions = unknown,
{ issue(options: InvoiceIssueOptions<Item>): Promise<I>; void(invoice: Invoice<PaymentItem>, options: InvoiceVoidOptions): Promise<Invoice<PaymentItem>>; allowance(invoice: Invoice<PaymentItem>, allowanceItems: InvoicePaymentItem[], options?: InvoiceAllowanceOptions): Promise<Invoice<PaymentItem>>; invalidAllowance(allowance: InvoiceAllowance<PaymentItem>): Promise<Invoice<PaymentItem>>; query(options: QueryOptions): Promise<I>; isMobileBarcodeValid(code: string): Promise<boolean>; isLoveCodeValid(code: string): Promise<boolean>; }
Invoice
The invoice entity interface:
interface Invoice<Item extends PaymentItem> { readonly invoiceNumber: string; readonly issuedOn: Date; readonly allowances: InvoiceAllowance<PaymentItem>[]; readonly issuedAmount: number; readonly randomCode: string; readonly items: Item[]; state: InvoiceState; nowAmount: number; voidOn: Date | null; setVoid: () => void; awardType?: InvoiceAwardType; }
InvoiceAllowance
The allowance entity interface:
interface InvoiceAllowance<Item extends PaymentItem> { readonly allowanceNumber: string; readonly allowancePrice: number; readonly allowancedOn: Date; readonly remainingAmount: number; readonly items: Item[]; readonly parentInvoice: Invoice<Item>; status: InvoiceAllowanceState; invalidOn: Date | null; invalid: () => void; }
Quick Reference
Supporting Types
// Issue Options interface InvoiceIssueOptions<Item extends PaymentItem = PaymentItem> { items: InvoicePaymentItem<Item>[]; vatNumber?: string; carrier?: InvoiceCarrier; customsMark?: CustomsMark; }
// Payment Item with Tax Type type InvoicePaymentItem<Item extends PaymentItem = PaymentItem> = Item & { taxType?: Omit<TaxType, TaxType.MIXED>; };
// Void Options interface InvoiceVoidOptions { reason: string; }
// Allowance Options interface InvoiceAllowanceOptions { taxType?: Omit<TaxType, TaxType.MIXED | TaxType.SPECIAL>; }
// Query Options interface BaseInvoiceQueryOptions { orderId?: string; invoiceNumber?: string; [key: string]: unknown; } type InvoiceQueryOptions<T = BaseInvoiceQueryOptions> = T;
// Carrier Types (Union) type InvoiceCarrier = | InvoicePrintCarrier | InvoiceMobileCarrier | InvoiceMoicaCarrier | InvoiceLoveCodeCarrier | InvoiceMemberCarrier | InvoicePlatformCarrier;
// Tax Types (Union) type InvoiceTax = CommonTax | SpecialTax;
interface CommonTax { type: Exclude<TaxType, TaxType.SPECIAL>; }
interface SpecialTax { type: TaxType.SPECIAL; taxCode: SpecialTaxCode; }
Enums
Enum Values
TaxType
TAXED, TAX_FREE, ZERO_TAX, SPECIAL, MIXED
InvoiceState
INITED, ISSUED, VOID, ALLOWANCED
InvoiceAllowanceState
INITED, ISSUED, INVALID
InvoiceCarrierType
PRINT, MOBILE, MOICA, LOVE_CODE, MEMBER, PLATFORM
CustomsMark
YES, NO
SpecialTaxCode
TEA, CLUB, BANK_SELF, INSURANCE, BANK_COMMON, BANK_SELF_SALES_BEFORE_103, BANK_SELF_SALES_AFTER_103, FREE
InvoiceAwardType
TWO_HUNDRED, FIVE_HUNDRED, EIGHT_HUNDRED, ONE_THOUSAND, FOUR_THOUSAND, TEN_THOUSAND, FORTY_THOUSAND, TWO_HUNDRED_THOUSAND, ONE_MILLION, TWO_MILLION, TEN_MILLION, CLOUD_TWO_THOUSAND
InvoiceAwardType (發票中獎類型)
import { InvoiceAwardType } from '@rytass/invoice';
enum InvoiceAwardType { TWO_HUNDRED = 6, // 200 元 FIVE_HUNDRED = 11, // 500 元 EIGHT_HUNDRED = 12, // 800 元 ONE_THOUSAND = 5, // 1,000 元 FOUR_THOUSAND = 4, // 4,000 元 TEN_THOUSAND = 3, // 10,000 元 FORTY_THOUSAND = 2, // 40,000 元 TWO_HUNDRED_THOUSAND = 1, // 200,000 元 ONE_MILLION = 10, // 1,000,000 元 TWO_MILLION = 7, // 2,000,000 元 TEN_MILLION = 8, // 10,000,000 元 CLOUD_TWO_THOUSAND = 9, // 雲端發票專屬 2,000 元 }
SpecialTaxCode (特殊稅種代碼)
當 TaxType.SPECIAL 時需指定特殊稅種代碼:
import { TaxType, SpecialTaxCode } from '@rytass/invoice';
enum SpecialTaxCode { TEA = 1, // 茶葉 CLUB = 2, // 娛樂業 BANK_SELF = 3, // 銀行業(本業) INSURANCE = 4, // 保險業 BANK_COMMON = 5, // 銀行業(一般) BANK_SELF_SALES_BEFORE_103 = 6, // 銀行業本業銷售額(103年前) BANK_SELF_SALES_AFTER_103 = 7, // 銀行業本業銷售額(103年後) FREE = 8, // 免稅 }
// 使用 SpecialTaxCode const invoice = await gateway.issue({ orderId: 'ORDER-001', items: [...], tax: { type: TaxType.SPECIAL, taxCode: SpecialTaxCode.BANK_COMMON, }, });
Utility Functions
Function Description
isValidVATNumber(input)
Validate Taiwan VAT number
getTaxTypeFromItems(items)
Determine TaxType from items
Carrier Helpers
import { InvoiceCarriers } from '@rytass/invoice';
InvoiceCarriers.PRINT; // 列印發票 InvoiceCarriers.MEMBER; // 會員載具 InvoiceCarriers.PLATFORM; // 平台載具 InvoiceCarriers.MOBILE('/ABC+123'); // 手機條碼 InvoiceCarriers.MOICA('...'); // 自然人憑證 InvoiceCarriers.LOVE_CODE('168001'); // 愛心碼捐贈
Deprecated Functions
import { verifyVatNumber, isValidVATNumber } from '@rytass/invoice';
// ⚠️ Deprecated - 請改用 isValidVATNumber verifyVatNumber('12345678'); // 會顯示 deprecation warning
// ✅ 建議使用 isValidVATNumber('12345678');
Detailed Documentation
For complete interface specifications and implementation guide:
-
Base Interfaces Reference - Complete type definitions
-
Creating an Adapter - Step-by-step guide