Files
keinasystem/改善案/施肥散布実績連携変更実装仕様.md
Akira c9ae99ebc8 CODEX版
昨日運んだ肥料を散布してきました。
それで、今は施肥計画に「散布確定」ボタンがあるのですが、それだと実態に合わない事がわかりました。
実際には運搬計画を元に、運んだ肥料を散布します。
順序は、運搬計画の1回目2回目などの順序には関係がなく
運搬計画のすべての中から、全部または一部の圃場に対して散布します。
散布中に、運搬計画から実際の散布袋数が変更になる場合があるので、変更に対処できなければなりません。。散布は日付単位で行い、その日付を元に作業記録が自動的に作成されるようにしたいです。
運搬計画にも日付をつけたので、それも作業記録が自動的に作成されるようにしたいです。

以上のような感じで、変更実装仕様を作成してもらえますか?
2026-03-17 16:26:41 +09:00

18 KiB
Raw Blame History

施肥散布実績連携変更実装仕様

作成日: 2026-03-17 対象プロジェクト: keinasystem_t02 目的: 実運用に合わせて、施肥計画の「散布確定」中心設計を見直し、運搬計画起点の散布実績管理と日付ベースの作業記録自動生成へ移行する


1. 結論

今回の変更では、施肥実績の確定主体を FertilizationPlan から外し、以下の流れに再設計する。

  • 施肥計画は「計画」と「在庫引当」の責務に限定する
  • 運搬計画は「どの日に何をどこへ運んだか」の実績起点にする
  • 散布実績は、運搬済み肥料を元にした「日付単位の散布記録」で管理する
  • 作業記録は、運搬日・散布日から自動生成する
  • 在庫の USE は施肥計画の散布確定ではなく、散布実績の保存時に発生させる

つまり、業務フローは以下に変更する。

  1. 施肥計画を作る
  2. 運搬計画で肥料を運ぶ
  3. 運んだ肥料の全部または一部を、日付単位で散布する
  4. 運搬日・散布日をもとに作業記録を自動作成する

2. 背景と現状課題

現状実装では、FertilizationPlan に「散布確定」ボタンがあり、ここで実績数量を入力して在庫の RESERVE → USE を行っている。

しかし実運用では、以下のギャップがある。

  • 実際の散布は施肥計画から直接ではなく、運搬計画で現地へ運んだ肥料を元に行う
  • 散布時に参照するのは「1回目」「2回目」という順番ではなく、日付まで付いた運搬済み肥料全体である
  • 散布対象は運搬計画全体の中から「全部」または「一部の圃場」になる
  • 散布中に、運搬計画上の袋数から実際の散布袋数へ変更が入る
  • 作業記録は日付単位で残したい
  • 運搬計画にも日付が付いたため、運搬も作業記録として自動生成したい

そのため、「施肥計画で一括散布確定する」設計は実態に合わない。


3. 変更後の設計方針

3.1 責務分離

  • FertilizationPlan は計画データ
  • DeliveryPlan / DeliveryTrip / DeliveryTripItem は運搬計画と運搬実績
  • 新設する SpreadingSession 系は散布実績
  • 新設する WorkRecord 系は日付ベースの作業記録

3.2 日付中心設計

作業記録は「年度中心」ではなく「日付中心」で扱う。 年度は date から導出できる補助情報とし、画面の年フィルタや施肥計画との照合に使う。

3.3 散布元の考え方

散布元は「特定の運搬回の順番」ではなく、以下を満たす運搬済み明細の集合とする。

  • DeliveryTrip.date が入っている
  • まだ未散布残がある
  • 年度が一致する

つまり、散布画面では「その年度の運搬済み・未散布残あり」の明細を一覧化し、その中から対象圃場を選んで散布する。

3.4 差異の扱い

運搬数量と実散布数量が一致しないことは許容する。 ただし整合性のため、以下の扱いにする。

  • 実散布数量は運搬明細から初期値セットする
  • ユーザーは実散布数量を編集できる
  • 実散布数量が運搬済み残を超える場合は、そのまま黙って保存せず、差異として明示する
  • MVP では「運搬実績を先に修正してから再保存」を推奨フローとする

4. 機能スコープ

4.1 IN

  • 施肥計画一覧から「散布確定」ボタンを外す
  • 散布実績を日付単位で新設する
  • 散布実績は運搬済み明細を元に、全部または一部の圃場を対象に作成できる
  • 散布時に実績袋数を変更できる
  • 運搬日から作業記録を自動生成する
  • 散布日から作業記録を自動生成する
  • 在庫使用実績は散布実績保存時に作成する
  • 施肥計画一覧に「未散布 / 一部散布 / 完了」などの進捗状態を表示する

4.2 OUT

  • 肥料の置き場所管理
  • 残肥の返却・再入庫
  • ルート最適化
  • 複数人同時編集のロック制御
  • 汎用的な作業日誌機能の完成版 UI

5. 新しい業務フロー

5.1 施肥計画

  1. 施肥計画を作成・更新する
  2. 従来どおり RESERVE を張る
  3. ここでは散布確定しない

5.2 運搬計画

  1. 年度の施肥計画から運搬計画を作る
  2. DeliveryTrip に日付を入れる
  3. 日付が入った DeliveryTrip は「運搬実績あり」と見なす
  4. DeliveryTrip ごとに作業記録を自動生成する

5.3 散布実績

  1. ユーザーは散布日を選ぶ
  2. その年度の「運搬済みかつ未散布残あり」の明細を候補表示する
  3. 候補の中から、全部または一部の圃場を選ぶ
  4. 初期値として未散布残袋数を入れる
  5. 実際の散布袋数へ修正して保存する
  6. 保存時に USE 在庫履歴を散布日で作る
  7. 散布日の作業記録を自動生成する

6. 推奨データモデル変更

6.1 FertilizationPlan

現行の is_confirmed / confirmed_at は業務上の意味が薄くなるため、段階的に非推奨化する。

方針

  • DB カラムは互換性のため一旦残してよい
  • 新UIでは confirm_spreading / unconfirm を使わない
  • 一覧表示は以下の計算状態へ置き換える

追加する表示用状態

  • spread_status: unspread | partial | completed | over_applied
  • planned_total_bags
  • spread_total_bags
  • remaining_total_bags
  • spread_started_at
  • spread_completed_at

これらは serializer で計算する実装を推奨する。

6.2 DeliveryTripItem

現在は field + fertilizer + bags のみを持つが、散布実績との照合性を上げるため、内部参照を追加する。

追加推奨フィールド

  • fertilization_entry: FK(FertilizationEntry, null=True, on_delete=SET_NULL)

目的

  • どの施肥計画エントリ由来かを内部的に追跡する
  • 施肥計画進捗の自動集計をしやすくする
  • 将来の差異分析をしやすくする

※ UI 上は引き続き「年度横断で選ぶ」挙動のままでよい。

6.3 SpreadingSession(新規)

散布日単位の親レコード。

フィールド 制約 説明
id int PK
year int required 年度フィルタ用
date DateField required 散布日
name varchar(100) blank 任意名
notes text blank 備考
created_at / updated_at datetime auto

制約

  • MVP では unique_together = [['year', 'date']] を推奨

同日に複数の散布イベントを分けたい場合は、将来 sequence を追加して拡張する。

6.4 SpreadingSessionItem(新規)

散布日の圃場×肥料ごとの実績。

フィールド 制約 説明
id int PK
session FK(SpreadingSession) CASCADE
fertilization_entry FK(FertilizationEntry) SET_NULL, nullable 元施肥計画エントリ
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 / updated_at datetime auto

制約

  • unique_together = [['session', 'field', 'fertilizer']]

6.5 SpreadingAllocation(新規)

どの運搬明細残からどれだけ散布に充当したかを持つ中間テーブル。

フィールド 制約 説明
id int PK
spreading_item FK(SpreadingSessionItem) CASCADE
delivery_trip_item FK(DeliveryTripItem) PROTECT
allocated_bags Decimal(10,4) required 充当袋数

目的

  • 運搬順ではなく、運搬済み明細全体から散布したことを追跡する
  • どの運搬明細に未散布残がどれだけあるかを算出できる
  • 後から「どの便で運んだ肥料をいつ散布したか」を確認できる

6.6 WorkRecord(新規)

日付単位で自動生成される作業記録。

MVP では汎用化しすぎず、今回必要な 2 種類に絞る。

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

方針

  • 作業記録の明細は二重保持しない
  • 画面表示時は元の DeliveryTrip / SpreadingSession を参照して詳細を出す

7. 在庫連携の変更

7.1 変更前

  • 施肥計画保存時に RESERVE
  • 施肥計画の「散布確定」で USE

7.2 変更後

  • 施肥計画保存時に RESERVE を継続
  • 散布実績保存時に USE
  • USE.occurred_onSpreadingSession.date
  • RESERVE は引き続き FertilizationPlan に紐づける
  • USESpreadingSessionItem に紐づける

7.3 StockTransaction 追加推奨フィールド

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

備考

fertilization_plan だけでは「どの圃場・どの散布日で使ったか」が追えないため、散布実績由来の FK を追加する。


8. API 変更方針

8.1 施肥計画 API

廃止対象

  • POST /api/fertilizer/plans/{id}/confirm_spreading/
  • POST /api/fertilizer/plans/{id}/unconfirm/

即時削除ではなく、まずは UI から呼ばない状態にし、その後バックエンドも段階廃止する。

追加する読み取り項目

  • spread_status
  • planned_total_bags
  • spread_total_bags
  • remaining_total_bags
  • spread_started_at
  • spread_completed_at

8.2 運搬計画 API

既存の POST / PUT

DeliveryTrip.date の保存時に、対応する WorkRecord を upsert する。

詳細レスポンスへの追加推奨

  • DeliveryTripItemspread_bags
  • DeliveryTripItemremaining_bags
  • DeliveryTripwork_record_id

8.3 散布実績 API新規

メソッド 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}&date={date} 散布候補一覧

候補一覧レスポンスイメージ

[
  {
    "field": 5,
    "field_name": "田中上",
    "fertilizer": 1,
    "fertilizer_name": "電気炉さい",
    "planned_bags": "4.0000",
    "delivered_bags": "4.0000",
    "already_spread_bags": "1.5000",
    "remaining_bags": "2.5000",
    "source_trip_item_ids": [12, 18]
  }
]

散布作成リクエストイメージ

{
  "year": 2026,
  "date": "2026-03-17",
  "items": [
    {
      "field_id": 5,
      "fertilizer_id": 1,
      "actual_bags": "2.3000"
    },
    {
      "field_id": 6,
      "fertilizer_id": 1,
      "actual_bags": "1.0000"
    }
  ]
}

サーバー側の割当ルール

  • 同一 field + fertilizer の候補運搬明細に対して自動割当する
  • 割当順は trip.date asc, trip.id asc, item.id asc の固定順を推奨
  • UI では「何回目」ではなく「残量」を見せる

9. フロントエンド変更方針

9.1 施肥計画一覧 /fertilizer

変更点

  • 「散布確定」ボタンを廃止
  • ConfirmSpreadingModal.tsx は削除対象
  • 各計画カードに進捗状態を表示

表示例

  • 未散布
  • 一部散布 3.5 / 8.0袋
  • 散布完了
  • 計画超過

9.2 運搬計画編集 /distribution/new /distribution/[id]/edit

追加する変更

  • DeliveryTripItem.bags を画面上で直接編集できるようにする
  • 各明細に 残り未散布 を表示する
  • date 入力済みの回は「運搬実績あり」表示にする

理由

現状 UI では回の間の移動はできるが、袋数の直接編集ができない。 今回の業務に合わせるなら、運搬実績の修正も可能である必要がある。

9.3 散布実績画面(新規)

新規ページ例:

  • /fertilizer/spreading
  • または /distribution/spreading

画面要件

  • 日付を先に選ぶ
  • その年度の運搬済み未散布残を一覧表示
  • 圃場ごとにチェックして「今日散布する対象」を選べる
  • 初期袋数は残量を自動セット
  • 実績袋数は編集可能
  • 保存時に差異があればインライン警告を表示

UI イメージ

[散布日: 2026-03-17] [年度: 2026]

未散布残一覧
  田中上     電気炉さい     計画4.0   運搬残2.5   実績[2.3]
  田中下     電気炉さい     計画2.0   運搬残2.0   実績[2.0]

[保存]

9.4 作業記録画面(将来 UI

今回の実装では、まずは自動生成と API を優先する。 一覧 UI は最小限でもよいが、少なくとも以下を表示できる形にする。

  • 日付
  • 作業種別
  • タイトル
  • 元データへのリンク

10. 作業記録自動生成ルール

10.1 運搬

作成契機

  • DeliveryTrip.datenull → 日付あり になったとき
  • 既存レコード更新時に日付が変わったとき

作成内容

  • work_type = fertilizer_delivery
  • work_date = DeliveryTrip.date
  • title = 肥料運搬: {delivery_plan.name} {n}回目

更新・削除

  • 日付変更時は WorkRecord.work_date も更新
  • 日付を空に戻したら、自動生成レコードを削除

10.2 散布

作成契機

  • SpreadingSession の作成時
  • date 更新時

作成内容

  • work_type = fertilizer_spreading
  • work_date = SpreadingSession.date
  • title = 肥料散布: {date}

更新・削除

  • 日付変更時は upsert
  • SpreadingSession 削除時は対応 WorkRecord を削除

10.3 実装上の注意

自動生成は view 層に直接書かず、サービス層関数に切り出して idempotent に実装する。

推奨関数:

  • sync_delivery_work_record(trip)
  • sync_spreading_work_record(session)
  • delete_auto_work_record_for_delivery(trip)
  • delete_auto_work_record_for_spreading(session)

11. 移行方針

11.1 既存の確定済み施肥計画

既存の confirm_spreading 実装では、圃場別散布実績が永続化されていない。 StockTransaction には material 単位の USE は残るが、圃場別の再構成は正確にできない。

そのため、既存の確定済みデータは以下方針を推奨する。

  • 既存 USE 在庫履歴はそのまま残す
  • 既存 is_confirmed=True の計画は「旧方式確定済み」と見なす
  • SpreadingSession への自動変換はしない
  • 新方式の散布実績は、リリース後の新データから適用する

11.2 実装ステップ

  1. SpreadingSession / SpreadingSessionItem / SpreadingAllocation / WorkRecord を追加
  2. DeliveryTripItem.fertilization_entryStockTransaction.spreading_item を追加
  3. 散布実績 API を追加
  4. 運搬日と散布日の作業記録同期を追加
  5. フロントで「散布確定」ボタンを撤去
  6. 散布実績画面を追加
  7. confirm_spreading を非表示化
  8. 十分移行後に旧 API を削除

12. 影響ファイル(想定)

Backend

  • backend/apps/fertilizer/models.py
  • backend/apps/fertilizer/serializers.py
  • backend/apps/fertilizer/views.py
  • backend/apps/fertilizer/urls.py
  • backend/apps/fertilizer/admin.py
  • backend/apps/fertilizer/migrations/
  • backend/apps/materials/models.py
  • backend/apps/materials/stock_service.py
  • backend/apps/materials/serializers.py
  • backend/apps/materials/migrations/
  • backend/apps/workrecords/ または同等の新規 app

Frontend

  • frontend/src/app/fertilizer/page.tsx
  • frontend/src/app/fertilizer/_components/ConfirmSpreadingModal.tsx
  • frontend/src/app/distribution/_components/DeliveryEditPage.tsx
  • frontend/src/types/index.ts
  • 散布実績の新規ページ群
  • 作業記録の新規ページ群または既存画面への表示追加

ドキュメント

  • document/13_マスタードキュメント_施肥計画編.md
  • document/14_マスタードキュメント_分配計画編.md
  • CLAUDE.md

※ これらは実装着手時に正式仕様へ反映する。


13. 受け入れ条件

  • 施肥計画一覧に「散布確定」ボタンが表示されない
  • 運搬済み明細を元に、日付単位の散布実績を新規作成できる
  • 散布対象は、運搬計画全体から全部または一部の圃場を選べる
  • 運搬回の順番に依存せず散布できる
  • 散布時に実際袋数を変更できる
  • 散布保存時に USE 在庫履歴が散布日で作成される
  • DeliveryTrip.date 保存時に運搬作業記録が自動生成される
  • SpreadingSession.date 保存時に散布作業記録が自動生成される
  • 施肥計画一覧で未散布・一部散布・完了が分かる

14. 前提と留意点

  • 本仕様では「残肥の返却」は扱わない。未散布残は運搬済み残として次回散布へ繰り越す
  • 同日複数散布の厳密な分離は MVP では不要とみなし、まずは 1日1レコードを採用する
  • 既存確定済みデータの完全移行は行わない
  • 作業記録 UI は最小構成でよいが、API と自動生成ロジックは今回入れる