# 帳票設計書 14-Part Label Code128

## 概要

本ドキュメントは、InvenTreeシステムにおける部品ラベル Code128版（Part Label Code128）の設計仕様を定義するものである。

### 本帳票の処理概要

本ラベルは、部品（Part）を識別するためのCode128バーコードと部品名を含むラベルを出力する機能を提供する。QRコードの代わりに1次元バーコード（Code128）を使用する点がNo.13と異なる。

**業務上の目的・背景**：製造業や在庫管理において、一部の環境ではQRコードリーダーではなく、従来の1次元バーコードスキャナが使用されている。本ラベルは、そのような環境でも部品識別が行えるよう、Code128形式のバーコードを採用している。Code128は高密度で英数字を効率的にエンコードでき、物流・製造業界で広く普及している規格である。バーコードスキャンと目視での部品名確認を組み合わせることで、部品の取り違えを防止し、作業効率を向上させる。

**帳票の利用シーン**：従来型のバーコードスキャナを使用する環境での部品管理、新規部品の登録時、部品棚の整理時、部品保管容器へのラベル貼付時、既存ラベルの劣化・破損による再印刷時などに利用される。

**主要な出力内容**：
1. 部品を識別するCode128バーコード画像（部品のバーコードデータをエンコード）
2. 部品のフルネーム（part.full_name）のテキスト表示

**帳票の出力タイミング**：部品詳細画面から「ラベル印刷」操作を実行した際に出力される。複数の部品を選択して一括印刷することも可能。

**帳票の利用者**：資材管理者、製造担当者、在庫管理担当者、購買担当者、ピッキング作業者

## 帳票種別

ラベル

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | Part Detail | /part/{id} | 「Print Label」ボタン |
| - | Part List | /part/ | 複数選択後「Print Labels」ボタン |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | PDF |
| 用紙サイズ | カスタム（テンプレート設定による） |
| 向き | - |
| ファイル名 | output.pdf（デフォルト、テンプレート設定で変更可能） |
| 出力方法 | ダウンロード / プラグインによる直接印刷 |
| 文字コード | UTF-8 |

### PDF固有設定

| 項目 | 内容 |
|-----|------|
| パスワード保護 | 無 |
| 印刷制限 | 無 |
| 電子署名 | 無 |

## 帳票レイアウト

### レイアウト概要

ラベル左側にCode128バーコード、右側に部品フルネームを表示するレイアウト。バーコードはラベルの高さと同じ幅の正方形エリアに配置され、テキストはバーコードの右側に配置される。

```
┌─────────────────────────────────────┐
│  ┌─────────┐                        │
│  │ ││││││││││  Resistor 10K Ohm 1%  │
│  │ Code128 │                        │
│  │ ││││││││││                       │
│  │         │                        │
│  └─────────┘                        │
└─────────────────────────────────────┘
```

### バーコード部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | Code128バーコード | 部品のバーコードデータをエンコードした1次元バーコード | Part.barcode（qr_dataコンテキスト変数） | 画像（PNG base64） |

### テキスト部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | 部品フルネーム | 部品の完全名称（カテゴリパス含む場合あり） | Part.full_name（part.full_nameコンテキスト変数） | テキスト |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| 部品ID | 対象となる部品のID | Yes |
| テンプレートフィルタ | LabelTemplateのfiltersフィールドで定義されたフィルタ条件 | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| - | 指定なし（選択順） | - |

### 改ページ条件

1ラベル1ページ。複数部品選択時は各ラベルが個別のページとして出力される。

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

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| part_part | 部品情報の取得 | PRIMARY KEY (id) |
| part_partcategory | カテゴリ情報（full_name生成用） | FOREIGN KEY (category_id) |

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

#### part_part

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| id | 内部識別用 | WHERE id = {指定ID} | - |
| name | 部品名（full_nameの一部） | - | - |
| IPN | 内部品番 | - | full_nameに含まれる場合あり |
| barcode_data | バーコードデータ | - | JSON形式のバーコードデータ |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| バーコードサイズ | height（mm） x height（mm） | - | ラベル高さに基づく正方形エリア |
| テキスト配置位置 | left: height（mm） | - | バーコードの右側に配置 |
| full_name | Part.full_name プロパティ | - | 部品名（+IPN）の組み合わせ |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[ラベル印刷要求] --> B[LabelPrint API呼び出し]
    B --> C[テンプレート・アイテム検証]
    C --> D[DataOutput生成]
    D --> E[バックグラウンドタスク起動]
    E --> F[各部品に対してループ]
    F --> G[report_context取得]
    G --> H[テンプレートレンダリング]
    H --> I[Code128バーコード生成]
    I --> J[HTML→PDF変換]
    J --> K{全件処理完了?}
    K -->|No| F
    K -->|Yes| L[PDF結合]
    L --> M[DataOutput更新]
    M --> N[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| データなし | 指定された部品が存在しない | No valid items provided to template | 有効な部品IDを指定 |
| テンプレートエラー | テンプレートファイルが存在しない | Template file {name} does not exist | テンプレートファイルを確認 |
| テンプレート構文エラー | テンプレートの構文が不正 | Template syntax error | テンプレートを修正 |
| プラグインエラー | 印刷プラグインが見つからない | Plugin not found | プラグイン設定を確認 |
| バーコードデータエラー | データが空 | No data provided to 'barcode' template tag | 有効なバーコードデータを設定 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 1〜100件/回 |
| 目標出力時間 | 10件あたり5秒以内 |
| 同時出力数上限 | システム設定による |

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

- ラベル印刷はログイン済みユーザーのみ実行可能（IsAuthenticatedOrReadScope）
- バーコードには部品の内部識別子のみが含まれ、機密情報は含まれない
- 部品名は組織内部の情報であるため、適切なアクセス制御が必要
- テンプレートの作成・編集はスタッフ権限が必要（IsStaffOrReadOnlyScope）

## 備考

- Code128バーコードの生成には`python-barcode`ライブラリを使用
- Code128は英数字および一部の記号をエンコード可能
- デフォルトの画像形式はPNG
- テンプレートはDjangoテンプレート言語で記述され、カスタマイズ可能
- テンプレートファイル: `part_label_code128.html`
- No.13との違いはQRコード→Code128バーコードの変更のみ（テンプレートタグが`qrcode`→`barcode`）

---

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

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

### 推奨読解順序

#### Step 1: No.13との差異を理解する

まず、No.13（Part Label）との違いがバーコード生成部分のみであることを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | part_label.html | `src/backend/InvenTree/report/templates/label/part_label.html` | QRコード版（比較用）。31行目で`{% qrcode qr_data %}`を使用 |
| 1-2 | part_label_code128.html | `src/backend/InvenTree/report/templates/label/part_label_code128.html` | Code128版。31行目で`{% barcode qr_data %}`を使用 |

**読解のコツ**: 両テンプレートを比較し、唯一の違いがバーコード生成タグ（`qrcode` vs `barcode`）であることを確認。

#### Step 2: barcodeテンプレートタグを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | barcode.py | `src/backend/InvenTree/report/templatetags/barcode.py` | barcodeテンプレートタグ（99-133行目）の実装。python-barcodeライブラリの使用方法を確認 |

**主要処理フロー**:
- **99-114行目**: 関数定義とdocstring
  - `barcode_class='code128'` がデフォルト値
  - format, fill_color, back_color, scaleなどのオプション
- **120行目**: `python_barcode.get_barcode_class(barcode_class)` でCode128クラスを取得
- **124行目**: データのゼロパディング（必要な桁数に調整）
- **128行目**: バーコード画像の生成
- **130行目**: 画像のレンダリング
- **133行目**: base64エンコードして返却

#### Step 3: データ構造を理解する（No.13と同一）

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | models.py | `src/backend/InvenTree/part/models.py` | Partモデルのreport_context()メソッド（555-570行目）。`qr_data`（実際にはバーコードデータ）が提供される |

#### Step 4: テンプレート構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | part_label_code128.html | `src/backend/InvenTree/report/templates/label/part_label_code128.html` | Code128ラベルの構造。`.qr`クラス名は変更されていないがCode128バーコードを表示 |

**主要処理フロー**:
- **7-15行目**: バーコードのスタイル定義（heightに基づく正方形エリア）
- **17-25行目**: `.part`クラスのスタイル定義
- **31行目**: `{% barcode qr_data %}` でCode128バーコード生成
- **33-35行目**: 部品フルネームのテキスト表示

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

```
LabelPrint.post() [api.py:157]
    │
    ├─ serializer.is_valid() [api.py:160]
    │
    ├─ get_plugin_class() [api.py:102-125]
    │
    ├─ template.get_model().objects.filter() [api.py:177]
    │
    └─ print() [api.py:187-224]
           │
           ├─ DataOutput.objects.create() [api.py:200-209]
           │
           └─ offload_task(report.tasks.print_labels) [api.py:213-220]
                  │
                  └─ LabelTemplate.print() [models.py:730]
                         │
                         ├─ plugin.before_printing()
                         │
                         ├─ plugin.print_labels()
                         │      │
                         │      └─ get_context() [models.py:704]
                         │             │
                         │             ├─ base_context()
                         │             │
                         │             └─ Part.report_context()
                         │                    │
                         │                    └─ returns: part, qr_data, name, IPN, etc.
                         │
                         │      テンプレートレンダリング時:
                         │      │
                         │      └─ {% barcode qr_data %} [barcode.py:99]
                         │             │
                         │             ├─ python_barcode.get_barcode_class('code128')
                         │             │
                         │             └─ barcode_image.render() → base64
                         │
                         └─ plugin.after_printing()
```

### データフロー図

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

Part.id ───────────────▶ LabelPrint API ──────────────────▶ DataOutput
                               │
                               ▼
                         LabelTemplate
                               │
                               ▼
                    ┌─────────────────────┐
                    │   report_context()  │
                    │  - part             │
                    │  - qr_data          │◀─── barcode tagのinput
                    │  - name             │
                    │  - IPN              │
                    └─────────────────────┘
                               │
                               ▼
                    ┌──────────────────────────┐
                    │ part_label_code128.html  │
                    │  + label_base.html       │
                    └──────────────────────────┘
                               │
                    ┌──────────┴──────────┐
                    ▼                     ▼
            ┌─────────────┐       ┌─────────────┐
            │ barcode tag │       │ part.full_name│
            │ (Code128)   │       └─────────────┘
            └─────────────┘              │
                    │                    │
                    ▼                    ▼
           Code128バーコード画像    テキスト
                    │                    │
                    └────────┬───────────┘
                             ▼
                        WeasyPrint ────────────────────▶ PDF
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| api.py | `src/backend/InvenTree/report/api.py` | ソース | ラベル印刷APIエンドポイント |
| models.py | `src/backend/InvenTree/report/models.py` | ソース | LabelTemplateモデル定義 |
| models.py | `src/backend/InvenTree/part/models.py` | ソース | Partモデルとreport_context |
| barcode.py | `src/backend/InvenTree/report/templatetags/barcode.py` | ソース | barcode/qrcodeテンプレートタグ |
| label_base.html | `src/backend/InvenTree/report/templates/label/label_base.html` | テンプレート | ラベル基底テンプレート |
| part_label_code128.html | `src/backend/InvenTree/report/templates/label/part_label_code128.html` | テンプレート | 本ラベルのテンプレート |
| part_label.html | `src/backend/InvenTree/report/templates/label/part_label.html` | テンプレート | 比較対象（QR版）のテンプレート |
