PHPackages                             agriweather/laravel-ezpay-invoice - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. agriweather/laravel-ezpay-invoice

ActiveLibrary

agriweather/laravel-ezpay-invoice
=================================

適用於 Laravel 的 ezPay 電子發票 API 套件

v1.1.0(3mo ago)051MITPHPPHP &gt;=8.1CI passing

Since Jun 26Pushed 3mo agoCompare

[ Source](https://github.com/Agriweather/laravel-ezpay-invoice)[ Packagist](https://packagist.org/packages/agriweather/laravel-ezpay-invoice)[ Docs](https://github.com/Agriweather/laravel-ezpay-invoice)[ RSS](/packages/agriweather-laravel-ezpay-invoice/feed)WikiDiscussions 1.x Synced 1mo ago

READMEChangelog (10)Dependencies (12)Versions (18)Used By (0)

Laravel ezPay Invoice - ezPay電子發票
=================================

[](#laravel-ezpay-invoice---ezpay電子發票)

[![Latest Version on Packagist](https://camo.githubusercontent.com/fbca1718d4a88e4c97062b631099557751138d6be213d8e86474626980a923c6/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f61677269776561746865722f6c61726176656c2d657a7061792d696e766f6963653f7374796c653d666c61742d737175617265)](https://packagist.org/packages/agriweather/laravel-ezpay-invoice)[![Software License](https://camo.githubusercontent.com/c090e080484e2a2bc766446291d04437db823929042bf614b26a1643660ddf6f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e3f7374796c653d666c61742d737175617265)](LICENSE)[![GitHub Tests Action Status](https://camo.githubusercontent.com/ee0f0d11b372072c707014cfe4abf23893e110971793a05225666b9abc0dc2d7/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f41677269776561746865722f6c61726176656c2d657a7061792d696e766f6963652f74657374732e796d6c3f6272616e63683d312e78266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/Agriweather/laravel-ezpay-invoice/actions/workflows/tests.yml?query=branch%3A1.x)[![Total Downloads](https://camo.githubusercontent.com/819980516eaca51604426d15771fdeb2c6fc581d4dca2d3621125656fb25dfe7/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f61677269776561746865722f6c61726176656c2d657a7061792d696e766f6963653f7374796c653d666c61742d737175617265)](https://packagist.org/packages/agriweather/laravel-ezpay-invoice)

**Laravel ezPay Invoice** 是適用於 Laravel 的 ezPay 電子發票 API 套件。由 [Lucas Yang](https://github.com/ycs77) 創建，並由 [阿龜微氣候天眼通](https://github.com/Agriweather) 團隊維護。

### 套件功能

[](#套件功能)

- 🧾 電子發票 API
- 🌏 電子發票 API (境外電商版)
- 🆎 字軌管理 API
- 📱 手機條碼與捐證碼驗證 API

目錄
--

[](#目錄)

- [版本需求](#%E7%89%88%E6%9C%AC%E9%9C%80%E6%B1%82)
- [開始使用](#%E9%96%8B%E5%A7%8B%E4%BD%BF%E7%94%A8)
- [電子發票 API](#%E9%9B%BB%E5%AD%90%E7%99%BC%E7%A5%A8-api)
    - [開立電子發票](#%E9%96%8B%E7%AB%8B%E9%9B%BB%E5%AD%90%E7%99%BC%E7%A5%A8)
    - [觸發電子發票](#%E8%A7%B8%E7%99%BC%E9%9B%BB%E5%AD%90%E7%99%BC%E7%A5%A8)
    - [查詢電子發票](#%E6%9F%A5%E8%A9%A2%E9%9B%BB%E5%AD%90%E7%99%BC%E7%A5%A8)
    - [作廢電子發票](#%E4%BD%9C%E5%BB%A2%E9%9B%BB%E5%AD%90%E7%99%BC%E7%A5%A8)
    - [開立折讓](#%E9%96%8B%E7%AB%8B%E6%8A%98%E8%AE%93)
    - [開立並延遲確認折讓](#%E9%96%8B%E7%AB%8B%E4%B8%A6%E5%BB%B6%E9%81%B2%E7%A2%BA%E8%AA%8D%E6%8A%98%E8%AE%93)
    - [作廢折讓](#%E4%BD%9C%E5%BB%A2%E6%8A%98%E8%AE%93)
- [電子發票 API (境外電商版)](#%E9%9B%BB%E5%AD%90%E7%99%BC%E7%A5%A8-api-%E5%A2%83%E5%A4%96%E9%9B%BB%E5%95%86%E7%89%88)
    - [境外電商開立電子發票](#%E5%A2%83%E5%A4%96%E9%9B%BB%E5%95%86%E9%96%8B%E7%AB%8B%E9%9B%BB%E5%AD%90%E7%99%BC%E7%A5%A8)
    - [境外電商觸發電子發票](#%E5%A2%83%E5%A4%96%E9%9B%BB%E5%95%86%E8%A7%B8%E7%99%BC%E9%9B%BB%E5%AD%90%E7%99%BC%E7%A5%A8)
    - [境外電商查詢電子發票](#%E5%A2%83%E5%A4%96%E9%9B%BB%E5%95%86%E6%9F%A5%E8%A9%A2%E9%9B%BB%E5%AD%90%E7%99%BC%E7%A5%A8)
    - [境外電商作廢電子發票](#%E5%A2%83%E5%A4%96%E9%9B%BB%E5%95%86%E4%BD%9C%E5%BB%A2%E9%9B%BB%E5%AD%90%E7%99%BC%E7%A5%A8)
    - [境外電商開立折讓](#%E5%A2%83%E5%A4%96%E9%9B%BB%E5%95%86%E9%96%8B%E7%AB%8B%E6%8A%98%E8%AE%93)
    - [境外電商開立並延遲確認折讓](#%E5%A2%83%E5%A4%96%E9%9B%BB%E5%95%86%E9%96%8B%E7%AB%8B%E4%B8%A6%E5%BB%B6%E9%81%B2%E7%A2%BA%E8%AA%8D%E6%8A%98%E8%AE%93)
    - [境外電商作廢折讓](#%E5%A2%83%E5%A4%96%E9%9B%BB%E5%95%86%E4%BD%9C%E5%BB%A2%E6%8A%98%E8%AE%93)
- [字軌管理 API](#%E5%AD%97%E8%BB%8C%E7%AE%A1%E7%90%86-api)
    - [準備帳號代號和金鑰](#%E6%BA%96%E5%82%99%E5%B8%B3%E8%99%9F%E4%BB%A3%E8%99%9F%E5%92%8C%E9%87%91%E9%91%B0)
    - [申請新字軌](#%E7%94%B3%E8%AB%8B%E6%96%B0%E5%AD%97%E8%BB%8C)
    - [查詢字軌](#%E6%9F%A5%E8%A9%A2%E5%AD%97%E8%BB%8C)
    - [啟用字軌](#%E5%95%9F%E7%94%A8%E5%AD%97%E8%BB%8C)
    - [暫停字軌](#%E6%9A%AB%E5%81%9C%E5%AD%97%E8%BB%8C)
    - [停用字軌](#%E5%81%9C%E7%94%A8%E5%AD%97%E8%BB%8C)
- [手機條碼與捐證碼驗證 API](#%E6%89%8B%E6%A9%9F%E6%A2%9D%E7%A2%BC%E8%88%87%E6%8D%90%E8%AD%89%E7%A2%BC%E9%A9%97%E8%AD%89-api)
    - [驗證手機條碼](#%E9%A9%97%E8%AD%89%E6%89%8B%E6%A9%9F%E6%A2%9D%E7%A2%BC)
    - [驗證捐證碼](#%E9%A9%97%E8%AD%89%E6%8D%90%E8%AD%89%E7%A2%BC)
- [錯誤處理](#%E9%8C%AF%E8%AA%A4%E8%99%95%E7%90%86)
- [單元測試](#%E5%96%AE%E5%85%83%E6%B8%AC%E8%A9%A6)
- [除錯支援](#%E9%99%A4%E9%8C%AF%E6%94%AF%E6%8F%B4)
- [API 參考文件](#api-%E5%8F%83%E8%80%83%E6%96%87%E4%BB%B6)
- [貢獻專案](#%E8%B2%A2%E7%8D%BB%E5%B0%88%E6%A1%88)
- [License](#license)

版本需求
----

[](#版本需求)

版本PHP 版本Laravel 版本1.x&gt;=8.1&gt;=9.x開始使用
----

[](#開始使用)

使用 Composer 安裝套件：

```
composer require agriweather/laravel-ezpay-invoice
```

發布設置檔案：

```
php artisan vendor:publish --tag=ezpay-invoice-config
```

前往 ezPay 電子發票官方網站註冊帳號（測試時需在測試環境註冊測試帳號）並建立商店。

在 ezPay 電子發票平台開立發票需要購買額度，如果額度不足，請前往「發票管理」&gt;「管理設定」&gt;「使用狀況」進行購買（測試環境同樣需要點擊購買，但不會實際收費）。

進入 ezPay 電子發票的「商店管理」頁面，找到對應的商店，複製商店串接 API 的商店代號、`HashKey` 和 `HashIV`，然後將這些資訊設定到 `.env` 檔案中的 `EZPAY_INVOICE_MERCHANT_ID` 等參數：

```
EZPAY_INVOICE_ENV=test
EZPAY_INVOICE_MERCHANT_ID=your-merchant-id
EZPAY_INVOICE_MERCHANT_HASH_KEY=your-merchant-hash-key
EZPAY_INVOICE_MERCHANT_HASH_IV=your-merchant-hash-iv
```

`EZPAY_INVOICE_ENV` 可以設定為 `test`（測試環境）或 `production`（正式環境）。

完成設定後，即可開始測試電子發票的開立：

```
use Agriweather\EzPayInvoice\Enums\Invoice\TaxType;
use Agriweather\EzPayInvoice\Facades\EzPayInvoice;

$result = EzPayInvoice::invoice()
    ->create()
    ->withOrder('Order'.time())
    ->forConsumer('John Doe')
    ->withEmail('customer@example.com')
    ->withAddress('台北市信義區信義路五段7號')
    ->withItem('測試商品', quantity: 1, unit: '個', price: 1000, amount: 1000)
    ->withTax(TaxType::TAXABLE, 5)
    ->withAmount(1000, 50, 1050)
    ->issue();

$result->invoiceNumber() // 發票號碼：'AB12345678'
$result->randomNumber() // 發票隨機碼：'1234'
```

電子發票 API
--------

[](#電子發票-api)

### 開立電子發票

[](#開立電子發票)

開立 B2C 電子發票的基本範例：

```
use Agriweather\EzPayInvoice\Facades\EzPayInvoice;

$result = EzPayInvoice::invoice()
    ->create()
    ->withOrder('Order001') // 訂單編號
    ->forConsumer('John Doe') // 消費者姓名
    ->withEmail('customer@example.com') // 消費者電子信箱
    ->withAddress('台北市信義區信義路五段7號') // 消費者地址
    ->withItem('測試商品', quantity: 1, unit: '個', price: 1000, amount: 1000) // 商品名稱、數量、單位、單價和金額
    ->withTax(TaxType::TAXABLE, 5) // 稅別：應稅稅別，稅率：5%
    ->withAmount(1000, 50, 1050) // 未稅銷售額、稅額、含稅銷售額
    ->issue();
```

開立 B2C 電子發票時，可以選擇使用不同的載具，如果設定了載具，會自動設定不索取紙本發票：

```
use Agriweather\EzPayInvoice\Enums\Invoice\CarrierType;

EzPayInvoice::invoice()
    ->create()
    ->forConsumer('John Doe')

    // 手機條碼載具: 第1碼 / + 7碼英、數字
    ->withCarrier(CarrierType::MOBILE, '/ABC.123')
    // 自然人憑證: 2碼大寫英文 + 14碼數字
    ->withCarrier(CarrierType::CITIZEN_CERT, 'AB12345678901234')
    // ezPay 電子發票載具
    ->withCarrier(CarrierType::EZPAY_CARRIER, '1234567890')
    ->withEmail('customer@example.com') // 當選擇 ezPay 電子發票載具時，需提供電子信箱
```

或者是可以提供捐贈碼，但不能與載具一起使用：

```
EzPayInvoice::invoice()
    ->create()
    ->forConsumer('John Doe')

    // 捐贈碼: 3~7 碼純數字
    ->withLoveCode('1234567')
```

開立 B2B 電子發票的基本範例：

```
$result = EzPayInvoice::invoice()
    ->create()
    ->withOrder('Order002')
    ->forBusiness('測試公司有限公司', '12345678') // 公司名稱、統一編號
    ->withEmail('business@company.com') // 公司電子信箱
    ->withAddress('台北市信義區信義路五段7號') // 公司地址
    ->withItem('商品A', quantity: 2, unit: '個', price: 300, amount: 600) // 商品名稱、數量、單位、單價和金額
    ->withItem('商品B', quantity: 1, unit: '個', price: 400, amount: 400) // 商品名稱、數量、單位、單價和金額
    ->withTax(TaxType::TAXABLE, 5) // 稅別：應稅稅別，稅率：5%
    ->withAmount(1000, 50, 1050) // 未稅銷售額、稅額、含稅銷售額
    ->issue();
```

如果開立了 B2B 電子發票，會自動設定索取紙本發票。

設定電子發票稅別和稅率：

```
use Agriweather\EzPayInvoice\Enums\Invoice\CustomsClearance;
use Agriweather\EzPayInvoice\Enums\Invoice\TaxType;

EzPayInvoice::invoice()
    ->create()

    // 應稅稅別，稅率：5%
    ->withTax(TaxType::TAXABLE, 5)

    // 零稅率
    ->withTax(TaxType::ZERO_RATE)
    // 當設定零稅率時，必須提供報關標記選項：
    ->withCustomsClearance(CustomsClearance::NON_CUSTOMS) // 非經海關
    ->withCustomsClearance(CustomsClearance::CUSTOMS) // 經海關

    // 免稅
    ->withTax(TaxType::TAX_FREE)

    // 混合應稅與免稅或零稅率 (例如：商品A應稅，商品B免稅)
    // 當開立 B2B 電子發票才能使用
    ->withTax(TaxType::MIXED)
```

設定電子發票的商品項目和銷售額：

Important

銷售額計算方式，請務必與公司財會人員進行確認。

```
EzPayInvoice::invoice()
    ->create()

    // 增加商品項目
    ->withItem('測試商品', quantity: 1, unit: '個', price: 1000, amount: 1000)
    ->withItem('Test Product', quantity: 2, unit: 'EA', price: 600, amount: 1200)

    // 批次增加商品項目
    ->withItems([
        [
            'name' => '測試商品',
            'quantity' => 1,
            'unit' => '個',
            'price' => 1000,
            'amount' => 1000,
        ],
        [
            'name' => 'Test Product',
            'quantity' => 2,
            'unit' => 'EA',
            'price' => 600,
            'amount' => 1200,
        ],
    ])

    // 未稅銷售額、稅額、含稅銷售額
    ->withAmount(2200, 110, 2310)
```

「混合應稅與免稅或零稅率」的銷售額設定範例：

Important

銷售額計算方式，請務必與公司財會人員進行確認。

```
use Agriweather\EzPayInvoice\Enums\Invoice\ItemTaxType;
use Agriweather\EzPayInvoice\Enums\Invoice\TaxType;

EzPayInvoice::invoice()
    ->create()
    ->forBusiness('測試公司有限公司', '12345678')

    // 設定稅別為混合應稅與免稅或零稅率
    ->withTax(TaxType::MIXED)

    // 為每個商品設定不同的稅別
    ->withItem('測試商品', quantity: 1, unit: '個', price: 1000, amount: 1000, taxType: ItemTaxType::TAXABLE)
    ->withItem('測試商品', quantity: 1, unit: '個', price: 600, amount: 600, taxType: ItemTaxType::ZERO_RATE)

    // 混合稅率銷售額: 銷售額(課稅別應稅)、銷售額(課稅別零稅率)、銷售額(課稅別免稅)
    ->withMixedTaxAmount(1000, 600, 0)

    // 銷售額為上面三個 混合稅率銷售額 的總和
    ->withAmount(1600, 0, 1600)
```

設定發票備註：

```
EzPayInvoice::invoice()
    ->create()
    ->withComment('發票備註'); // 發票備註，字數限 200 字，如有難字則再縮短
```

套件同時提供條件式語法，可以在開立發票時根據需要選擇性地添加參數：

```
use Agriweather\EzPayInvoice\Builders\Invoice\CreateBuilder;

EzPayInvoice::invoice()
    ->create()
    ->when($request->input('carrier_type') === 'mobile', function (CreateBuilder $builder) use ($mobileCarrier) {
        $builder->withCarrier(CarrierType::MOBILE, $mobileCarrier);
    })
    ->when($request->input('carrier_type') === 'lovecode', function (CreateBuilder $builder) use ($loveCode) {
        $builder->withLoveCode($loveCode);
    })
```

立即開立發票：

```
// 立即開立發票
$result = EzPayInvoice::invoice()
    ->create()
    ...
    ->issue();

$result->invoiceNumber() // 發票號碼：'AB12345678'
$result->randomNumber() // 發票隨機碼：'1234'
$result->orderNo() // 訂單編號：'Order001'
$result->totalAmount() // 含稅銷售額：1050
```

等待觸發開立發票：

```
// 等待觸發開立發票
// 當選擇此開立發票方式時，發票資料僅暫存於平台，需手動呼叫「觸發電子發票 API」來完成開立。
$result = EzPayInvoice::invoice()
    ->create()
    ...
    ->deferIssue();

// 預約自動開立發票
// 當選擇此開立發票方式時，發票會在設定時間自動開立，如需提前開立，可手動呼叫「觸發電子發票 API」。
$result = EzPayInvoice::invoice()
    ->create()
    ...
    ->scheduleAt('2025-03-01'); // 設定開立發票的時間

// 保存這些資料用於觸發開立發票
$result->invoiceTransNo() // ezPay 電子發票開立序號：'25072515224376654'
$result->orderNo() // 訂單編號：'Order001'
$result->totalAmount() // 含稅銷售額：1050
```

### 觸發開立電子發票

[](#觸發開立電子發票)

若使用了 **等待觸發開立發票** (`deferIssue()`) 方式，需呼叫觸發電子發票 API 來完成開立。若使用 **預約自動開立發票** (`scheduleAt()`) 方式，則可透過呼叫觸發 API 來提前開立發票：

```
$result = EzPayInvoice::invoice()
    ->pending()
    ->withInvoiceTransNo('25072515224376654')
    ->withOrder('Order004')
    ->withTotalAmount(210)
    ->trigger();
```

### 查詢電子發票

[](#查詢電子發票)

使用發票號碼和隨機碼查詢電子發票：

```
$invoiceResult = EzPayInvoice::invoice()
    ->query()
    ->withInvoice('GG72002017')
    ->withRandomNumber('1234')
    ->get();
```

或者也可使用訂單編號及發票金額查詢電子發票：

```
$invoiceResult = EzPayInvoice::invoice()
    ->query()
    ->withOrder('Order001')
    ->withTotalAmount(1050)
    ->get();
```

電子發票查詢結果包含以下資訊：

```
$invoiceResult->invoiceNumber() // 發票號碼：'GG72002017'
$invoiceResult->randomNumber() // 發票隨機碼：'1234'
$invoiceResult->orderNo() // 訂單編號：'Order001'
$invoiceResult->invoiceTransNo() // ezPay 電子發票開立序號：'25072515224376654'

$invoiceResult->invoiceStatus() // 發票狀態：`InvoiceStatus::ISSUED` (已開立)
$invoiceResult->invoiceUploadStatus() // 發票上傳財政部之狀態：`InvoiceUploadStatus::UPLOADED` (已上傳)

$invoiceResult->buyerName() // 買受人名稱：'John Doe'
$invoiceResult->buyerTaxIdNumber() // 買受人統一編號：'12345678'
$invoiceResult->buyerAddress() // 買受人地址：'台北市信義區信義路五段7號'
$invoiceResult->buyerPhone() // 買受人電話：'02-12345678'
$invoiceResult->buyerEmail() // 買受人電子信箱：'customer@example.com'

$invoiceResult->invoiceType() // 發票類別：`InvoiceType::GENERAL` (07: 一般稅額計算)
$invoiceResult->category() // 發票種類：`InvoiceCategory::B2C` (B2C電子發票)
$invoiceResult->taxType() // 課稅別：`TaxType::TAXABLE` (應稅)
$invoiceResult->taxRate() // 稅率：5.0 (5%)

$invoiceResult->amount() // 發票銷售額合計 (未稅)：1000
$invoiceResult->salesAmount() // 銷售額 (課稅別應稅的未稅金額)：300
$invoiceResult->zeroAmount() // 銷售額 (課稅別零稅率的未稅金額)：350
$invoiceResult->freeAmount() // 銷售額 (課稅別免稅的未稅金額)：300
$invoiceResult->taxAmount() // 稅額：50
$invoiceResult->totalAmount() // 含稅銷售額：1050

$invoiceResult->carrierType() // 載具類型：`CarrierType::MOBILE` (手機條碼載具)
$invoiceResult->carrierNumber() // 載具編號：'/ABC.123'
$invoiceResult->loveCode() // 捐贈碼：'1234567'
$invoiceResult->printFlag() // 是否索取紙本發票：true (索取紙本發票)
$invoiceResult->kioskPrintFlag() // 是否開放至合作超商 Kiosk 列印：true (開放列印)

$items = $invoiceResult->items() // 商品項目陣列
// [
//     [
//         'number' => 1,
//         'name' => '測試商品',
//         'quantity' => 1,
//         'unit' => '個',
//         'price' => 1000,
//         'amount' => 1000,
//         'taxType' => TaxType::TAXABLE, // 應稅
//     ],
//     [
//         'number' => 2,
//         'name' => 'Test Product',
//         'quantity' => 2,
//         'unit' => 'EA',
//         'price' => 600,
//         'amount' => 1200,
//         'taxType' => TaxType::ZERO_RATE, // 零稅率
//     ],
// ]
```

除了透過 API 查詢電子發票外，也可以直接跳轉到 ezPay 平台的查詢發票頁面：

```
Route::get('/invoice/search', function () {
    return EzPayInvoice::invoice()
        ->query()
        ->withInvoice('GG72002017')
        ->withRandomNumber('1234')
        ->redirectToEzPay();
});
```

或者是取得表單資料，並自行撰寫前端表單進行跳轉：

Tip

HTML 表單可以參考 [src/Transporters/FormRedirectTransporter.php](src/Transporters/FormRedirectTransporter.php)

```
$requestData = EzPayInvoice::invoice()
    ->query()
    ->withInvoice('GG72002017')
    ->withRandomNumber('1234')
    ->toRedirectRequestData();

// [
//     'url' => 'https://cinv.ezpay.com.tw/Api/invoice_issue',
//     'formData' => [
//         'MerchantID_' => 'your-merchant-id',
//         'PostData' => 'xxxxxx',
//     ],
// ]
```

或者是單純取得 ezPay 平台的查詢發票網址：

```
$url = EzPayInvoice::invoice()
    ->query()
    ->withInvoice('GG72002017')
    ->withRandomNumber('1234')
    ->getEzPaySearchUrl();

// 'https://inv.ezpay.com.tw/Invoice_index/search_platform?PostData=xxxxxx'
```

### 作廢電子發票

[](#作廢電子發票)

作廢電子發票需要傳入發票號碼和作廢原因：

```
EzPayInvoice::invoice()
    ->voidable()
    ->withInvoice('GG72002017')
    ->because('客戶取消訂單')
    ->invalidate();
```

### 開立折讓

[](#開立折讓)

當需要對已開立的電子發票進行部分或全部退貨時，可以立即開立發票折讓 (同時會立即確認折讓)：

```
$result = EzPayInvoice::allowance()
    ->create()
    ->withInvoice('GG72002018')
    ->withOrder('Order001')
    ->withItem('退貨商品', quantity: 2, unit: '個', price: 300, amount: 600, taxAmount: 30)
    ->withTotalAmount(630)
    ->withNotification('customer@example.com')
    ->issue();

$result->allowanceNo() // 折讓號：'A250725235346456'
$result->orderNo() // 訂單編號：'Order001'
$result->invoiceNumber() // 發票號碼：'GG72002018'
$result->allowanceAmount() // 折讓金額：630
$result->remainingAmount() // 折讓後剩餘發票金額：420
```

### 開立並延遲確認折讓

[](#開立並延遲確認折讓)

開立延遲確認的折讓，待買受人確認折讓後，再向 ezPay 平台發動確認折讓：

```
$result = EzPayInvoice::allowance()
    ->create()
    ...
    ->issuePendingConfirmation();
```

買受人發動確認折讓：

```
EzPayInvoice::allowance()
    ->pending()
    ->withAllowance('A250726001830959')
    ->withOrder('Order001')
    ->withTotalAmount(420)
    ->confirm();
```

買受人發動取消折讓：

```
EzPayInvoice::allowance()
    ->pending()
    ->withAllowance('A250726001830959')
    ->withOrder('Order001')
    ->withTotalAmount(420)
    ->cancel();
```

### 作廢折讓

[](#作廢折讓)

作廢已開立的折讓，需傳入折讓號和作廢原因：

```
EzPayInvoice::allowance()
    ->voidable()
    ->withAllowance('A250726001830959')
    ->because('作廢原因')
    ->invalidate();
```

電子發票 API (境外電商版)
----------------

[](#電子發票-api-境外電商版)

境外電商版的電子發票 API 主要差異在於部分欄位不同，不支援載具和捐贈碼，但增加了外幣、匯率等欄位，因此可在金額中輸入最多兩位小數。

### 境外電商開立電子發票

[](#境外電商開立電子發票)

開立 B2C 電子發票的基本範例：

```
use Agriweather\EzPayInvoice\Enums\Invoice\CurrencyType;
use Agriweather\EzPayInvoice\Facades\EzPayInvoice;

$result = EzPayInvoice::crossBorder()
    ->invoice()
    ->create()
    ->withOrder('Order001') // 訂單編號
    ->withCustomer('John Doe') // 買受人姓名
    ->withEmail('customer@example.com') // 買受人電子信箱
    ->withAddress('台北市信義區信義路五段7號') // 買受人地址
    ->withCurrency(CurrencyType::USD) // 幣別：USD 美元
    ->withItem('國際商品', quantity: 1, unit: 'EA', price: 105.5, amount: 105.5) // 商品名稱、數量、單位、單價和金額
    ->withAmount(100.0, 5.5, 105.5) // 未稅銷售額、稅額、含稅銷售額
    ->withOriginalCurrencyAmount(100.0) // 營業人備註之原幣金額
    ->withExchangeRate(30.5) // 營業人備註之匯率
    ->issue();
```

設定電子發票使用幣別、原幣金額和匯率：

```
use Agriweather\EzPayInvoice\Enums\Invoice\CurrencyType;

$result = EzPayInvoice::crossBorder()
    ->invoice()
    ->create()

    ->withCurrency(CurrencyType::USD) // 幣別：USD 美元
    ->withOriginalCurrencyAmount(100.0) // 營業人備註之原幣金額
    ->withExchangeRate(30.5) // 營業人備註之匯率
```

ezPay 電子發票的幣別支援：

- USD
- HKD
- GBP
- AUD
- CAD
- SGD
- CHF
- JPY
- ZAR
- SEK
- NZD
- THB
- PHP
- IDR
- EUR
- KRW
- VND
- MYR
- CNY
- TWD

設定電子發票的商品項目和銷售額：

Important

銷售額計算方式，請務必與公司財會人員進行確認。

```
EzPayInvoice::crossBorder()
    ->invoice()
    ->create()

    // 增加商品項目
    ->withItem('測試商品', quantity: 1, unit: '個', price: 105.5, amount: 105.5)
    ->withItem('Test Product', quantity: 2, unit: 'EA', price: 217.5, amount: 435)

    // 批次增加商品項目
    ->withItems([
        [
            'name' => '測試商品',
            'quantity' => 1,
            'unit' => '個',
            'price' => 105.5,
            'amount' => 105.5,
        ],
        [
            'name' => 'Test Product',
            'quantity' => 2,
            'unit' => 'EA',
            'price' => 217.5,
            'amount' => 435,
        ],
    ])

    // 未稅銷售額、稅額、含稅銷售額
    ->withAmount(520.0, 20.5, 540.5)
```

設定發票備註：

```
EzPayInvoice::crossBorder()
    ->invoice()
    ->create()
    ->withComment('發票備註'); // 發票備註，字數限 200 字，如有難字則再縮短
```

立即開立發票：

```
// 立即開立發票
$result = EzPayInvoice::crossBorder()
    ->invoice()
    ->create()
    ...
    ->issue();

$result->invoiceNumber() // 發票號碼：'AB12345678'
$result->randomNumber() // 發票隨機碼：'1234'
$result->orderNo() // 訂單編號：'Order001'
$result->totalAmount() // 含稅銷售額：105.5
```

等待觸發開立發票：

```
// 等待觸發開立發票
// 當選擇此開立發票方式時，發票資料僅暫存於平台，需手動呼叫「觸發電子發票 API」來完成開立。
$result = EzPayInvoice::crossBorder()
    ->invoice()
    ->create()
    ...
    ->deferIssue();

// 預約自動開立發票
// 當選擇此開立發票方式時，發票會在設定時間自動開立，如需提前開立，可手動呼叫「觸發電子發票 API」。
$result = EzPayInvoice::crossBorder()
    ->invoice()
    ->create()
    ...
    ->scheduleAt('2025-03-01'); // 設定開立發票的時間

// 保存這些資料用於觸發開立發票
$result->invoiceTransNo() // ezPay 電子發票開立序號：'25072515224376654'
$result->orderNo() // 訂單編號：'Order001'
$result->totalAmount() // 含稅銷售額：105.5
```

### 境外電商觸發開立電子發票

[](#境外電商觸發開立電子發票)

若使用了 **等待觸發開立發票** (`deferIssue()`) 方式，需呼叫觸發電子發票 API 來完成開立。若使用 **預約自動開立發票** (`scheduleAt()`) 方式，則可透過呼叫觸發 API 來提前開立發票：

```
$result = EzPayInvoice::crossBorder()
    ->invoice()
    ->pending()
    ->withInvoiceTransNo('25072515224376654')
    ->withOrder('Order004')
    ->withTotalAmount(217.5)
    ->trigger();
```

### 境外電商查詢電子發票

[](#境外電商查詢電子發票)

使用發票號碼和隨機碼查詢電子發票：

```
$invoiceResult = EzPayInvoice::crossBorder()
    ->invoice()
    ->query()
    ->withInvoice('GG72002017')
    ->withRandomNumber('1234')
    ->get();
```

或者也可使用訂單編號及發票金額查詢電子發票：

```
$invoiceResult = EzPayInvoice::crossBorder()
    ->invoice()
    ->query()
    ->withOrder('Order001')
    ->withTotalAmount(105.5)
    ->get();
```

電子發票查詢結果包含以下資訊：

```
$invoiceResult->invoiceNumber() // 發票號碼：'GG72002017'
$invoiceResult->randomNumber() // 發票隨機碼：'1234'
$invoiceResult->orderNo() // 訂單編號：'Order001'
$invoiceResult->invoiceTransNo() // ezPay 電子發票開立序號：'25072515224376654'

$invoiceResult->invoiceStatus() // 發票狀態：`InvoiceStatus::ISSUED` (已開立)
$invoiceResult->invoiceUploadStatus() // 發票上傳財政部之狀態：`InvoiceUploadStatus::UPLOADED` (已上傳)

$invoiceResult->buyerName() // 買受人名稱：'John Doe'
$invoiceResult->buyerAddress() // 買受人地址：'台北市信義區信義路五段7號'
$invoiceResult->buyerEmail() // 買受人電子信箱：'customer@example.com'

$invoiceResult->invoiceType() // 發票類別：`InvoiceType::GENERAL` (07: 一般稅額計算)

$invoiceResult->currency() // 幣別：`CurrencyType::USD` (USD 美元)
$invoiceResult->originalCurrencyAmount() // 營業人備註之原幣金額：100.0
$invoiceResult->exchangeRate() // 營業人備註之匯率：30.5

$invoiceResult->amount() // 發票銷售額合計 (未稅)：100.0
$invoiceResult->taxAmount() // 稅額：5.5
$invoiceResult->totalAmount() // 含稅銷售額：105.5

$items = $invoiceResult->items() // 商品項目陣列
// [
//     [
//         'number' => 1,
//         'name' => '測試商品',
//         'quantity' => 1,
//         'unit' => '個',
//         'price' => 105.5,
//         'amount' => 105.5,
//     ],
//     [
//         'number' => 2,
//         'name' => 'Test Product',
//         'quantity' => 2,
//         'unit' => 'EA',
//         'price' => 217.5,
//         'amount' => 435,
//     ],
// ]
```

除了透過 API 查詢電子發票外，也可以直接跳轉到 ezPay 平台的查詢發票頁面：

```
Route::get('/invoice/search', function () {
    return EzPayInvoice::crossBorder()
        ->invoice()
        ->query()
        ->withInvoice('GG72002017')
        ->withRandomNumber('1234')
        ->redirectToEzPay();
});
```

或者是取得表單資料，並自行撰寫前端表單進行跳轉：

Tip

HTML 表單可以參考 [src/Transporters/FormRedirectTransporter.php](src/Transporters/FormRedirectTransporter.php)

```
$requestData = EzPayInvoice::invoice()
    ->query()
    ->withInvoice('GG72002017')
    ->withRandomNumber('1234')
    ->toRedirectRequestData();

// [
//     'url' => 'https://cinv.ezpay.com.tw/Api/invoice_issue',
//     'formData' => [
//         'MerchantID_' => 'your-merchant-id',
//         'PostData' => 'xxxxxx',
//     ],
// ]
```

或者是單純取得 ezPay 平台的查詢發票網址：

```
$url = EzPayInvoice::crossBorder()
    ->invoice()
    ->query()
    ->withInvoice('GG72002017')
    ->withRandomNumber('1234')
    ->getEzPaySearchUrl();

// 'https://inv.ezpay.com.tw/Invoice_index/search_platform?PostData=xxxxxx'
```

### 境外電商作廢電子發票

[](#境外電商作廢電子發票)

作廢電子發票需要傳入發票號碼和作廢原因：

```
EzPayInvoice::crossBorder()
    ->invoice()
    ->voidable()
    ->withInvoice('GG72002017')
    ->because('客戶取消訂單')
    ->invalidate();
```

### 境外電商開立折讓

[](#境外電商開立折讓)

當需要對已開立的電子發票進行部分或全部退貨時，可以立即開立發票折讓 (同時會立即確認折讓)：

```
$result = EzPayInvoice::crossBorder()
    ->allowance()
    ->create()
    ->withInvoice('GG72002018')
    ->withOrder('Order001')
    ->withItem('退貨商品', quantity: 2, unit: '個', price: 217.5, amount: 435)
    ->withTotalAmount(435)
    ->withNotification('customer@example.com')
    ->issue();

$result->allowanceNo() // 折讓號：'A250725235346456'
$result->orderNo() // 訂單編號：'Order001'
$result->invoiceNumber() // 發票號碼：'GG72002018'
$result->allowanceAmount() // 折讓金額：435
$result->remainingAmount() // 折讓後剩餘發票金額：105.5
```

### 境外電商開立並延遲確認折讓

[](#境外電商開立並延遲確認折讓)

開立延遲確認的折讓，待買受人確認折讓後，再向 ezPay 平台發動確認折讓：

```
$result = EzPayInvoice::crossBorder()
    ->allowance()
    ->create()
    ...
    ->issuePendingConfirmation();
```

買受人發動確認折讓：

```
EzPayInvoice::crossBorder()
    ->allowance()
    ->pending()
    ->withAllowance('A250726001830959')
    ->withOrder('Order001')
    ->withTotalAmount(435)
    ->confirm();
```

買受人發動取消折讓：

```
EzPayInvoice::crossBorder()
    ->allowance()
    ->pending()
    ->withAllowance('A250726001830959')
    ->withOrder('Order001')
    ->withTotalAmount(435)
    ->cancel();
```

### 境外電商作廢折讓

[](#境外電商作廢折讓)

作廢已開立的折讓，需傳入折讓號和作廢原因：

```
EzPayInvoice::crossBorder()
    ->allowance()
    ->voidable()
    ->withAllowance('A250726001830959')
    ->because('作廢原因')
    ->invalidate();
```

字軌管理 API
--------

[](#字軌管理-api)

### 準備帳號代號和金鑰

[](#準備帳號代號和金鑰)

字軌管理和開立電子發票需要不同的帳號代號和金鑰。首先前往 ezPay 電子發票平台的「會員管理」頁面，找到並複製會員編號、會員 API 串接金鑰的 `HashKey` 和 `HashIV`，然後將這些資訊設定到 `.env` 檔案中的 `EZPAY_INVOICE_COMPANY_ID` 等參數：

```
EZPAY_INVOICE_COMPANY_ID=your-company-id
EZPAY_INVOICE_COMPANY_HASH_KEY=your-company-hash-key
EZPAY_INVOICE_COMPANY_HASH_IV=your-company-hash-iv
```

### 申請新字軌

[](#申請新字軌)

使用新增字軌 API 申請新字軌：

```
use Agriweather\EzPayInvoice\Enums\Invoice\InvoiceTerm;
use Agriweather\EzPayInvoice\Enums\Invoice\InvoiceType;
use Agriweather\EzPayInvoice\Facades\EzPayInvoice;

$result = EzPayInvoice::alphanumericCode()
    ->create()
    ->withYear(113) // 民國年，只可輸入今年與明年。
    ->withTerm(InvoiceTerm::JUL_AUG) // 發票期別：07-08月
    ->withCode('AA') // 字軌英文代碼
    ->withRange('24000100', '24000199') // 發票號碼範圍
    ->withType(InvoiceType::GENERAL) // 發票類別：`InvoiceType::GENERAL` (07: 一般稅額計算)
    ->save();

$result->managementNo() // 字軌管理編號：'0t0ghr0fyv'
$result->lastNumber() // 該組字軌剩餘張數：100
$result->status() // 字軌狀態： `AlphanumericCodeStatus::ACTIVE` (啟用)
```

### 查詢字軌

[](#查詢字軌)

使用發票年度和期別來查詢字軌資訊：

```
$alphanumericCodeResults = EzPayInvoice::alphanumericCode()
    ->query()
    ->withYear(113)
    ->withTerm(InvoiceTerm::JUL_AUG)
    ->get();

foreach ($alphanumericCodeResults as $result) {
    $result->managementNo() // 字軌管理編號：'0t0ghr0fyv'
    $result->year() // 發票年度：113
    $result->term() // 發票期別：`InvoiceTerm::JUL_AUG` (07-08月)
    $result->alphanumericCode() // 字軌英文代碼：'AA'
    $result->startNumber() // 字軌起號：'24000100'
    $result->endNumber() // 字軌迄號：'24000199'
    $result->lastNumber() // 該組字軌剩餘張數：100
    $result->type() // 發票類別：`InvoiceType::GENERAL` (07: 一般稅額計算)
    $result->status() // 字軌狀態： `AlphanumericCodeStatus::ACTIVE` (啟用)
}
```

### 啟用字軌

[](#啟用字軌)

如果字軌是暫停狀態，可以啟用字軌。需要傳入字軌管理編號和發票年度：

```
EzPayInvoice::alphanumericCode()
    ->query()
    ->withNo('0t0ghr0fyv')
    ->withYear(113)
    ->enable();
```

### 暫停字軌

[](#暫停字軌)

如果字軌是啟用狀態，可以暫停字軌。需要傳入字軌管理編號和發票年度：

```
$result = EzPayInvoice::alphanumericCode()
    ->query()
    ->withNo('0t0ghr0fyv')
    ->withYear(113)
    ->pause();
```

### 停用字軌

[](#停用字軌)

可以停用字軌，但請注意，停用後將無法再啟用該字軌。需要傳入字軌管理編號和發票年度：

```
EzPayInvoice::alphanumericCode()
    ->query()
    ->withNo('0t0ghr0fyv')
    ->withYear(113)
    ->disable();
```

手機條碼與捐證碼驗證 API
--------------

[](#手機條碼與捐證碼驗證-api)

### 驗證手機條碼

[](#驗證手機條碼)

驗證手機條碼是否存在於財政部電子發票整合服務平台：

```
use Agriweather\EzPayInvoice\Facades\EzPayInvoice;

$result = EzPayInvoice::codeValidation()
    ->withBarcode('/ABC.123')
    ->check();

$result->isValid() // 手機條碼是否有效：true
```

### 驗證捐證碼

[](#驗證捐證碼)

驗證捐證碼是否存在於財政部電子發票整合服務平台：

```
use Agriweather\EzPayInvoice\Facades\EzPayInvoice;

$result = EzPayInvoice::codeValidation()
    ->withLoveCode('123')
    ->check();

$result->isValid() // 捐證碼是否有效：true
```

錯誤處理
----

[](#錯誤處理)

當 ezPay API 回傳失敗的回應時，會拋出 `EzPayInvoiceException` 例外，可以取得 ezPay 的錯誤代碼和錯誤訊息進行進一步處理：

```
use Agriweather\EzPayInvoice\Exceptions\EzPayInvoiceException;

try {
    $result = EzPayInvoice::invoice()
        ->create()
        ...
        ->issue();
} catch (EzPayInvoiceException $e) {
    $status = $e->getApiStatus(); // 'KEY10013'
    $message = $e->getApiMessage(); // '資料不可空白MerchantOrderNo'

    // 記錄錯誤日誌...
    logger()->error($e->getMessage(), $e->context());

    // 顯示錯誤訊息給使用者...
    return response()->json([
        'error' => $message,
    ], 400);
}
```

單元測試
----

[](#單元測試)

在單元測試中，可以使用 `EzPayInvoice::fake()` 模擬 API 回應，這邊要模擬開立發票回應，因此使用 `CreateResult` 來建立模擬回應資料：

```
