# 機能設計書 53-ラベル印刷

## 概要

本ドキュメントは、InvenTreeモバイルアプリにおけるラベル印刷機能の設計を記述する。

### 本機能の処理概要

パーツ・在庫アイテム・ロケーションなどに対応したラベルを選択し、プリンタープラグイン経由で印刷する機能を提供する。

**業務上の目的・背景**：在庫管理において、物品の識別・追跡のためにラベル貼付は必須の業務である。バーコードやQRコード付きのラベルを印刷することで、スキャンによる迅速な在庫操作が可能となる。また、パーツや在庫アイテムに適切なラベルを貼付することで、保管場所の特定や在庫確認の効率化が実現できる。本機能は、現場でモバイルデバイスから直接ラベル印刷を指示できるため、業務効率を大幅に向上させる。

**機能の利用シーン**：パーツ詳細画面、在庫アイテム詳細画面、在庫ロケーション画面などで、印刷ボタンをタップしてラベル印刷ダイアログを開く。テンプレートとプリンタープラグインを選択し、印刷を実行する。

**主要な処理内容**：
1. 印刷対象のモデルタイプとインスタンスIDを受け取る
2. 利用可能なラベルテンプレートとプリンタープラグインを取得する
3. ユーザーが選択したテンプレートとプラグインで印刷リクエストを送信する
4. 印刷結果をポーリングして完了を確認する
5. PDF出力の場合はファイルをダウンロードして開く

**関連システム・外部連携**：InvenTree REST API（label/print/エンドポイント）、プリンタープラグイン（ラベル印刷ミキシン対応）との連携を行う。

**権限による制御**：認証済みユーザーのみがアクセス可能。ラベル印刷機能はアプリ設定で有効/無効を切り替え可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 22 | 部品詳細画面 | 補助機能 | ラベル印刷ボタン押下時に印刷処理実行 |
| 23 | 在庫ロケーション画面 | 補助機能 | ラベル印刷ボタン押下時に印刷処理実行 |
| 25 | 在庫アイテム詳細画面 | 補助機能 | ラベル印刷ボタン押下時に印刷処理実行 |

## 機能種別

データ連携 / 帳票出力

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| labelType | String | Yes | ラベルタイプ（part/stockitem/stocklocation等） | サーバー定義のタイプ |
| instanceId | int | Yes | 印刷対象インスタンスのID | 正の整数 |
| template | int | Yes | ラベルテンプレートのID | 正の整数 |
| plugin | String | Yes | プリンタープラグインのキー | 有効なプラグインキー |
| items | List<int> | Yes | 印刷対象アイテムIDリスト | 非空リスト |

### 入力データソース

- ユーザー操作（印刷ボタンタップ、テンプレート/プラグイン選択）
- InvenTree REST API（テンプレート一覧、プラグイン一覧）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| pk | int | 印刷ジョブのID |
| complete | bool | 印刷完了フラグ |
| output | String | 出力ファイルのURL（PDF等） |
| errors | dynamic | エラー情報（存在する場合） |

### 出力先

- プリンタープラグイン（物理プリンター出力）
- ファイルダウンロード（PDF出力の場合）
- 画面表示（成功/失敗メッセージ）

## 処理フロー

### 処理シーケンス

```
1. 印刷ボタンタップ
   └─ selectAndPrintLabel() 呼び出し
2. 接続・機能チェック
   └─ サーバー接続確認、モダンラベルAPI対応確認
3. デフォルト設定取得
   └─ 保存済みテンプレート・プラグインを取得
4. 印刷フォーム表示
   └─ launchApiForm() でテンプレート/プラグイン選択画面表示
5. プラグイン変更時の動的フィールド更新
   └─ onPluginChanged() で追加フィールドを取得
6. 印刷実行
   └─ POST label/print/ でジョブ送信
7. 印刷完了確認
   └─ handlePrintingSuccess() でポーリング
8. 結果処理
   ├─ 完了+出力ファイルあり → ダウンロード
   ├─ 完了+出力なし → 成功メッセージ表示
   └─ エラー → 失敗メッセージ表示
9. デフォルト設定保存
   └─ 選択したテンプレート・プラグインを永続化
```

### フローチャート

```mermaid
flowchart TD
    A[印刷ボタンタップ] --> B{接続確認}
    B -->|未接続| C[処理終了]
    B -->|接続済| D{モダンAPI対応?}
    D -->|No| E[非対応メッセージ]
    D -->|Yes| F[デフォルト設定取得]
    F --> G[印刷フォーム表示]
    G --> H{フォーム送信?}
    H -->|キャンセル| C
    H -->|送信| I[POST label/print/]
    I --> J[handlePrintingSuccess]
    J --> K{complete?}
    K -->|Yes| L{output存在?}
    K -->|No+retry| M{repeatCount < 60?}
    K -->|エラー| N[失敗メッセージ]
    L -->|Yes| O[ダウンロード]
    L -->|No| P[成功メッセージ]
    M -->|Yes| Q[1秒待機]
    Q --> R[data-output API]
    R --> J
    M -->|No| C
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-53-01 | モダンAPI必須 | APIバージョン201以上が必要 | 印刷実行時 |
| BR-53-02 | デフォルト保存 | 選択したテンプレート・プラグインを次回以降のデフォルトとして保存 | 印刷成功時 |
| BR-53-03 | ポーリング上限 | 印刷完了確認は最大60回（60秒） | 印刷ジョブ監視時 |
| BR-53-04 | プラグインフィルタ | ラベル印刷ミキシン対応プラグインのみ表示 | プラグイン選択時 |

### 計算ロジック

該当なし

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| テンプレート取得 | label templates | SELECT | 有効なテンプレート一覧取得 |
| プラグイン取得 | plugins | SELECT | ラベル印刷対応プラグイン取得 |
| 印刷ジョブ作成 | data_output | INSERT | 印刷ジョブを登録 |
| ジョブステータス取得 | data_output | SELECT | 印刷完了状態を確認 |

### テーブル別操作詳細

#### ローカル設定

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| GET/SET | defaultLabelPlugin | プラグインキー | Sembastで永続化 |
| GET/SET | defaultLabelTemplates | {type: templateId} | Sembastで永続化 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 非対応エラー | APIバージョン201未満 | エラーメッセージ表示 |
| - | 接続エラー | サーバー未接続時 | 接続を促す |
| - | 印刷失敗 | プラグインエラー時 | 失敗メッセージ表示 |

### リトライ仕様

印刷ジョブの完了確認は1秒間隔で最大60回ポーリング

## トランザクション仕様

印刷ジョブの作成・ステータス管理はサーバー側で制御

## パフォーマンス要件

- 印刷フォーム表示は2秒以内
- 印刷ジョブの完了確認は最大60秒

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

- 認証トークンによるアクセス制御
- プラグインはサーバー管理者が有効化したもののみ使用可能
- HTTPS通信による通信暗号化

## 備考

API バージョン201以降でのみサポート。旧APIのラベル印刷エンドポイントは非対応。

---

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

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

### 推奨読解順序

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

ラベル印刷機能のメインエントリーポイントを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | labels.dart | `lib/labels.dart` | selectAndPrintLabel()関数、印刷フロー全体 |

**読解のコツ**: selectAndPrintLabel()が主要なエントリーポイント。launchApiForm()でフォームを表示し、onSuccessコールバックで結果処理を行う。

**主要処理フロー**:
- **10行目**: PRINT_LABEL_URL定数定義 "label/print/"
- **209-280行目**: selectAndPrintLabel()関数
- **214-222行目**: 接続確認とモダンAPI対応チェック
- **227-241行目**: デフォルト設定（テンプレート・プラグイン）の取得
- **245-263行目**: フォームフィールドの定義
- **268-279行目**: launchApiForm()呼び出しと印刷実行

#### Step 2: 動的フォーム処理を理解する

プラグイン選択時の動的フィールド更新処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | labels.dart | `lib/labels.dart` | LabelFormWidgetState、onPluginChanged() |

**主要処理フロー**:
- **16-163行目**: LabelFormWidgetStateクラス
- **25-41行目**: formFieldsゲッター（動的フィールド結合）
- **43-48行目**: onValueChanged()でプラグイン変更検知
- **85-96行目**: onPluginChanged()でOPTIONSリクエスト
- **102-162行目**: updateFields()で動的フィールド構築

#### Step 3: 印刷結果処理を理解する

印刷ジョブの完了確認とポーリング処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | labels.dart | `lib/labels.dart` | handlePrintingSuccess() |

**主要処理フロー**:
- **165-202行目**: handlePrintingSuccess()関数
- **170行目**: MAX_REPEATS定数（60回）
- **172-175行目**: レスポンスデータの解析
- **177-185行目**: 完了時の処理（ダウンロードまたは成功メッセージ）
- **186-187行目**: エラー時の処理
- **188-201行目**: 未完了時のポーリング処理

#### Step 4: 設定永続化を理解する

デフォルト設定の保存・取得処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | labels.dart | `lib/labels.dart` | handleSuccess()での設定保存 |
| 4-2 | preferences.dart | `lib/preferences.dart` | 設定キー定義 |

**主要処理フロー**:
- **50-79行目**: handleSuccess()でデフォルト設定保存
- **62-63行目**: プラグインキーの保存
- **67-78行目**: テンプレートIDの保存（ラベルタイプ別）

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

```
selectAndPrintLabel() (labels.dart)
    │
    ├─ InvenTreeAPI().isConnected()
    │
    ├─ InvenTreeAPI().supportsModernLabelPrinting
    │
    ├─ InvenTreeSettingsManager().getValue()
    │      ├─ INV_LABEL_DEFAULT_TEMPLATES
    │      └─ INV_LABEL_DEFAULT_PLUGIN
    │
    ├─ launchApiForm() (api_form.dart)
    │      │
    │      └─ LabelFormWidgetState
    │             ├─ formFields
    │             ├─ onValueChanged()
    │             │      └─ onPluginChanged()
    │             │             └─ InvenTreeAPI().options()
    │             │                    └─ updateFields()
    │             │
    │             └─ handleSuccess()
    │                    └─ InvenTreeSettingsManager().setValue()
    │
    └─ handlePrintingSuccess()
           │
           ├─ (complete=true, output) → InvenTreeAPI().downloadFile()
           ├─ (complete=true, no output) → showSnackIcon()
           ├─ (error) → showSnackIcon()
           └─ (incomplete) → Future.delayed → InvenTreeAPI().get()
                                                └─ handlePrintingSuccess() [再帰]
```

### データフロー図

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

印刷ボタン       ───▶  selectAndPrintLabel()      ───▶  印刷フォーム
                          │
テンプレート選択  ───▶  launchApiForm()            ───▶  フォーム表示
プラグイン選択           │
                          ├─ OPTIONS label/print/
                          │      └─ 動的フィールド取得
                          │
                          ▼
フォーム送信     ───▶  POST label/print/          ───▶  印刷ジョブ作成
                          │
                          ▼
                   handlePrintingSuccess()
                          │
                          ├─ GET data-output/{id}/
                          │      └─ ポーリング(max 60回)
                          │
                          ▼
印刷完了        ◀───  complete=true               ───▶  ダウンロード/成功通知
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| labels.dart | `lib/labels.dart` | ソース | ラベル印刷機能メイン |
| api_form.dart | `lib/api_form.dart` | ソース | APIフォームウィジェット |
| api.dart | `lib/api.dart` | ソース | API通信・ファイルダウンロード |
| preferences.dart | `lib/preferences.dart` | ソース | 設定キー定義・永続化 |
| snacks.dart | `lib/widget/snacks.dart` | ソース | 通知メッセージ表示 |
| progress.dart | `lib/widget/progress.dart` | ソース | ローディングオーバーレイ |
