# 機能設計書 50-単位変換管理

## 概要

本ドキュメントは、InvenTreeシステムにおける単位変換管理機能の設計仕様を定義する。この機能は、物理単位の定義・変換を管理し、パラメータ値の単位計算を可能にする。

### 本機能の処理概要

**業務上の目的・背景**：
在庫管理や製造業務では、様々な物理単位（長さ、重量、容量等）を扱う必要がある。本機能は、標準的な物理単位に加えて、業務固有のカスタム単位を定義・管理できる。これにより、部品パラメータの単位を統一的に扱い、異なる単位間での比較や計算が可能になる。例えば、ある部品の長さが「mm」で、別の部品が「inch」で登録されていても、正確な比較やフィルタリングができる。

**機能の利用シーン**：
- 業務固有のカスタム単位を定義する
- 利用可能な全単位を確認する
- 部品パラメータに単位を設定する
- 単位間の変換を行う

**主要な処理内容**：
1. カスタム単位の定義・管理（CustomUnit）
2. 全単位の一覧取得（pint単位レジストリ）
3. 単位間の変換計算
4. パラメータテンプレートへの単位設定

**関連システム・外部連携**：
- pint（Python単位ライブラリ）
- パラメータテンプレート機能

**権限による制御**：
- カスタム単位の管理はスタッフ権限が必要
- 単位一覧の閲覧は認証済みユーザーで可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 34 | 管理センター画面 | 主機能 | 単位管理パネル |

## 機能種別

CRUD操作 / 設定管理 / 計算処理

## 入力仕様

### 入力パラメータ（カスタム単位）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | string | Yes | 単位名 | 既存単位と重複不可 |
| definition | string | Yes | 単位定義（pint形式） | 有効な単位定義 |
| symbol | string | No | 単位記号 | 既存シンボルと重複不可 |

### 入力データソース

- 管理画面の単位設定パネル
- APIリクエスト

## 出力仕様

### 出力データ（カスタム単位）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| pk | integer | 単位ID |
| name | string | 単位名 |
| definition | string | 単位定義 |
| symbol | string | 単位記号 |

### 出力データ（全単位）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| name | string | 単位名 |
| is_alias | boolean | エイリアスかどうか |
| compatible_units | array | 互換単位リスト |
| isdimensionless | boolean | 無次元かどうか |

### 出力先

- 管理画面の単位一覧テーブル
- APIレスポンス（JSON形式）

## 処理フロー

### 処理シーケンス（カスタム単位作成）

```
1. カスタム単位作成リクエスト
   └─ POST /api/units/
2. バリデーション
   └─ 名前・シンボルの重複チェック
3. 単位定義の検証
   └─ pint形式として有効か確認
4. CustomUnitレコード作成
   └─ common_customunit テーブルにINSERT
5. 単位レジストリの再構築
   └─ pint UnitRegistryに新単位を登録
```

### フローチャート

```mermaid
flowchart TD
    A[カスタム単位作成リクエスト] --> B[バリデーション]
    B --> C{名前重複?}
    C -->|Yes| D[エラー: 名前重複]
    C -->|No| E{シンボル重複?}
    E -->|Yes| F[エラー: シンボル重複]
    E -->|No| G[単位定義検証]
    G --> H{定義有効?}
    H -->|No| I[エラー: 無効な定義]
    H -->|Yes| J[DBレコード作成]
    J --> K[レジストリ再構築]
    K --> L[成功レスポンス]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-50-01 | 名前一意性 | カスタム単位名はシステム内で一意 | カスタム単位作成・更新時 |
| BR-50-02 | シンボル一意性 | シンボルが設定される場合、一意である必要がある | カスタム単位作成・更新時 |
| BR-50-03 | 定義形式 | pint形式の有効な単位定義が必要 | カスタム単位作成・更新時 |
| BR-50-04 | レジストリ同期 | カスタム単位変更時はレジストリを再構築 | 全てのカスタム単位変更 |

### 計算ロジック

単位定義文字列の構築：
```python
def fmt_string(self):
    fmt = f'{self.name} = {self.definition}'
    if self.symbol:
        fmt += f' = {self.symbol}'
    return fmt
```

単位変換：
```python
from InvenTree.conversion import convert_physical_value
result = convert_physical_value(value, target_unit)
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| カスタム単位一覧取得 | common_customunit | SELECT | カスタム単位一覧取得 |
| カスタム単位作成 | common_customunit | INSERT | 新規カスタム単位作成 |
| カスタム単位更新 | common_customunit | UPDATE | カスタム単位更新 |
| カスタム単位削除 | common_customunit | DELETE | カスタム単位削除 |

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

#### common_customunit

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name | ユーザー入力 | 一意制約あり |
| INSERT | definition | ユーザー入力 | pint形式 |
| INSERT | symbol | ユーザー入力 | 任意、一意 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 400 | ValidationError | 単位名が重複 | 別の名前を使用 |
| 400 | ValidationError | シンボルが重複 | 別のシンボルを使用 |
| 400 | ValidationError | 無効な単位定義 | pint形式の有効な定義を使用 |
| 403 | PermissionDenied | スタッフ権限なし | 管理者に権限付与を依頼 |

### リトライ仕様

作成・更新操作は冪等であり、再試行が可能。

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

カスタム単位の保存は単一トランザクションで実行。レジストリ再構築は保存後のシグナルで実行。

## パフォーマンス要件

- カスタム単位CRUD：200ms以内
- 全単位一覧取得：300ms以内

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

- カスタム単位の管理はスタッフ権限が必要
- 単位定義はpint形式でサニタイズ

## 備考

- pint（Python単位ライブラリ）を使用
- カスタム単位はシステム起動時にレジストリに読み込まれる

---

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

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

### 推奨読解順序

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

カスタム単位のデータモデルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | models.py | `src/backend/InvenTree/common/models.py` | CustomUnitクラス（1791-1860行目） |

**読解のコツ**:
- `fmt_string()`で単位定義文字列を構築（pint形式）
- `validate_unique()`で名前とシンボルの一意性チェック
- `clean()`で単位定義の有効性検証

#### Step 2: フロントエンドの単位管理画面を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | UnitManagementPanel.tsx | `src/frontend/src/pages/Index/Settings/AdminCenter/UnitManagementPanel.tsx` | 単位管理パネル（1-74行目） |
| 2-2 | CustomUnitsTable.tsx | `src/frontend/src/tables/settings/CustomUnitsTable.tsx` | カスタム単位テーブル（1-129行目） |

**主要処理フロー**:
- `AllUnitTable`で全単位一覧を表示
- `CustomUnitsTable`でカスタム単位のCRUD操作

#### Step 3: バックエンドAPIを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | api.py | `src/backend/InvenTree/common/api.py` | CustomUnitList, CustomUnitDetail, AllUnitList（498-543行目） |

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

```
UnitManagementPanel
    │
    ├─ CustomUnitsTable
    │      │
    │      ├─ GET /api/units/
    │      │      └─ CustomUnitList.get()
    │      │
    │      ├─ POST /api/units/
    │      │      └─ CustomUnitList.create()
    │      │             └─ CustomUnit.save()
    │      │                    └─ レジストリ再構築シグナル
    │      │
    │      ├─ PATCH /api/units/{pk}/
    │      │      └─ CustomUnitDetail.update()
    │      │
    │      └─ DELETE /api/units/{pk}/
    │             └─ CustomUnitDetail.delete()
    │
    └─ AllUnitTable
           │
           └─ GET /api/units/all/
                  └─ AllUnitList.get()
                         └─ get_unit_registry()
```

### データフロー図

```
[フロントエンド]         [バックエンド]              [pint]

CustomUnitsTable   ───▶ CRUD /api/units/      ───▶ common_customunit
                                                     テーブル
                              │
                              ▼
                   レジストリ再構築シグナル
                              │
                              ▼
AllUnitTable       ───▶ GET /api/units/all/  ───▶ UnitRegistry
                              │                    (pint)
                              ▼
                   available_units返却
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| models.py | `src/backend/InvenTree/common/models.py` | ソース | CustomUnitモデル |
| api.py | `src/backend/InvenTree/common/api.py` | ソース | 単位API |
| serializers.py | `src/backend/InvenTree/common/serializers.py` | ソース | CustomUnitSerializer |
| conversion.py | `src/backend/InvenTree/InvenTree/conversion.py` | ソース | 単位変換ヘルパー |
| UnitManagementPanel.tsx | `src/frontend/src/pages/Index/Settings/AdminCenter/UnitManagementPanel.tsx` | ソース | 単位管理パネル |
| CustomUnitsTable.tsx | `src/frontend/src/tables/settings/CustomUnitsTable.tsx` | ソース | カスタム単位テーブル |
