# 帳票設計書 1-Invoice（請求書）

## 概要

本ドキュメントは、ECモバイルアプリにおける請求書（Invoice）帳票の設計仕様を定義するものである。注文に対して発行された請求書の詳細情報を画面上に表示する機能について記述する。

### 本帳票の処理概要

本帳票は、顧客が注文詳細画面から請求書情報を確認するための機能を提供する。注文に紐づく請求書一覧を取得し、各請求書の明細項目と価格情報を整形して画面表示する。

**業務上の目的・背景**：ECサイトにおいて、顧客が注文内容と請求金額を正確に把握することは重要である。本帳票は、顧客が購入した商品の内訳、税額、配送料を含む請求明細を提供し、透明性のある取引記録を顧客に提示することを目的とする。これにより、顧客は支払い内容を確認でき、問い合わせ対応の効率化にも寄与する。

**帳票の利用シーン**：顧客が注文履歴から特定の注文を選択し、その請求内容を確認する場面で利用される。商品購入後の支払い確認、経費精算のための証憑確認、注文内容に疑問がある場合の照会などに使用される。

**主要な出力内容**：
1. 請求書ID（Invoice ID）
2. 商品明細（SKU、商品名、単価、数量、小計、税額、合計）
3. 価格詳細（小計、配送料、税額、総合計）
4. 配送・支払い情報

**帳票の出力タイミング**：注文詳細画面において、請求書情報セクションを選択またはタップした際に、GraphQL APIを通じてデータを取得し画面に表示する。

**帳票の利用者**：購入した商品の請求内容を確認したい一般顧客（エンドユーザー）。

## 帳票種別

請求書（Invoice）- 画面表示形式

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | 請求書詳細画面 | InvoiceScreen（Flutter Widget） | 注文詳細画面から請求書セクションを選択 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | 画面表示（Flutter Widget） |
| 用紙サイズ | N/A（モバイルアプリ画面） |
| 向き | 縦（スクロール可能） |
| ファイル名 | N/A |
| 出力方法 | 画面レンダリング |
| 文字コード | UTF-8 |

### PDF固有設定

N/A（本帳票は画面表示のみ）

### Excel固有設定

N/A

## 帳票レイアウト

### レイアウト概要

請求書画面は、請求書明細部と価格詳細部、配送・支払い情報部で構成される。スクロール可能なシングルカラムレイアウトを採用し、請求書が複数存在する場合は縦に並列表示される。

```
┌─────────────────────────────────────┐
│           AppBar（請求書）           │
├─────────────────────────────────────┤
│     請求書 #ID                      │
│     ─────────────────               │
│     商品明細リスト                   │
│     - SKU / 商品名 / 単価 / 数量等    │
├─────────────────────────────────────┤
│     価格詳細                        │
│     - 小計 / 配送料 / 税額 / 合計    │
├─────────────────────────────────────┤
│     配送・支払い情報                 │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | 請求書ID | 請求書の識別番号 | ViewInvoices.id | "Invoice #" + ID |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | SKU | 商品SKUコード | InvoicesItems.sku | 文字列 | 自動 |
| 2 | 商品名 | 商品の名称 | InvoicesItems.name | 文字列 | 自動 |
| 3 | 単価 | 商品1点あたりの価格 | InvoicesItems.formattedPrice.price | 通貨形式 | 自動 |
| 4 | 数量 | 購入数量 | InvoicesItems.qty | 整数 | 自動 |
| 5 | 小計 | 商品の基本合計額 | InvoicesItems.formattedPrice.baseTotal | 通貨形式 | 自動 |
| 6 | 税額 | 商品にかかる税額 | InvoicesItems.formattedPrice.taxAmount | 通貨形式 | 自動 |
| 7 | 合計 | 商品の最終合計額 | InvoicesItems.formattedPrice.total | 通貨形式 | 自動 |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | 小計 | 全商品の小計 | ViewInvoices.formattedPrice.subTotal | 通貨形式 |
| 2 | 配送料 | 配送にかかる費用 | ViewInvoices.formattedPrice.shippingAmount | 通貨形式 |
| 3 | 税額 | 税金の合計 | ViewInvoices.formattedPrice.taxAmount | 通貨形式 |
| 4 | 総合計 | 最終請求金額 | ViewInvoices.formattedPrice.grandTotal | 通貨形式 |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| 注文ID | 対象注文の識別子 | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | 請求書ID | APIレスポンス順（デフォルト） |

### 改ページ条件

N/A（画面スクロールにより全件表示）

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| invoices | 請求書基本情報 | order_id = 指定注文ID |
| invoice_items | 請求書明細 | invoice_id = invoices.id |
| orders | 注文情報 | id = 指定注文ID |

### テーブル別参照項目詳細

#### invoices

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| id | 請求書ID | order_id一致 | - |
| sub_total | 小計 | - | フォーマット済み価格で取得 |
| shipping_amount | 配送料 | - | フォーマット済み価格で取得 |
| tax_amount | 税額 | - | フォーマット済み価格で取得 |
| grand_total | 総合計 | - | フォーマット済み価格で取得 |

#### invoice_items

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| id | 明細ID | invoice_id一致 | - |
| sku | SKU | - | - |
| name | 商品名 | - | - |
| qty | 数量 | - | - |
| price | 単価 | - | フォーマット済み |
| base_total | 小計 | - | フォーマット済み |
| tax_amount | 税額 | - | フォーマット済み |
| total | 合計 | - | フォーマット済み |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| 商品小計 | 単価 × 数量 | サーバー側で計算済み | バックエンドで計算 |
| 税額 | 課税対象額 × 税率 | サーバー側で計算済み | バックエンドで計算 |
| 総合計 | 小計 + 配送料 + 税額 | サーバー側で計算済み | バックエンドで計算 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[注文詳細画面で請求書セクションを選択] --> B[InvoiceScreen初期化]
    B --> C[OrderInvoiceBloc初期化]
    C --> D[OrderInvoiceFetchDataEventを発行]
    D --> E[OrderInvoiceRepositoryでAPI呼び出し]
    E --> F[GraphQL viewInvoicesクエリ実行]
    F --> G[InvoicesModelにパース]
    G --> H{データ取得成功?}
    H -->|Yes| I[OrderInvoiceListDataState.success発行]
    H -->|No| J[OrderInvoiceListDataState.fail発行]
    I --> K[invoiceDetails()で画面レンダリング]
    J --> L[エラー状態表示]
    K --> M[請求書明細・価格詳細・配送支払い情報を表示]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| データなし | 請求書が存在しない | EmptyDataView表示 | 空データビューを表示 |
| 通信エラー | ネットワーク障害 | エラーメッセージ | 再試行またはオフライン対応 |
| APIエラー | サーバー側エラー | エラーメッセージ | エラーログ出力、再試行促進 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 1注文あたり1〜数件の請求書 |
| 目標出力時間 | 2秒以内 |
| 同時出力数上限 | N/A（ユーザー単位で逐次処理） |

## セキュリティ考慮事項

- 認証済みユーザーのみがアクセス可能（ログインセッション必須）
- 自身の注文に紐づく請求書のみ参照可能（他ユーザーの請求書は参照不可）
- GraphQL APIはHTTPS通信で保護
- 価格情報は改ざん防止のためサーバー側で計算・整形済みデータを使用

## 備考

- 本帳票はFlutterアプリ内での画面表示機能であり、PDFや印刷出力には対応していない
- 価格のフォーマット（通貨記号、小数点桁数等）はサーバー側のformattedPriceで処理済み
- ShippingAndPaymentInfoウィジェットで配送・支払い情報を共通表示

---

## コードリーディングガイド

本帳票を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、請求書データのモデル構造を把握することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | order_invoices_model.dart | `lib/data_model/order_model/order_invoices_model.dart` | InvoicesModel、ViewInvoices、InvoicesItemsの構造を理解。各フィールドがAPIレスポンスのどの部分に対応するか確認 |
| 1-2 | cart_data_model.dart | `lib/screens/cart_screen/cart_model/cart_data_model.dart` | FormattedPriceクラス（157-188行目）を確認。価格関連フィールド（price, total, taxAmount等）の構造を理解 |

**読解のコツ**: `@JsonSerializable()`アノテーションと`@JsonKey`でJSONとの対応付けを確認する。`part 'xxx.g.dart'`は自動生成されるシリアライズコード。

#### Step 2: エントリーポイントを理解する

処理の起点となる画面ウィジェットを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | invoice_details.dart | `lib/screens/order_invoices/view/invoice_details.dart` | InvoiceScreenウィジェットの構造と状態管理を理解 |

**主要処理フロー**:
1. **27-31行目**: initState()でOrderInvoiceBlocを取得し、OrderInvoiceFetchDataEventを発行
2. **48-62行目**: BlocConsumerでStateを監視し、成功時にinvoiceDetails()を呼び出し
3. **64-123行目**: invoiceDetails()で請求書データをUIにレンダリング
4. **166-231行目**: getInvoices()で各請求書の明細をListView形式で表示

#### Step 3: BLoCパターンによる状態管理を理解する

Flutterの状態管理としてBLoCパターンを採用している。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | order_invoice_bloc.dart | `lib/screens/order_invoices/bloc/order_invoice_bloc.dart` | イベントを受けてリポジトリを呼び出し、結果をStateとして発行する流れ |
| 3-2 | order_invoice_state.dart | `lib/screens/order_invoices/bloc/order_invoice_state.dart` | OrderInvoiceInitialState、OrderInvoiceListDataStateの定義 |

**主要処理フロー**:
- **23-34行目（bloc）**: mapEventToStateでOrderInvoiceFetchDataEventを処理し、成功/失敗に応じてStateを発行

#### Step 4: リポジトリ層とAPI通信を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | order_invoice_repository.dart | `lib/screens/order_invoices/bloc/order_invoice_repository.dart` | ApiClient().getInvoicesList()の呼び出し |
| 4-2 | api_client.dart | `lib/services/api_client.dart` | 1374-1386行目：getInvoicesListメソッドでGraphQLクエリを実行 |
| 4-3 | mutation_query.dart | `lib/services/mutation_query.dart` | 1849-1895行目：viewInvoicesのGraphQLクエリ定義 |

**主要処理フロー**:
- **1374行目（api_client）**: getInvoicesList()でmutation.getInvoicesList()を実行
- **1849行目（mutation_query）**: GraphQLクエリでorderId指定して請求書データを取得

### プログラム呼び出し階層図

```
InvoiceScreen (Widget)
    │
    ├─ initState()
    │      └─ OrderInvoiceBloc.add(OrderInvoiceFetchDataEvent)
    │
    ├─ BlocConsumer<OrderInvoiceBloc, OrderInvoiceBaseState>
    │      │
    │      └─ OrderInvoiceBloc.mapEventToState()
    │             └─ OrderInvoiceRepositoryImp.getInvoicesList()
    │                    └─ ApiClient.getInvoicesList()
    │                           └─ mutation.getInvoicesList() [GraphQL]
    │
    └─ invoiceDetails()
           ├─ getInvoices() [明細リスト表示]
           ├─ getOrdersRow() [価格行表示]
           └─ ShippingAndPaymentInfo [共通ウィジェット]
```

### データフロー図

```
[入力]                    [処理]                         [出力]

orderId ─────────▶ OrderInvoiceFetchDataEvent
                          │
                          ▼
                  OrderInvoiceBloc
                          │
                          ▼
                  OrderInvoiceRepositoryImp
                          │
                          ▼
                  ApiClient.getInvoicesList()
                          │
                          ▼
                  GraphQL viewInvoices Query ────▶ Backend Server
                          │
                          ▼
                  InvoicesModel (JSON Parse)
                          │
                          ▼
                  OrderInvoiceListDataState.success
                          │
                          ▼
                  InvoiceScreen.invoiceDetails() ────▶ UI表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| invoice_details.dart | `lib/screens/order_invoices/view/invoice_details.dart` | ソース | 請求書画面のUI実装 |
| order_invoice_bloc.dart | `lib/screens/order_invoices/bloc/order_invoice_bloc.dart` | ソース | 状態管理BLoC |
| order_invoice_state.dart | `lib/screens/order_invoices/bloc/order_invoice_state.dart` | ソース | 状態定義 |
| order_invoice_event.dart | `lib/screens/order_invoices/bloc/order_invoice_event.dart` | ソース | イベント定義 |
| order_invoice_repository.dart | `lib/screens/order_invoices/bloc/order_invoice_repository.dart` | ソース | リポジトリ層 |
| order_invoices_model.dart | `lib/data_model/order_model/order_invoices_model.dart` | ソース | データモデル定義 |
| cart_data_model.dart | `lib/screens/cart_screen/cart_model/cart_data_model.dart` | ソース | FormattedPriceモデル |
| api_client.dart | `lib/services/api_client.dart` | ソース | API通信クライアント |
| mutation_query.dart | `lib/services/mutation_query.dart` | ソース | GraphQLクエリ定義 |
| index.dart | `lib/screens/order_invoices/utils/index.dart` | ソース | エクスポート定義 |
