# 通知設計書 46-割当成功

## 概要

本ドキュメントは、InvenTreeモバイルアプリにおける「割当成功」通知の設計仕様を定義するものである。販売発注（Sales Order）に対する在庫の割当処理が正常に完了した際に、ユーザーに視覚的なフィードバックを提供するスナックバー通知について記載する。

### 本通知の処理概要

本通知は、バーコードスキャンまたは手動操作による在庫の販売発注への割当が成功したことをユーザーに通知するためのアプリ内スナックバー通知である。

**業務上の目的・背景**：販売発注処理において、注文に対する在庫の割当は重要な業務プロセスである。出荷準備のために、どの在庫アイテムをどの注文に割り当てるかを正確に管理する必要がある。割当が成功したことを即座にフィードバックすることで、作業者は次の作業（次のアイテムのスキャン、出荷処理など）に移行できる。

**通知の送信タイミング**：バーコードスキャンによる在庫割当API（POST `/api/barcode/so-allocate/`）が成功した場合、または割当フォーム送信が成功した場合に通知される。具体的には、`SOAllocateStockHandler`クラスの`onBarcodeMatched`メソッド内、または`launchApiForm`の`onSuccess`コールバック内でトリガーされる。

**通知の受信者**：割当操作を実行したユーザー本人のみ。アプリ内通知であるため、他のユーザーには通知されない。

**通知内容の概要**：「割当済み」を示すローカライズされたメッセージ（`L10().allocated`）と、成功を示す緑色の背景、チェックマークアイコンがスナックバーとして画面下部に表示される。バーコードスキャン経由の場合は成功音も再生される。

**期待されるアクション**：ユーザーは割当が完了したことを確認し、次のアイテムのスキャンや出荷処理に進む。

## 通知種別

アプリ内通知（スナックバー）+ 音声フィードバック

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 中 |
| リトライ | なし（UI通知のため） |

### 送信先決定ロジック

操作を実行したユーザーのアプリ画面に直接表示。ユーザー選択や条件分岐は不要。

## 通知テンプレート

### スナックバー通知

| 項目 | 内容 |
|-----|------|
| 背景色 | `Colors.lightGreen`（成功時） |
| アイコン | `TablerIcons.circle_check` |
| 表示時間 | 5秒 |
| 形式 | スナックバー（画面下部） |

### 音声通知

| 項目 | 内容 |
|-----|------|
| 音声ファイル | `sounds/barcode_scan.mp3` |
| 条件 | バーコードスキャン経由の場合 |

### 本文テンプレート

```
{L10().allocated}
```

英語の場合: "Allocated" または類似のメッセージ

### 添付ファイル

なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| allocated | 割当成功メッセージ | L10()（国際化リソース） | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| バーコードスキャン | SO割当APIの成功レスポンス | `line_item`キーが含まれる | `onBarcodeMatched`で処理 |
| フォーム送信 | 割当フォームのAPI成功 | APIレスポンスが成功 | `launchApiForm`の`onSuccess` |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| line_itemキーなし | バーコード不一致として処理される |
| APIエラー | エラー通知が代わりに表示される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[バーコードスキャン/フォーム送信] --> B{処理ルート}
    B -->|バーコード| C[API POST barcode/so-allocate/]
    B -->|フォーム| D[API POST allocate/]
    C --> E{レスポンス確認}
    D --> F{APIレスポンス確認}
    E -->|line_item有| G[barcodeSuccess - 成功音 + 通知]
    E -->|action_required有| H[割当フォーム表示]
    E -->|エラー| I[エラー通知]
    F -->|成功| J[showSnackIcon 割当成功]
    F -->|失敗| I
    H --> D
    G --> K[終了]
    J --> K
    I --> K
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| SalesOrder | 販売発注情報 | InvenTreeサーバー側 |
| SalesOrderLineItem | 発注明細情報 | InvenTreeサーバー側 |
| StockItem | 在庫アイテム情報 | InvenTreeサーバー側 |
| SalesOrderShipment | 出荷情報 | InvenTreeサーバー側 |

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

#### SalesOrderLineItem（サーバー側）

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| pk | ラインアイテムID | バーコード/指定 |
| order | 発注ID | ラインアイテムから取得 |
| part | パーツID | 割当対象パーツ |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| SalesOrderAllocation | INSERT | 在庫割当レコード作成 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| バーコード不一致 | 在庫アイテムが見つからない | エラー通知を表示 |
| 在庫不足 | 割当可能な在庫がない | エラー通知を表示 |
| 権限エラー | 割当権限がない | エラー通知を表示 |
| ネットワークエラー | API通信失敗 | エラー通知を表示 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0回（ユーザー操作による再試行） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | なし |
| 1日あたり上限 | なし |

### 配信時間帯

制限なし（ユーザー操作に応じて即座に表示）

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

- 割当操作は認証済みユーザーのみ実行可能
- 販売発注に対する適切な権限が必要
- バーコードスキャンによる割当はセキュアなAPI経由で処理

## 備考

- バーコードスキャン経由の場合は`barcodeSuccess`ヘルパー関数で処理され、音声フィードバックも含まれる
- フォーム送信経由の場合は`showSnackIcon`で直接通知
- バーコードで追加情報が必要な場合は`action_required`レスポンスによりフォームが表示される
- 国際化対応済み（L10()による多言語サポート）
- API version 160以上でサポートされる機能

---

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

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

### 推奨読解順序

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

バーコード割当のレスポンス構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | sales_order.dart | `lib/barcode/sales_order.dart` | SOAllocateStockHandlerクラスの構造 |
| 1-2 | handler.dart | `lib/barcode/handler.dart` | BarcodeHandlerの基本構造 |

**読解のコツ**: `onBarcodeMatched`と`onBarcodeUnhandled`の使い分けを確認する。

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

割当処理の起点を特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | sales_order.dart | `lib/barcode/sales_order.dart` | SOAllocateStockHandler.onBarcodeMatched（104-111行目） |

**主要処理フロー**:
1. **106-107行目**: `line_item`キーの確認
2. **110行目**: `barcodeSuccess(L10().allocated);` で成功通知

#### Step 3: 追加情報が必要な場合の処理を理解する

フォーム表示経由の割当を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | sales_order.dart | `lib/barcode/sales_order.dart` | SOAllocateStockHandler.onBarcodeUnhandled（114-153行目） |

**主要処理フロー**:
- **115-118行目**: `action_required`の確認
- **142-152行目**: `launchApiForm`と`onSuccess`での通知

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

```
SOAllocateStockHandler (sales_order.dart line 78)
    │
    ├─ processBarcode() (line 89-101)
    │      │
    │      └─ super.processBarcode() - バーコードAPIリクエスト
    │             url: "barcode/so-allocate/"
    │
    ├─ onBarcodeMatched() (line 104-111)
    │      │
    │      ├─ [line_item キーあり]
    │      │      │
    │      │      └─ barcodeSuccess(L10().allocated) (barcode.dart)
    │      │             ├─ barcodeSuccessTone() - 成功音
    │      │             └─ showSnackIcon() - 通知表示
    │      │
    │      └─ [line_item キーなし]
    │             └─ onBarcodeUnknown()
    │
    └─ onBarcodeUnhandled() (line 114-153)
           │
           ├─ [action_required & line_item あり]
           │      │
           │      └─ launchApiForm() - 割当フォーム表示
           │             │
           │             └─ onSuccess callback (line 149-151)
           │                    └─ showSnackIcon(L10().allocated, success: true)
           │
           └─ [その他]
                  └─ super.onBarcodeUnhandled()
```

### データフロー図

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

バーコード       ┌─────────────────┐
スキャン ───────▶│processBarcode() │
                 └────────┬────────┘
                          │
                          ▼
                 ┌─────────────────┐     API Request
                 │barcode/         │────────────────▶ InvenTreeサーバー
                 │so-allocate/     │◀────────────────
                 └────────┬────────┘     API Response
                          │
            ┌─────────────┼─────────────┐
            ▼             ▼             ▼
    ┌───────────┐  ┌───────────┐  ┌───────────┐
    │line_item  │  │action_    │  │error      │
    │含む       │  │required   │  │           │
    └─────┬─────┘  └─────┬─────┘  └─────┬─────┘
          │              │              │
          ▼              ▼              ▼
    ┌───────────┐  ┌───────────┐  ┌───────────┐
    │barcode    │  │launchApi  │  │エラー通知 │
    │Success()  │  │Form()     │  │           │
    └─────┬─────┘  └─────┬─────┘  └───────────┘
          │              │
          ▼              ▼
    ┌───────────┐  ┌───────────┐
    │成功音+    │  │フォーム   │
    │スナックバー│  │onSuccess  │
    └───────────┘  │→allocated │
                   └───────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| sales_order.dart | `lib/barcode/sales_order.dart` | ソース | SO割当バーコードハンドラー |
| handler.dart | `lib/barcode/handler.dart` | ソース | バーコードハンドラー基底クラス |
| barcode.dart | `lib/barcode/barcode.dart` | ソース | barcodeSuccess関数 |
| tones.dart | `lib/barcode/tones.dart` | ソース | 成功音再生 |
| snacks.dart | `lib/widget/snacks.dart` | ソース | スナックバー通知の表示関数 |
| api_form.dart | `lib/api_form.dart` | ソース | APIフォーム処理 |
| l10.dart | `lib/l10.dart` | ソース | 国際化ヘルパー関数 |
