Files
keinasystem/document/13_マスタードキュメント_施肥計画編.md
Akira 13c21ed7de ローカル更新済み:
13_マスタードキュメント_施肥計画編.md — 散布実績セクション整備、在庫連携・集計ルール・WorkRecord自動生成・前年度コピーのセクション追加、旧「散布確定モーダル」記述削除、型定義・ファイル構成・将来の拡張を更新
14_マスタードキュメント_分配計画編.md — 散布実績との連携・WorkRecord自動生成のセクション追加
CLAUDE.md — データモデル(SpreadingSession/Item, WorkRecord, actual_bags)追加、プロジェクト構造にfertilizer/workrecordsアプリ追加、実装状況に散布実績・作業記録索引を追記、更新履歴に2026-03-17エントリ追加
2026-03-17 20:31:22 +09:00

26 KiB
Raw Permalink Blame History

マスタードキュメント:施肥計画機能

作成: 2026-03-01 最終更新: 2026-03-17 対象機能: 施肥計画(年度×品種単位のマトリクス管理・在庫引当・散布実績記録) 実装状況: 実装完了・本番稼働中(散布実績連携追加)


概要

農業生産者が「年度 × 品種」単位で施肥計画を立てる機能。 複数圃場 × 複数肥料 × 袋数をマトリクス形式で管理し、PDF出力・在庫引当・散布実績記録・作業記録索引生成まで一連で扱う。

機能スコープIN / OUT

IN実装済み OUT対象外
肥料マスタ管理 肥料購入管理
施肥計画の作成・編集・削除 運搬計画(→ 14_マスタードキュメント_分配計画編.md 参照)
3方式の自動計算 運搬便ごとの散布充当追跡
作付け計画からの圃場自動取得 相手先ごとのPDF様式実装
PDF出力圃場×肥料マトリクス表 残肥返却・再入庫管理
在庫引当・引当解除
散布実績記録(日付単位・運搬済み肥料ベース)
作業記録索引WorkRecord自動生成
在庫USE連携散布実績保存時
施肥計画進捗表示(未散布/一部散布/完了/計画超過)

データモデル

Fertilizer肥料マスタ

フィールド 制約 説明
id int PK
name varchar(100) unique, required 肥料名
maker varchar(100) nullable メーカー
capacity_kg decimal(8,3) nullable 1袋重量(kg) ← nitrogen計算に必須
nitrogen_pct decimal(5,2) nullable 窒素含有率(%) ← nitrogen計算に必須
phosphorus_pct decimal(5,2) nullable リン酸含有率(%)
potassium_pct decimal(5,2) nullable カリ含有率(%)
notes text nullable 備考

FertilizationPlan施肥計画

フィールド 制約 説明
id int PK
name varchar(200) required 計画名(ユーザーが自由入力)
year int required 年度
variety FK(plans.Variety) PROTECT 品種≠NULL
is_confirmed bool default=False 散布確定済みフラグdeprecated: 新UIでは使用しない
confirmed_at datetime nullable 散布確定日時deprecated: 新UIでは使用しない
created_at datetime auto
updated_at datetime auto

表示用計算項目APIレスポンスに含まれる

項目 説明
spread_status string unspread / partial / completed / over_applied
planned_total_bags decimal 計画袋数合計全entries.bagsの合計
spread_total_bags decimal 散布済み袋数合計全entries.actual_bagsの合計
remaining_total_bags decimal 残袋数planned_total_bags - spread_total_bags

FertilizationEntry施肥エントリ圃場×肥料×袋数

フィールド 制約 説明
id int PK
plan FK(FertilizationPlan) CASCADE
field FK(fields.Field) CASCADE
fertilizer FK(Fertilizer) PROTECT 施肥計画で使用中の肥料は削除不可
bags decimal(8,2) required 袋数(計画値)
actual_bags decimal(10,4) nullable 散布実績集計値SpreadingSessionItemから自動集計
  • unique_together = ['plan', 'field', 'fertilizer']
  • 順序: field__display_order, field__id, fertilizer__name

SpreadingSession散布実績セッション

フィールド 制約 説明
id int PK
year int required 年度フィルタ用
date DateField required 散布日
name varchar(100) required セッション名(必須)
notes text blank 備考
created_at datetime auto
updated_at datetime auto
  • year + date の一意制約は付けない(同日に午前・午後やエリア別で複数記録可能)

SpreadingSessionItem散布実績明細

フィールド 制約 説明
id int PK
session FK(SpreadingSession) CASCADE
field FK(fields.Field) PROTECT
fertilizer FK(Fertilizer) PROTECT
actual_bags decimal(10,4) required 実散布袋数
planned_bags_snapshot decimal(10,4) required 表示時点の計画値
delivered_bags_snapshot decimal(10,4) required 表示時点の運搬済み合計
created_at datetime auto
updated_at datetime auto
  • unique_together = ['session', 'field', 'fertilizer']

WorkRecord作業記録索引

別アプリ apps/workrecords/ で管理。施肥・運搬の作業を日付順に一覧するための索引テーブル。 詳細の本体は各業務テーブル側DeliveryTrip / SpreadingSessionに持つ。

フィールド 制約 説明
id int PK
work_date DateField required 作業日
work_type varchar required fertilizer_delivery / fertilizer_spreading
title varchar(200) required 一覧表示名
year int required 年度フィルタ補助
auto_created bool default=True 自動生成フラグ
delivery_trip OneToOne FK(DeliveryTrip) nullable 運搬由来
spreading_session OneToOne FK(SpreadingSession) nullable 散布由来
created_at datetime auto
updated_at datetime auto

API エンドポイント

すべて JWT 認証(Authorization: Bearer <token>)が必要。

肥料マスタ

メソッド URL 説明
GET /api/fertilizer/fertilizers/ 一覧取得
POST /api/fertilizer/fertilizers/ 新規作成
GET /api/fertilizer/fertilizers/{id}/ 詳細取得
PUT/PATCH /api/fertilizer/fertilizers/{id}/ 更新
DELETE /api/fertilizer/fertilizers/{id}/ 削除

レスポンス例Fertilizer:

{
  "id": 1,
  "name": "コシヒカリ専用一発肥料",
  "maker": "JA",
  "capacity_kg": "20.000",
  "nitrogen_pct": "14.00",
  "phosphorus_pct": "12.00",
  "potassium_pct": "12.00",
  "notes": null
}

施肥計画

メソッド URL 説明
GET /api/fertilizer/plans/?year={year} 年度別一覧
POST /api/fertilizer/plans/ 新規作成entries 含む)
GET /api/fertilizer/plans/{id}/ 詳細取得entries 含む)
PUT /api/fertilizer/plans/{id}/ 更新entries 全置換)
DELETE /api/fertilizer/plans/{id}/ 削除
POST /api/fertilizer/plans/{id}/confirm_spreading/ 散布確定deprecated: UI上で廃止、バックエンドは互換維持
POST /api/fertilizer/plans/{id}/unconfirm/ 散布確定取消deprecated: UI上で廃止、バックエンドは互換維持
GET /api/fertilizer/plans/{id}/pdf/ PDF出力application/pdf

一覧レスポンス例FertilizationPlan:

{
  "id": 1,
  "name": "2025年コシヒカリ施肥計画",
  "year": 2025,
  "variety": 3,
  "variety_name": "コシヒカリ",
  "crop_name": "米",
  "is_confirmed": false,
  "confirmed_at": null,
  "field_count": 12,
  "fertilizer_count": 2,
  "entries": [
    {
      "id": 1,
      "field": 5,
      "field_name": "田中上",
      "field_area_tan": "1.2000",
      "fertilizer": 1,
      "fertilizer_name": "コシヒカリ専用一発肥料",
      "bags": "2.40"
    }
  ],
  "created_at": "2025-03-01T10:00:00Z",
  "updated_at": "2025-03-01T10:00:00Z"
}

POST/PUT リクエスト例:

{
  "name": "2025年コシヒカリ施肥計画",
  "year": 2025,
  "variety": 3,
  "entries": [
    {"field_id": 5, "fertilizer_id": 1, "bags": 2.4},
    {"field_id": 6, "fertilizer_id": 1, "bags": 1.6}
  ]
}

PUT 時は entries が全置換削除→再作成。entries を省略した場合は既存を維持。

散布実績(新規)

メソッド URL 説明
GET /api/fertilizer/spreading/?year={year} 年度別一覧
POST /api/fertilizer/spreading/ 新規作成
GET /api/fertilizer/spreading/{id}/ 詳細
PUT /api/fertilizer/spreading/{id}/ 更新
DELETE /api/fertilizer/spreading/{id}/ 削除
GET /api/fertilizer/spreading/candidates/?year={year} 散布候補一覧

散布候補一覧レスポンス例:

[
  {
    "field": 5,
    "field_name": "田中上",
    "fertilizer": 1,
    "fertilizer_name": "電気炉さい",
    "planned_bags": "4.0000",
    "delivered_bags": "4.0000",
    "spread_bags": "1.5000",
    "remaining_bags": "2.5000",
    "remaining_plan_bags": "2.5000",
    "delivery_gap": "0.0000"
  }
]

散布実績 POST リクエスト例:

{
  "year": 2026,
  "date": "2026-04-15",
  "name": "午前・田中エリア",
  "notes": "",
  "items": [
    {
      "field": 5,
      "fertilizer": 1,
      "actual_bags": "2.5000",
      "planned_bags_snapshot": "4.0000",
      "delivered_bags_snapshot": "4.0000"
    }
  ]
}

作業記録(新規・別アプリ)

メソッド URL 説明
GET /api/workrecords/?year={year} 一覧
GET /api/workrecords/{id}/ 詳細(元レコードへのリンク情報を返す)

圃場候補取得

GET /api/fertilizer/candidate_fields/?year={year}&variety_id={variety_id}

作付け計画Planモデルから year + variety で圃場を検索して返す。

レスポンス例:

[
  {"id": 5, "name": "田中上", "area_tan": "1.2000", "area_m2": 1200, "group_name": "田中"},
  {"id": 6, "name": "田中下", "area_tan": "0.8000", "area_m2": 800, "group_name": "田中"}
]

自動計算

POST /api/fertilizer/calculate/

計算結果を返すのみDB保存なし

方式 1: per_tan反当袋数

{
  "method": "per_tan",
  "param": 2.0,
  "field_ids": [5, 6]
}

計算式: bags = Sa × ASa: 反当袋数, A: 圃場面積[反]

方式 2: even均等配分

{
  "method": "even",
  "param": 50,
  "field_ids": [5, 6]
}

計算式: bags = (SS / ΣA) × ASS: 総袋数, A: 圃場面積[反]

方式 3: nitrogen反当チッソ成分量

{
  "method": "nitrogen",
  "param": 3.0,
  "fertilizer_id": 1,
  "field_ids": [5, 6]
}

計算式: bags = (Nr / (C × Nd/100)) × A

  • Nr: 反当チッソ成分量(kg/反)
  • C: 1袋重量(kg) ← Fertilizer.capacity_kg 必須
  • Nd: 窒素含有率(%) ← Fertilizer.nitrogen_pct 必須
  • A: 圃場面積[反]

nitrogen 方式は capacity_kg・nitrogen_pct が未設定の肥料に対してはエラー400

レスポンス(共通):

[
  {"field_id": 5, "bags": 2.40},
  {"field_id": 6, "bags": 1.60}
]

品種・作物の取得

品種一覧は既存の plans アプリの CropViewSet を使用:

GET /api/plans/crops/

レスポンス例:

[
  {
    "id": 1,
    "name": "米",
    "base_temp": "0.0",
    "varieties": [
      {"id": 1, "name": "コシヒカリ", "crop": 1},
      {"id": 2, "name": "ヒノヒカリ", "crop": 1}
    ]
  }
]

注意: plans アプリの DefaultRouter が r'' に登録されているため、 /api/plans/get-crops-with-varieties/ のようなカスタムパスは 404 になるURLルーティング競合/api/plans/crops/ を使うこと。


PDF 出力

GET /api/fertilizer/plans/{id}/pdf/

  • WeasyPrint を使用reports アプリと同パターン)
  • テンプレート: backend/apps/fertilizer/templates/fertilizer/pdf.html
  • フォーマット: A4横向き
  • 内容: 圃場(行)× 肥料(列)のマトリクス表、行合計・列合計・総合計
  • ファイル名: fertilization_{year}_{plan_id}.pdf

フロントエンド画面

施肥計画一覧(/fertilizer

  • 年度セレクタlocalStorage fertilizerYear で保持)
  • 計画カード一覧: 計画名・作物/品種・圃場数・肥料数・散布進捗
  • 操作ボタン: PDF出力・編集・削除
  • ヘッダー: 「肥料マスタ」「新規作成」ボタン
  • 進捗表示: 未散布 / 一部散布 3.5 / 8.0袋 / 散布完了 / 計画超過
  • 計画値と実績値を並べて表示

肥料マスタ(/fertilizer/masters

  • 肥料一覧テーブル(名前・メーカー・容量・窒素・リン酸・カリ・備考)
  • インライン行編集EditRow コンポーネント)
  • 新規追加フォーム
  • 削除ボタン押下で即削除を試みるconfirm ダイアログなし)
  • 施肥計画で使用中の場合は PROTECT によりバックエンドが 500 を返し、赤いインラインバナーで理由を表示

施肥計画編集(/fertilizer/new / /fertilizer/[id]/edit

FertilizerEditPage.tsxfertilizer/_components/)を共有コンポーネントとして使用。

操作フロー

  1. 計画基本情報入力: 計画名・年度・品種(ドロップダウン)
  2. 圃場選択: 品種選択後に候補圃場が自動取得(candidate_fields API。チップ形式で追加/解除。候補外の圃場は「全圃場から追加」で手動選択
  3. 肥料追加: 「+肥料を追加」で肥料マスタからドロップダウン選択
  4. 自動計算: 各肥料に方式per_tan/even/nitrogenとパラメータを設定し「計算」ボタンでマトリクスに反映上書き確認あり
  5. 四捨五入: 肥料列ヘッダーの ボタン(青)を押すと袋数を整数に丸める。押した後は ボタン(琥珀色)に変わり、押すと元の計算値に戻る
  6. 手動調整: マトリクス表のセルを直接編集
  7. 保存: 「保存」ボタンで entries を一括送信

在庫連携・実績表示

  • 肥料列ヘッダーに在庫 / 利用可能在庫 / 計画計 / 不足数を表示
  • マトリクス表で bags(計画値)を編集可能、actual_bags(実績値)は読み取り専用で参照表示
  • 散布実績画面(/fertilizer/spreading)へのリンクを表示

マトリクスの表示仕様

  • 自動計算直後: セルに計算値(小数)がそのまま表示される(編集可)
  • ボタン押下後: セルの入力値が整数に丸められ、元の計算値が薄いグレーで参照表示される
  • ボタン押下: 整数値を破棄し、元の計算値に戻る(参照グレー表示も消える)
  • 編集中に計算を再実行すると、その肥料列の adjustedroundedColumns がリセットされる

散布実績画面(/fertilizer/spreading

  • 年度セレクタlocalStorage fertilizerYear と連動)
  • 散布日入力DateField
  • セッション名入力(必須)
  • 運搬済み・未散布候補一覧を表示(candidates APIから取得
  • 圃場単位で選択可能(全部または一部)
  • 実績袋数の編集
  • 差異がある場合はインライン警告表示
  • 保存時に在庫USE連携・WorkRecord自動生成・FertilizationEntry.actual_bags再集計を実行

作業記録画面(/workrecords

  • 年度セレクタ
  • 日付・作業種別・タイトルの一覧表示
  • 元データ(運搬回 / 散布セッション)への遷移リンク

State 構成(施肥計画編集画面)

// 基本情報
const [name, setName] = useState('')
const [year, setYear] = useState(currentYear)
const [varietyId, setVarietyId] = useState<number | ''>('')

// 圃場・肥料
const [selectedFields, setSelectedFields] = useState<Field[]>([])
const [planFertilizers, setPlanFertilizers] = useState<Fertilizer[]>([])

// 自動計算設定(肥料ごと)
const [calcSettings, setCalcSettings] = useState<CalcSetting[]>([])
// CalcSetting: { fertilizer_id, method: 'per_tan'|'even'|'nitrogen', param: string }

// マトリクス 2層構成fieldId → fertilizerId → 袋数文字列)
const [calcMatrix, setCalcMatrix] = useState<Matrix>({})   // 自動計算値(参照用・変更不可表示)
const [adjusted, setAdjusted] = useState<Matrix>({})       // ユーザー確定値(保存対象)
const [roundedColumns, setRoundedColumns] = useState<Set<number>>(new Set())  // ↩ トグル管理

// effectiveValue(fieldId, fertId) で保存値を決定:
//   adjusted[field][fert] があればそれを優先、なければ calcMatrix[field][fert]

ファイル構成

Backend

backend/apps/fertilizer/
├── __init__.py
├── admin.py                   # Django admin 登録
├── apps.py                    # FertilizerConfig
├── models.py                  # Fertilizer, FertilizationPlan, FertilizationEntry, SpreadingSession, SpreadingSessionItem
├── serializers.py             # FertilizerSerializer, FertilizationPlanSerializer/WriteSerializer, SpreadingSessionSerializer
├── services.py                # actual_bags再集計、WorkRecord自動生成、在庫USE連携
├── views.py                   # FertilizerViewSet, FertilizationPlanViewSet, SpreadingSessionViewSet, CandidateFieldsView, CalculateView
├── urls.py                    # DefaultRouter + candidate_fields/ + calculate/ + spreading/
├── migrations/
│   ├── 0001_initial.py
│   ├── 0002_alter_fertilizationentry_fertilizer.py  # CASCADE → PROTECT
│   └── ...                    # SpreadingSession, SpreadingSessionItem, actual_bags 追加
└── templates/
    └── fertilizer/
        └── pdf.html           # WeasyPrint テンプレートA4横向き

Frontend

frontend/src/app/fertilizer/
├── page.tsx                   # 施肥計画一覧
├── new/
│   └── page.tsx               # 新規作成FertilizerEditPage をラップ)
├── [id]/
│   └── edit/
│       └── page.tsx           # 編集FertilizerEditPage をラップ)
├── masters/
│   └── page.tsx               # 肥料マスタ管理
├── spreading/
│   └── ...                    # 散布実績画面(一覧・作成・編集)
└── _components/
    └── FertilizerEditPage.tsx  # 新規/編集共通コンポーネント(複雑)

frontend/src/app/workrecords/
└── ...                        # 作業記録画面(一覧・詳細)

変更されたファイル

ファイル 変更内容
backend/keinasystem/settings.py INSTALLED_APPS'apps.fertilizer', 'apps.workrecords' を追加
backend/keinasystem/urls.py api/fertilizer/, api/workrecords/ を追加
backend/apps/materials/models.py StockTransaction.spreading_item FK 追加(on_delete=SET_NULL
backend/apps/workrecords/ 作業記録索引アプリWorkRecord モデル・API・services
frontend/src/types/index.ts 施肥・散布・作業記録の型を追加
frontend/src/components/Navbar.tsx Sprout アイコン + 施肥計画メニューを追加

在庫連携

RESERVE施肥計画保存時

  • 従来どおり計画値 bags ベースで維持
  • 施肥計画の entries 保存時に RESERVE トランザクションを作成

USE散布実績保存時

  • SpreadingSessionItem ごとに USE を1件作成
  • material: item.fertilizer.material
  • quantity: actual_bags
  • occurred_on: session.date
  • note: 散布実績「{session.name or session.date}」

StockTransaction 追加フィールド

  • spreading_item = FK(SpreadingSessionItem, null=True, blank=True, on_delete=SET_NULL)

更新・削除

  • 散布実績更新時: その session に紐づく USE を全置換で作り直す
  • 散布実績削除時: 対応 USE を削除する

RESERVE と USE の整合

  • RESERVE は計画値 bags ベース
  • USE は散布実績 actual_bags ベース
  • 計画値と実績値は併存する

集計ルール

planned_total圃場×肥料×年度

FertilizationEntry.bags の合計

delivered_total圃場×肥料×年度

DeliveryTrip.date != nullDeliveryTripItem.bags 合計

spread_total圃場×肥料×年度

SpreadingSessionItem.actual_bags の合計

actual_bags 再集計ルール

  • SUM(SpreadingSessionItem.actual_bags) を同一 year, field, fertilizer で集計
  • 散布実績の保存・更新・削除時に該当する FertilizationEntry.actual_bags を即時再計算
  • SUM(...) = 0 の場合は actual_bags = null

remaining_bags表示用の残量

delivered_total - spread_total

remaining_plan_bags計画進捗用の残量

planned_total - spread_total

差異の扱い

  • remaining_bags < 0: 運搬実績不足
  • remaining_plan_bags < 0: 計画超過
  • 圃場+肥料単位で差異が分かることを優先する

WorkRecord 自動生成ルール

運搬fertilizer_delivery

  • DeliveryTrip.date 保存時に upsert
  • title = 肥料運搬: {delivery_plan.name} {n}回目
  • 日付削除時は対応 WorkRecord を削除

散布fertilizer_spreading

  • SpreadingSession 保存時に upsert
  • title = 肥料散布: {session.name or session.date}
  • 削除時は対応 WorkRecord を削除

実装方針

自動生成は view に直書きせず、サービス層(services.py)で idempotent に実装する。


前年度コピー

copy_from_previous_year で前年度の FertilizationEntry をコピーする際のルール:

  • actual_bags がある場合: actual_bags を新年度の bags 初期値として使用
  • actual_bagsnull の場合: 従来どおり bags をコピー

前年度に実際に散布した量を次年度計画の初期値として再利用できる。


型定義TypeScript

// frontend/src/types/index.ts主要な型のみ抜粋

export interface Fertilizer {
  id: number;
  name: string;
  maker: string | null;
  capacity_kg: string | null;
  nitrogen_pct: string | null;
  phosphorus_pct: string | null;
  potassium_pct: string | null;
  notes: string | null;
}

export interface FertilizationEntry {
  id: number;
  field: number;
  field_name: string;
  field_area_tan: string;
  fertilizer: number;
  fertilizer_name: string;
  bags: string;
  actual_bags: string | null;  // 散布実績集計値
}

export interface FertilizationPlan {
  id: number;
  name: string;
  year: number;
  variety: number;
  variety_name: string;
  crop_name: string;
  field_count: number;
  fertilizer_count: number;
  entries: FertilizationEntry[];
  spread_status: 'unspread' | 'partial' | 'completed' | 'over_applied';
  planned_total_bags: string;
  spread_total_bags: string;
  remaining_total_bags: string;
}

注意点・既知の問題

エラー表示方針confirm/alert を使わない)

ブラウザが alert() / confirm() をブロックすると操作が無音で失敗する問題を受けて、 施肥機能全体で alert/confirm を廃止し、React インラインバナーに統一した。

  • 保存失敗: saveError state → ヘッダー直下に赤いバナー(✕で閉じられる)
  • 肥料削除失敗: deleteError state → テーブル上部に赤いバナー
  • 計画削除失敗: deleteError state → 一覧上部に赤いバナー
  • 肥料列の除去: ローカルstate操作のみ失敗しない

URL ルーティング競合(解決済み)

plans アプリの DefaultRouter(r'', PlanViewSet)plans/get-crops-with-varieties/{pk}/ パターンとして解釈して 404 になる問題があった。 /api/plans/crops/CropViewSetを使うことで回避。

nitrogen 計算の前提条件

反当チッソ成分量方式nitrogenは、指定した肥料に capacity_kgnitrogen_pct が 両方登録されていないと 400 エラーになる。肥料マスタ登録時にユーザーへ案内が必要。

袋数の精度

袋数は decimal(8,2)小数点以下2桁。0.01 刻みで四捨五入。 自動計算も Decimal.quantize(Decimal('0.01')) で丸める。

entries の更新方式

PUT 時は entries を全削除→再作成する「全置換」方式。 部分更新は非対応PATCH でも entries がある場合は全置換)。

散布実績の在庫連携

  • 施肥計画保存時: RESERVE(計画値 bags ベース)
  • 散布実績保存時: USE(実績値 actual_bags ベース)
  • RESERVEUSE は併存する(計画値と実績値は別管理)
  • 散布実績更新時は session に紐づく USE を全置換で作り直す
  • 散布実績削除時は対応 USE を削除する(StockTransaction.spreading_itemSET_NULL
  • perform_destroy で明示的に StockTransaction を削除してから session.delete() を呼ぶ

散布セッション名は必須

SpreadingSession.name は必須フィールド。WorkRecord のタイトル生成や一覧表示に使用するため、 空文字での保存は許可しない。

useSearchParams と SuspenseNext.js 14

散布実績画面(/fertilizer/spreading)では useSearchParams() を使用するため、 Suspense boundary でラップする必要がある(本番ビルドで必須)。

Next.js ホットリロードが効かない問題Windows + Docker

Windows 環境では Docker ボリュームマウント経由のファイル変更が inotify で検知されず、 フロントエンドのホットリロードが動かない。

対策: docker-compose.yml の frontend 環境変数に WATCHPACK_POLLING: "true" を追加。 ポーリング方式に切り替えることでファイル変更を検知できるようになる。


将来の拡張(スコープ外)

  • 相手先別PDF様式: 客先ごとの提出資料フォーマット(元データは散布実績から取得可能)
  • 残肥返却・再入庫管理: 散布後の残りを在庫に戻す処理
  • SpreadingAllocation: 運搬便単位の散布充当追跡(現状は集計ベースで十分)
  • 購入管理: 肥料の購入・在庫管理(施肥計画の集計から購入数量を自動算出)
  • 配置計画: 複数圃場分を一か所にまとめる時の置き場所割り当て(別機能として検討)