# データ仕様書

> **最終更新**: 2026-02-16
> **変更履歴**: M:N関係に更新、中山間モデル全17列対応、面積単位統一、帳票仕様追加

## 📊 データ構造の全体像

このシステムで扱うデータは3種類：

1. **実圃場データ**（吉田農地台帳.ods）- 実際に作業する農地
2. **共済マスタ**（水稲共済細目用.ods）- 申請書用の区画
3. **中山間マスタ**（中山間.ods）- 申請書用の区画

**紐付けの関係:**
- 実圃場 ↔ 共済区画: **M対N**（複数の実圃場が1つの共済区画に対応、また1つの実圃場が複数の共済区画に対応するケースもある）
- 実圃場 ↔ 中山間区画: **M対N**（同上）

```mermaid
erDiagram
    実圃場 }o--o{ 共済区画 : "紐づく(M:N)"
    実圃場 }o--o{ 中山間区画 : "紐づく(M:N)"
    実圃場 ||--o{ 作付け計画 : "持つ(1:N)"
    作付け計画 }o--|| 作物 : "参照"
    作付け計画 }o--o| 品種 : "参照(任意)"
    作物 ||--o{ 品種 : "持つ"

    実圃場 {
        int id PK
        string 名称
        string 住所
        decimal 面積_反
        int 面積_m2
        string 地主
        string グループ名
        int 表示順
        string 細目_耕地番号 "共済紐付けキー(raw)"
        string 細目_分筆番号 "共済紐付けキー(raw)"
        string 中山間_ID "中山間紐付けキー(raw)"
    }

    共済区画 {
        int id PK
        string 地名_地番
        int 耕地番号
        int 分筆番号
        decimal 本地面積_m2
        string 漢字地名
    }

    中山間区画 {
        int id PK
        string 中山間ID
        string 中山間フラグ
        string 大字
        string 字
        string 地番
        string 枝番
        string 地目
        int 農地面積_m2
        int 植栽面積_m2
        string 作付け品目_元
        string 協定管理者
        string 所有者
        string 傾斜度
        int 基本金額
        decimal 超急傾斜加算額
        decimal スマート農業加算額
        int 交付金額
    }

    作付け計画 {
        int id PK
        int 実圃場_id FK
        int 年度
        int 作物_id FK
        int 品種_id FK_nullable
        text 備考
    }

    作物 {
        int id PK
        string 作物名
    }

    品種 {
        int id PK
        int 作物_id FK
        string 品種名
    }
```

---

## 1. 実圃場データ（吉田農地台帳.ods）

### ファイル情報
- **行数:** 39行（39筆の圃場）
- **列数:** 7列

### カラム定義

| カラム名 | データ型 | 必須 | 説明 | 例 |
|---------|---------|-----|------|---|
| 名称 | string | ○ | 圃場の名称（自由記述） | "口神　１反２畝" |
| 住所 | string | ○ | 圃場の住所 | "口神ノ川１９８（笹ヶ谷374-1)" |
| 面積(反) | float | ○ | 面積（単位: 反）※1反=1000m2=10a | 1.20 |
| 地主 | string | ○ | 地主の氏名 | "山崎　出祥" |
| 細目_耕地番号 | int | ○ | 共済マスタとの紐付けキー（1/2） | 2 |
| 細目_分筆番号 | int | ○ | 共済マスタとの紐付けキー（2/2） | 1 |
| 中山間_ID | int | △ | 中山間マスタとの紐付けキー | 50 |

### DBモデル（Field）

| フィールド名 | データ型 | 説明 |
|-------------|---------|------|
| name | CharField(100) | 圃場名 |
| address | CharField(255) | 住所 |
| area_tan | DecimalField(6,4) | 面積（反） |
| area_m2 | IntegerField | 面積（m2）= area_tan × 1000 |
| owner_name | CharField(100) | 所有者名 |
| group_name | CharField(50), nullable | グループ名（エリアや用途による分類） |
| display_order | IntegerField, default=0 | リスト表示時の順序 |
| raw_kyosai_k_num | CharField(20), nullable | 細目_耕地番号（インポート元の値） |
| raw_kyosai_s_num | CharField(20), nullable | 細目_分筆番号（インポート元の値） |
| raw_chusankan_id | CharField(20), nullable | 中山間_ID（インポート元の値） |
| kyosai_fields | ManyToManyField → OfficialKyosaiField | 関連共済マスタ（M:N） |
| chusankan_fields | ManyToManyField → OfficialChusankanField | 関連中山間マスタ（M:N） |
| location | PointField, nullable | 位置情報（Phase 1では未使用） |

### データサンプル
```
名称             住所                         面積(反)  細目_耕地番号  細目_分筆番号  中山間_ID
口神　１反２畝    口神ノ川１９８（笹ヶ谷374-1)     1.20          2            1            50
口神　北東        口神ノ川１９８（笹ヶ谷374-1)     0.40          2            2            50
口神　北中        口神ノ川１９８（笹ヶ谷374-1)     0.43          2            2            50
```

### 特記事項
- **中山間_IDは一部NULL**: 39筆中2筆が中山間の対象外（`NaN`）
- **同じ共済区画に複数の実圃場**: 例えば共済キー「2-2」には3つの実圃場が紐づく
- **1つの実圃場が複数の申請区画に紐づくケースもある**: M:N関係で対応
- **面積単位**: DB内部では「反（DecimalField）」と「m2（IntegerField）」の両方を保持する（変換: 1反=1000m2）
- **グループ機能**: group_name でエリア分け、display_order で表示順を制御

---

## 2. 共済マスタ（水稲共済細目用.ods）

### ファイル情報
- **行数:** 31行（31区画）
- **列数:** 5列

### カラム定義

| カラム名 | データ型 | 必須 | 説明 | 例 |
|---------|---------|-----|------|---|
| 地名 地番 | string | ○ | 地名と地番（スペース区切り） | "四万十町 ササガタニ 374-1" |
| 耕地番号 | int | ○ | 共済区画の識別子（1/2） | 2 |
| 分筆番号 | int | ○ | 共済区画の識別子（2/2） | 1 |
| 本地面積 (m2) | float | ○ | 申請上の面積（単位: m2） | 25.4 |
| 漢字地名 | string | ○ | 漢字表記の地名 | "四万十町 笹ヶ谷 374-1" |

### DBモデル（OfficialKyosaiField）

| フィールド名 | データ型 | 説明 |
|-------------|---------|------|
| k_num | IntegerField | 耕地番号 |
| s_num | IntegerField | 分筆番号 |
| address | CharField(200) | 地名地番 |
| kanji_name | CharField(200) | 漢字地名 |
| area | IntegerField | 本地面積（m2） |

**制約:** (k_num, s_num) のペアで一意（unique_together）

### データサンプル
```
地名 地番                  耕地番号  分筆番号  本地面積(m2)  漢字地名
四万十町 ササガタニ 374-1      2        1        25.4      四万十町 笹ヶ谷 374-1
四万十町 ササガタニ 374-1      2        2        12.0      四万十町 笹ヶ谷 374-1
```

### 特記事項
- **面積の不整合は許容**: 役場データが古いため、実圃場の合計面積と一致しないことがある
  - 例: 共済キー「2-2」の面積は12.0m2だが、実圃場の合計は1.33反=1330m2
  - これは「そういうもの」として扱い、システム側で修正しない
- **重複キーなし**: (耕地番号, 分筆番号)の組み合わせは一意

---

## 3. 中山間マスタ（中山間.ods）

### ファイル情報
- **行数:** 71行（71区画）
- **列数:** 17列（全列をDBに保存）

### カラム定義（全17列）

| カラム名 | データ型 | 必須 | 説明 | 例 |
|---------|---------|-----|------|---|
| ID | int | ○ | 中山間区画の識別子 | 1 |
| 中山間 | string | ○ | 中山間フラグ | "〇" |
| 大字 | string | ○ | 大字名 | "口神ノ川" |
| 字 | string | ○ | 字名 | "壱町切" |
| 地番 | string | ○ | 地番（数値でないケースあり：イ、ロ等） | "1694" |
| 枝番 | string | △ | 枝番（-, 1, イ, ロ等） | "-" |
| 地目 | string | ○ | 地目 | "田" |
| 農地面積 | int | ○ | 農地面積（m2） | 2900 |
| 植栽面積 | int | ○ | 植栽面積（m2） | 2748 |
| 作付け品目 | string | △ | 役場が記入した作付け品目 | "ニラ" |
| 協定管理者 | string | ○ | 協定管理者名 | "神山倫子" |
| 所有者 | string | △ | 所有者名（NULLあり） | "谷脇史男" |
| 傾斜度 | string | ○ | 傾斜度 | "1/29" |
| 基本金額 | int | ○ | 基本金額（円） | 23200 |
| 超急傾斜加算額 | decimal | △ | 超急傾斜加算額（円） | 0.0 |
| スマート農業加算額 | decimal | △ | スマート農業加算額（円） | 14500 |
| 交付金額 | int | ○ | 交付金額合計（円） | 37700 |

### DBモデル（OfficialChusankanField）

| フィールド名 | データ型 | 説明 |
|-------------|---------|------|
| c_id | CharField(20), unique | 中山間ID |
| chusankan_flag | CharField(10), nullable | 中山間フラグ（〇等） |
| oaza | CharField(100) | 大字 |
| aza | CharField(100) | 字 |
| chiban | CharField(50) | 地番（文字列：イ、ロ等があるため） |
| branch_num | CharField(20), nullable | 枝番（-, 1, イ, ロ等） |
| land_type | CharField(20), nullable | 地目（田, 畑等） |
| area | IntegerField | 農地面積（m2） |
| planting_area | IntegerField, nullable | 植栽面積（m2） |
| original_crop | CharField(100), nullable | 作付け品目（役場記入の元データ） |
| manager | CharField(100), nullable | 協定管理者 |
| owner | CharField(100), nullable | 所有者 |
| slope | CharField(20), nullable | 傾斜度 |
| base_amount | IntegerField, nullable | 基本金額（円） |
| steep_slope_addition | DecimalField, nullable | 超急傾斜加算額（円） |
| smart_agri_addition | DecimalField, nullable | スマート農業加算額（円） |
| payment_amount | IntegerField, nullable | 交付金額（円） |

### データサンプル
```
ID  中山間  大字      字      地番   枝番  地目  農地面積  植栽面積  作付け品目  協定管理者  所有者     傾斜度  基本金額  交付金額
1   〇     口神ノ川  壱町切  1694    -    田    2900     2748     ニラ       神山倫子              1/29   23200   37700
2   〇     口神ノ川  大窪    490     1    田     652      490     野菜       谷脇誠一   谷脇史男   1/20   15204   18824
```

### 特記事項
- **全17列をDBに保存**: 将来どの列が必要になるかわからないため全保存
- **地番・枝番は文字列型**: 「イ」「ロ」などの非数値データが入る
- **作付け品目は参考情報**: 役場が記入した値。システムの作付け計画（Plan）とは別
- **面積の不整合は許容**: 共済マスタと同様、実圃場との差異は受け入れる

---

## 4. 作付け計画データ（システム内部）

### DBモデル（Plan）

| フィールド名 | データ型 | 必須 | 説明 |
|-------------|---------|-----|------|
| id | int (自動) | ○ | 主キー |
| field | FK → Field | ○ | 実圃場（外部キー） |
| year | IntegerField | ○ | 年度（2025など） |
| crop | FK → Crop, nullable | △ | 作物（外部キー） |
| variety | FK → Variety, nullable | △ | 品種（外部キー、NULLあり） |
| notes | TextField, nullable | △ | 備考 |

### 制約
- **ユニーク制約**: (field, year) - 1つの圃場に対して1年度につき1つの作付け計画のみ
  - Phase 2で二毛作対応する場合は、この制約を見直す

### 備考
- planting_date（播種日）、harvest_date（収穫日）は Phase 2 で追加予定
- crop, variety は外部キー（文字列ではなくリレーション）

---

## 5. 作物マスタ

### DBモデル（Crop）

| フィールド名 | データ型 | 説明 |
|-------------|---------|------|
| id | int (自動) | 主キー |
| name | CharField(50), unique | 作物名 |

### DBモデル（Variety）

| フィールド名 | データ型 | 説明 |
|-------------|---------|------|
| id | int (自動) | 主キー |
| crop | FK → Crop | 所属する作物 |
| name | CharField(100) | 品種名 |

**制約:** (crop, name) のペアで一意

### 作物・品種の管理方針
- 初期データは投入しない（管理画面またはUIから登録）
- すべての作物で品種選択UIは統一
- 「作付けしない」系も特別扱いしない（「その他」作物の品種として扱う）
- 品種の追加・削除は作付け計画画面から可能

---

## 6. データインポート仕様

### 初期セットアップ時

1. **共済マスタのインポート**
   - `水稲共済細目用.ods` を読み込み
   - `OfficialKyosaiField` テーブルに保存

2. **中山間マスタのインポート**
   - `中山間.ods` を読み込み
   - `OfficialChusankanField` テーブルに全17列を保存

3. **実圃場データのインポート**
   - `吉田農地台帳.ods` を読み込み
   - `Field` テーブルに保存
   - 同時に共済・中山間マスタとの紐付けを確立（ManyToMany）:
     - `細目_耕地番号` + `細目_分筆番号` → `OfficialKyosaiField` を検索して M:N 関連に追加
     - `中山間_ID` → `OfficialChusankanField` を検索して M:N 関連に追加

### 紐付けロジック

```python
# 共済マスタとの紐付け（M:N）
kyosai_record = OfficialKyosaiField.objects.get(
    k_num=row['細目_耕地番号'],
    s_num=row['細目_分筆番号']
)
field.kyosai_fields.add(kyosai_record)

# 中山間マスタとの紐付け（M:N）
if pd.notna(row['中山間_ID']):
    chusankan_record = OfficialChusankanField.objects.get(
        c_id=str(int(row['中山間_ID']))
    )
    field.chusankan_fields.add(chusankan_record)
```

---

## 7. 申請書PDF出力ロジック

### 水稲共済細目書

**出力形式:**
- A4サイズ、縦向き
- ヘッダー: 「水稲共済細目書（YYYY年度）」
- 表形式（罫線あり）、1行1区画（31行）
- フォントサイズ: 10pt
- ページ番号あり

**表の列:**

| 列名 | データ元 | 備考 |
|------|---------|------|
| 漢字地名 | OfficialKyosaiField.kanji_name | 例: 四万十町 笹ヶ谷 374-1 |
| 耕地-分筆 | k_num + "-" + s_num | 例: 2-1 |
| 本地面積 (m2) | OfficialKyosaiField.area | |
| 作付品目 | Plan.crop.name | システムの作付け計画から |
| 品種 | Plan.variety.name | 〃 |
| 圃場名称 | Field.name | 吉田農地台帳の名称 |

**集計ロジック:**
1. 共済マスタ（31区画）をループ
2. 各共済区画に紐づく実圃場を取得（M:N関係）
3. 紐づく実圃場の作付け情報を集約（作物名・品種名・圃場名をカンマ区切り）
4. HTMLテンプレートで表を生成 → WeasyPrint で PDF変換
5. 複数の実圃場が紐づく場合 → 作物・品種・圃場名をカンマ区切りで列挙
6. 作付け未設定の場合 → 「未設定」と表示

### 中山間交付金申請

**出力形式:**
- A4サイズ、横向き（列が多いため）
- ヘッダー: 「中山間地域等直接支払交付金（YYYY年度）」
- 表形式（罫線あり）、1行1区画（71行）
- ページ番号あり

**表の列:**

| 列名 | データ元 | 備考 |
|------|---------|------|
| 所在地 | 大字+字+地番+枝番 連結 | 例: 口神ノ川 壱町切 1694 |
| 植栽面積 | OfficialChusankanField.planting_area | m2 |
| 作付け品目(元) | OfficialChusankanField.original_crop | 役場記入の値 |
| 協定管理者 | OfficialChusankanField.manager | |
| 所有者 | OfficialChusankanField.owner | |
| 作物 | Plan.crop.name | システムの作付け計画から |
| 品種 | Plan.variety.name | 〃 |
| 圃場名称 | Field.name | 吉田農地台帳の名称 |

**集計ロジック:**
- 水稲共済と同様、中山間マスタをループして実圃場を集約 → HTMLテンプレート → PDF

---

## 8. データ移行・メンテナンス

### 年度更新
- **圃場マスタ**: 年度をまたいで共通（更新不要）
- **作付け計画**: 年度ごとに独立（前年度コピー機能で複製）

### マスタデータの更新
- **共済・中山間マスタ**: 役場から新しいファイルをもらった場合、再インポート
  - 既存データは上書きせず、差分を確認してマージ
  - または、全削除→再インポートの2段階処理

### バックアップ
- 全テーブルをCSV/Excelでエクスポート可能にする（サーバー移行時にも利用）
- 最低5年分のデータを保持（補助金監査対応）

---

## 9. 面積単位の扱い

システム内部では以下のように統一:

| 用途 | 単位 | DB型 | 変換式 |
|-----|------|------|--------|
| 実圃場の面積（DB保存） | 反 + m2 | DecimalField + IntegerField | 1反 = 1000m2 |
| 共済マスタの面積（DB保存） | m2 | IntegerField | - |
| 中山間マスタの面積（DB保存） | m2 | IntegerField | - |
| 画面表示 | 反 | - | area_m2 / 1000 |

**実装方針:**
- 実圃場: `area_tan`（DecimalField）と `area_m2`（IntegerField）の両方を保持
- 共済・中山間マスタ: `area` は m2（IntegerField）で保存
- 表示時は「反」に統一（1反 = 10a = 1000m2）
- 入力時は「反」で受け付け、内部で `m2` に変換

---

## 10. データ整合性チェック

### チェック項目

1. **紐付けの存在確認**
   - 実圃場の `細目_耕地番号`/`細目_分筆番号` が共済マスタに存在するか
   - 実圃場の `中山間_ID` が中山間マスタに存在するか

2. **面積の整合性（参考情報）**
   - 1つの共済区画に紐づく実圃場の合計面積と、共済マスタの面積を比較
   - ⚠️ 不整合があっても警告のみ（修正はしない）

3. **作付け未設定の検出**
   - 指定年度で作付け計画が未設定の圃場をリストアップ

### 実装
- インポート時にバリデーションを実行
- 管理画面で「データ整合性レポート」を表示
