taiwan-payment-skill 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,370 +1,85 @@
1
- # 快速參考 (Quick Reference)
1
+ ## When to Apply
2
2
 
3
- > 此文件為 Claude 專用快速參考,提供金流服務商比較表、常用代碼片段、快速查找表。
3
+ Reference these guidelines when:
4
+ - Developing Taiwan E-Invoice issuance functionality
5
+ - Integrating ECPay, SmilePay, or Amego APIs
6
+ - Implementing B2C or B2B invoice logic
7
+ - Handling invoice printing, void, and allowance
8
+ - Troubleshooting invoice API integration issues
4
9
 
5
- ## 三家服務商快速比較
10
+ ## Provider Quick Reference
6
11
 
7
- | 特性 | 綠界 ECPay | 藍新 NewebPay | 統一 PAYUNi |
8
- |------|-----------|--------------|------------|
9
- | **加密方式** | URL Encode + SHA256 | AES-256-CBC + SHA256 雙層 | AES-256-GCM + SHA256 |
10
- | **API 風格** | Form POST | Form POST + AES | RESTful JSON |
11
- | **內容格式** | application/x-www-form-urlencoded | application/x-www-form-urlencoded | application/json |
12
- | **市佔率** | 🥇 最高 | 🥈 | 🥉 中等 |
13
- | **支付方式** | 11 | 13 | 8 |
14
- | **文檔品質** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
15
- | **測試環境** | 完整 | 完整 | 完整 |
16
- | **最佳用途** | 高交易量電商 | 多元支付需求 | 新創 API 開發 |
12
+ | Priority | Task | Impact | Provider |
13
+ |----------|------|--------|----------|
14
+ | 1 | Amount Calculation | CRITICAL | All |
15
+ | 2 | Encryption/Signature | CRITICAL | All |
16
+ | 3 | B2B vs B2C Logic | HIGH | All |
17
+ | 4 | Print Response Handling | HIGH | All |
18
+ | 5 | Provider Binding | MEDIUM | All |
19
+ | 6 | Error Handling | MEDIUM | All |
20
+ | 7 | Carrier/Donation | LOW | B2C only |
17
21
 
18
- ## 常用代碼片段
22
+ ## Quick Reference
19
23
 
20
- ### ECPay - 快速建立訂單
24
+ ### 1. Amount Calculation (CRITICAL)
21
25
 
22
- ```typescript
23
- import crypto from 'crypto'
26
+ - `b2c-tax-inclusive` - B2C uses tax-inclusive total
27
+ - `b2b-split-tax` - B2B requires pre-tax + tax split
28
+ - `round-tax` - Round tax: `Math.round(total - (total / 1.05))`
29
+ - `salesamount` - ECPay/Amego: Use SalesAmount for pre-tax
24
30
 
25
- // 1. 生成 CheckMacValue
26
- function generateECPayCheckMac(params: Record<string, any>, hashKey: string, hashIV: string): string {
27
- const { CheckMacValue, ...cleanParams } = params
28
- const sortedKeys = Object.keys(cleanParams).sort()
29
- const paramString = sortedKeys.map(k => `${k}=${cleanParams[k]}`).join('&')
30
- const rawString = `HashKey=${hashKey}&${paramString}&HashIV=${hashIV}`
31
- const encoded = encodeURIComponent(rawString).toLowerCase()
32
- return crypto.createHash('sha256').update(encoded).digest('hex').toUpperCase()
33
- }
31
+ ### 2. Encryption/Signature (CRITICAL)
34
32
 
35
- // 2. 建立訂單參數
36
- const orderParams = {
37
- MerchantID: '3002607',
38
- MerchantTradeNo: 'ORD' + Date.now(),
39
- MerchantTradeDate: new Date().toISOString().replace(/[-:T]/g, '').slice(0, 14),
40
- PaymentType: 'aio',
41
- TotalAmount: 1000,
42
- TradeDesc: '商品描述',
43
- ItemName: '商品名稱',
44
- ReturnURL: 'https://yourdomain.com/api/payment/callback',
45
- ChoosePayment: 'Credit',
46
- EncryptType: 1
47
- }
48
- orderParams.CheckMacValue = generateECPayCheckMac(orderParams, hashKey, hashIV)
33
+ - `ecpay-aes` - ECPay: AES-128-CBC with HashKey/HashIV
34
+ - `smilepay-verify` - SmilePay: Grvc + Verify_key params
35
+ - `amego-md5` - Amego: MD5(data + time + appKey)
36
+ - `url-encode` - Always URL encode before encryption
49
37
 
50
- // 3. POST https://payment-stage.ecpay.com.tw/Cashier/AioCheckOut/V5
51
- ```
38
+ ### 3. B2B vs B2C Logic (HIGH)
52
39
 
53
- ### NewebPay - 快速建立訂單
40
+ - `buyer-id-b2c` - B2C: BuyerIdentifier = "0000000000"
41
+ - `buyer-id-b2b` - B2B: BuyerIdentifier = actual 8-digit tax ID
42
+ - `no-carrier-b2b` - B2B: Cannot use carrier or donation
43
+ - `validate-taxid` - Validate 8-digit tax ID format
54
44
 
55
- ```typescript
56
- import crypto from 'crypto'
45
+ ### 4. Print Response Handling (HIGH)
57
46
 
58
- // 1. AES 加密
59
- function encryptNewebPay(data: Record<string, any>, hashKey: string, hashIV: string) {
60
- const queryString = new URLSearchParams(data).toString()
61
- const cipher = crypto.createCipheriv('aes-256-cbc', hashKey, hashIV)
62
- cipher.setAutoPadding(true)
63
- let encrypted = cipher.update(queryString, 'utf8', 'hex')
64
- encrypted += cipher.final('hex')
47
+ - `ecpay-html` - ECPay: Returns HTML, use window.document.write
48
+ - `smilepay-redirect` - SmilePay: Returns URL, use window.open
49
+ - `amego-pdf` - Amego: Returns PDF URL, use window.open
50
+ - `form-submit` - Some APIs require form POST submission
65
51
 
66
- const tradeSha = crypto
67
- .createHash('sha256')
68
- .update(`HashKey=${hashKey}&${encrypted}&HashIV=${hashIV}`)
69
- .digest('hex')
70
- .toUpperCase()
52
+ ### 5. Provider Binding (MEDIUM)
71
53
 
72
- return { TradeInfo: encrypted, TradeSha: tradeSha }
73
- }
54
+ - `save-provider` - Save invoiceProvider when issuing
55
+ - `save-random` - Save invoiceRandomNum for printing
56
+ - `match-provider` - Use issuing provider for print/void
74
57
 
75
- // 2. 建立訂單參數
76
- const orderData = {
77
- MerchantID: 'YOUR_MERCHANT_ID',
78
- RespondType: 'JSON',
79
- TimeStamp: Math.floor(Date.now() / 1000).toString(),
80
- Version: '2.0',
81
- MerchantOrderNo: 'ORD' + Date.now(),
82
- Amt: 1000,
83
- ItemDesc: '商品描述',
84
- Email: 'customer@example.com',
85
- NotifyURL: 'https://yourdomain.com/api/payment/callback',
86
- ReturnURL: 'https://yourdomain.com/payment/result'
87
- }
58
+ ### 6. Error Handling (MEDIUM)
88
59
 
89
- const encrypted = encryptNewebPay(orderData, hashKey, hashIV)
60
+ - `log-raw-response` - Log complete raw response for debugging
61
+ - `ecpay-codes` - ECPay: Check RtnCode and RtnMsg
62
+ - `smilepay-codes` - SmilePay: Check Status field
63
+ - `amego-codes` - Amego: Check Code and Message
90
64
 
91
- // 3. POST https://ccore.newebpay.com/MPG/mpg_gateway
92
- // Body: MerchantID, TradeInfo, TradeSha, Version
93
- ```
65
+ ### 7. Carrier/Donation (B2C only)
94
66
 
95
- ### PAYUNi - 快速建立訂單
67
+ - `carrier-mobile` - Mobile barcode: /XXXXXXX format
68
+ - `carrier-npc` - Natural person certificate
69
+ - `donation-code` - Donation: 3-7 digit love code
70
+ - `mutual-exclusive` - Carrier and donation are mutually exclusive
96
71
 
97
- ```typescript
98
- import crypto from 'crypto'
72
+ ## Test Credentials
99
73
 
100
- // 1. AES-GCM 加密
101
- function encryptPAYUNi(data: Record<string, any>, hashKey: string, hashIV: string) {
102
- const jsonString = JSON.stringify(data)
103
- const cipher = crypto.createCipheriv('aes-256-gcm', hashKey, hashIV)
104
- let encrypted = cipher.update(jsonString, 'utf8', 'hex')
105
- encrypted += cipher.final('hex')
106
- const authTag = cipher.getAuthTag().toString('hex')
107
- const encryptInfo = encrypted + authTag
74
+ | Provider | Key Info |
75
+ |----------|----------|
76
+ | ECPay | MerchantID: 2000132, Stage URL |
77
+ | SmilePay | Grvc: SEI1000034, Test Tax ID: 80129529 |
78
+ | Amego | Tax ID: 12345678, test@amego.tw |
108
79
 
109
- const hashInfo = crypto
110
- .createHash('sha256')
111
- .update(`HashKey=${hashKey}&${encryptInfo}&HashIV=${hashIV}`)
112
- .digest('hex')
113
- .toUpperCase()
80
+ ## How to Use
114
81
 
115
- return { EncryptInfo: encryptInfo, HashInfo: hashInfo }
116
- }
117
-
118
- // 2. 建立訂單參數
119
- const orderData = {
120
- MerchantID: 'YOUR_MERCHANT_ID',
121
- MerchantTradeNo: 'ORD' + Date.now(),
122
- MerchantTradeDate: new Date().toISOString().slice(0, 19).replace('T', ' '),
123
- TotalAmount: 1000,
124
- TradeDesc: '商品描述',
125
- ItemName: '商品名稱',
126
- NotifyURL: 'https://yourdomain.com/api/payment/callback',
127
- ReturnURL: 'https://yourdomain.com/payment/result'
128
- }
129
-
130
- const encrypted = encryptPAYUNi(orderData, hashKey, hashIV)
131
-
132
- // 3. POST 到 https://sandbox-api.payuni.com.tw/api/upp
133
- // Body: MerchantID, EncryptInfo, HashInfo
134
- ```
135
-
136
- ## 付款方式對照表
137
-
138
- | 付款方式 | ECPay | NewebPay | PAYUNi | 備註 |
139
- |---------|-------|----------|--------|------|
140
- | 信用卡一次付清 | `Credit` | `CREDIT` | `credit` | 最常用 |
141
- | 信用卡分期 | `Credit` + InstallmentFlag | `CREDIT` + InstFlag | `credit` + Installment | 需最低 1000 元 |
142
- | 信用卡定期 | `Credit` + PeriodType | `CREDIT` + PeriodType | `credit` + Period | 訂閱制 |
143
- | ATM 虛擬帳號 | `ATM` | `VACC=1` | `atm` | 1-3 天 |
144
- | 網路 ATM | `WebATM` | `WEBATM=1` | `webatm` | 即時 |
145
- | 超商代碼 | `CVS` | `CVS=1` | `cvs` | 30-20,000 |
146
- | 超商條碼 | `BARCODE` | `BARCODE=1` | `barcode` | 20-40,000 |
147
- | Apple Pay | `ApplePay` | `APPLEPAY=1` | `applepay` | 需申請 |
148
- | Google Pay | `GooglePay` | `GOOGLEPAY=1` | `googlepay` | 需申請 |
149
- | LINE Pay | `LINEPAY` | `LINEPAY=1` | ❌ | NewebPay 最佳 |
150
- | 台灣 Pay | `TWQR` | `P2G=1` | `taiwanpay` | 最高 49,999 |
151
- | BNPL 無卡分期 | `BNPL` | ❌ | ❌ | ECPay 獨家 |
152
- | AFTEE 先享後付 | ❌ | ❌ | `aftee` | PAYUNi 獨家 |
153
-
154
- ## 錯誤碼快速查找
155
-
156
- ### ECPay 常見錯誤
157
-
158
- | 錯誤碼 | 說明 | 解決方案 |
159
- |-------|------|---------|
160
- | `10100058` | CheckMacValue 錯誤 | 檢查參數排序、URL Encode |
161
- | `10100003` | 訂單編號重複 | 使用唯一的 MerchantTradeNo |
162
- | `10100047` | 金額不符 | 檢查 TotalAmount 是否正整數 |
163
- | `10100073` | 商品名稱錯誤 | ItemName 不可為空 |
164
- | `10200095` | 付款逾時 | 重新建立訂單 |
165
-
166
- ### NewebPay 常見錯誤
167
-
168
- | 錯誤碼 | 說明 | 解決方案 |
169
- |-------|------|---------|
170
- | `TRA10001` | 交易失敗 | 檢查加密參數 |
171
- | `TRA10002` | CheckValue 錯誤 | 檢查 TradeSha 計算 |
172
- | `TRA10003` | 訂單不存在 | 檢查 MerchantOrderNo |
173
- | `TRA10004` | 金額錯誤 | 檢查 Amt 是否正整數 |
174
- | `TRA10005` | 商店代號錯誤 | 檢查 MerchantID |
175
-
176
- ### PAYUNi 常見錯誤
177
-
178
- | 錯誤碼 | 說明 | 解決方案 |
179
- |-------|------|---------|
180
- | `ER0001` | 參數錯誤 | 檢查必填欄位 |
181
- | `ER0002` | 簽章錯誤 | 檢查 HashInfo 計算 |
182
- | `ER0003` | 訂單重複 | 使用唯一訂單號 |
183
- | `ER0004` | 金額錯誤 | 檢查 TotalAmount |
184
- | `ER0005` | 商店不存在 | 檢查 MerchantID |
185
-
186
- ## 測試資料快速複製
187
-
188
- ### ECPay 測試環境
189
- ```
190
- MerchantID: 3002607
191
- HashKey: pwFHCqoQZGmho4w6
192
- HashIV: EkRm7iFT261dpevs
193
- 測試 URL: https://payment-stage.ecpay.com.tw/Cashier/AioCheckOut/V5
194
- 測試卡號: 4311-9522-2222-2222
195
- 有效期: 任意未來月年 (如 12/28)
196
- CVV: 任意 3 碼 (如 123)
197
- ```
198
-
199
- ### NewebPay 測試環境
200
- ```
201
- 測試 URL: https://ccore.newebpay.com/MPG/mpg_gateway
202
- 測試卡號: 4000-2211-1111-1111
203
- 有效期: 任意未來月年 (如 12/28)
204
- CVV: 任意 3 碼 (如 123)
205
- 後台: https://cwww.newebpay.com/
206
- 注意: 需先申請測試帳號
207
- ```
208
-
209
- ### PAYUNi 測試環境
210
- ```
211
- 測試 URL: https://sandbox-api.payuni.com.tw/api/upp
212
- 後台: https://sandbox.payuni.com.tw/
213
- 注意: 需先申請測試帳號
214
- ```
215
-
216
- ## 欄位對照表
217
-
218
- | 用途 | ECPay | NewebPay | PAYUNi |
219
- |-----|-------|----------|--------|
220
- | 商店代號 | `MerchantID` | `MerchantID` | `MerchantID` |
221
- | 訂單編號 | `MerchantTradeNo` | `MerchantOrderNo` | `MerchantTradeNo` |
222
- | 訂單日期 | `MerchantTradeDate` | `TimeStamp` | `MerchantTradeDate` |
223
- | 訂單金額 | `TotalAmount` | `Amt` | `TotalAmount` |
224
- | 商品名稱 | `ItemName` | `ItemDesc` | `ItemName` |
225
- | 商品描述 | `TradeDesc` | `ItemDesc` | `TradeDesc` |
226
- | 付款通知 URL | `ReturnURL` | `NotifyURL` | `NotifyURL` |
227
- | 完成導向 URL | `OrderResultURL` | `ReturnURL` | `ReturnURL` |
228
- | 付款方式 | `ChoosePayment` | 多個開關 | `PaymentType` |
229
- | 簽章 | `CheckMacValue` | `TradeSha` | `HashInfo` |
230
- | 加密資料 | - | `TradeInfo` | `EncryptInfo` |
231
-
232
- ## 回呼驗證範例
233
-
234
- ### ECPay 回呼驗證
235
- ```typescript
236
- export async function POST(request: Request) {
237
- const formData = await request.formData()
238
- const params = Object.fromEntries(formData)
239
-
240
- // 驗證簽章
241
- const receivedMac = params.CheckMacValue
242
- const calculatedMac = generateECPayCheckMac(params, hashKey, hashIV)
243
-
244
- if (receivedMac !== calculatedMac) {
245
- return new Response('0|CheckMacValue Error')
246
- }
247
-
248
- // 更新訂單
249
- // ...
250
-
251
- return new Response('1|OK')
252
- }
253
- ```
254
-
255
- ### NewebPay 回呼驗證
256
- ```typescript
257
- export async function POST(request: Request) {
258
- const formData = await request.formData()
259
- const tradeInfo = formData.get('TradeInfo') as string
260
- const tradeSha = formData.get('TradeSha') as string
261
-
262
- // 驗證 TradeSha
263
- const calculatedSha = crypto
264
- .createHash('sha256')
265
- .update(`HashKey=${hashKey}&${tradeInfo}&HashIV=${hashIV}`)
266
- .digest('hex')
267
- .toUpperCase()
268
-
269
- if (tradeSha !== calculatedSha) {
270
- return Response.json({ Status: 'ERROR', Message: 'CheckValue Error' })
271
- }
272
-
273
- // 解密 TradeInfo
274
- const decrypted = decryptNewebPay(tradeInfo, hashKey, hashIV)
275
-
276
- // 更新訂單
277
- // ...
278
-
279
- return Response.json({ Status: 'SUCCESS' })
280
- }
281
- ```
282
-
283
- ### PAYUNi 回呼驗證
284
- ```typescript
285
- export async function POST(request: Request) {
286
- const body = await request.json()
287
- const { EncryptInfo, HashInfo } = body
288
-
289
- // 驗證 HashInfo
290
- const calculatedHash = crypto
291
- .createHash('sha256')
292
- .update(`HashKey=${hashKey}&${EncryptInfo}&HashIV=${hashIV}`)
293
- .digest('hex')
294
- .toUpperCase()
295
-
296
- if (HashInfo !== calculatedHash) {
297
- return Response.json({ Status: 'ERROR', Message: 'Hash Error' })
298
- }
299
-
300
- // 解密 EncryptInfo
301
- const decrypted = decryptPAYUNi(EncryptInfo, hashKey, hashIV)
302
-
303
- // 更新訂單
304
- // ...
305
-
306
- return Response.json({ Status: 'SUCCESS' })
307
- }
308
- ```
309
-
310
- ## 智能工具快速使用
311
-
312
- ```bash
313
- # 搜索錯誤碼
314
- python scripts/search.py "10100058" --domain error
315
-
316
- # 推薦服務商
317
- python scripts/recommend.py "電商 高交易量"
318
-
319
- # 測試連線
320
- python scripts/test_payment.py ecpay
321
- ```
322
-
323
- ## 前端表單提交範例
324
-
325
- ```typescript
326
- // 通用表單提交函數
327
- function submitPaymentForm(action: string, params: Record<string, string>) {
328
- const form = document.createElement('form')
329
- form.method = 'POST'
330
- form.action = action
331
- form.target = '_self'
332
-
333
- Object.entries(params).forEach(([key, value]) => {
334
- const input = document.createElement('input')
335
- input.type = 'hidden'
336
- input.name = key
337
- input.value = value
338
- form.appendChild(input)
339
- })
340
-
341
- document.body.appendChild(form)
342
- form.submit()
343
- }
344
-
345
- // ECPay 使用
346
- submitPaymentForm('https://payment-stage.ecpay.com.tw/Cashier/AioCheckOut/V5', orderParams)
347
-
348
- // NewebPay 使用
349
- submitPaymentForm('https://ccore.newebpay.com/MPG/mpg_gateway', {
350
- MerchantID: merchantID,
351
- TradeInfo: encrypted.TradeInfo,
352
- TradeSha: encrypted.TradeSha,
353
- Version: '2.0'
354
- })
355
-
356
- // PAYUNi 使用 (JSON POST,不用表單)
357
- fetch('https://sandbox-api.payuni.com.tw/api/upp', {
358
- method: 'POST',
359
- headers: { 'Content-Type': 'application/json' },
360
- body: JSON.stringify({
361
- MerchantID: merchantID,
362
- EncryptInfo: encrypted.EncryptInfo,
363
- HashInfo: encrypted.HashInfo
364
- })
365
- })
366
- ```
82
+ See the full skill documentation for detailed API references and code examples.
367
83
 
368
84
  ---
369
85
 
370
- 最後更新:2026/01/29