作成: 2026-04-04
最終更新: 2026-05-15
対象機能: トラクター作業記録(畔塗・荒代掻き・植代掻き・耕耘)
実装状況: 畔塗のみ実装済み。荒代掻き・植代掻き・耕耘は設計中(Issue #21)
対象 Issue:akira/keinasystem#21
農業生産者が、水稲作付け圃場に対して実施したトラクター作業を日付単位で記録する機能。
対象圃場をまとめて選択し、保存時に作業記録一覧へ自動反映する。
対象作業種別:
| 種別 | 日本語名 | 説明 |
|---|---|---|
levee_work |
畔塗 | 畦畔の補修・造成 |
rough_harrowing |
荒代掻き | 田植え前の粗い代掻き |
transplant_harrowing |
植代掻き | 田植え直前の仕上げ代掻き |
cultivation |
耕耘 | 土起こし・耕起 |
これらはいずれもトラクターを用いた資材なし作業であり、同一のデータモデルで管理する。
本機能は、施肥計画の散布実績と同様に
「作業本体を専用テーブルで持ち、作業記録一覧には索引を自動生成する」
という設計方針を採用する。
| IN(本機能で扱う) | OUT(本機能では扱わない) |
|---|---|
| 日付単位の作業記録作成(全4種別) | 作業の工程管理 |
| 水稲作付け圃場の候補抽出 | 作業者別の工数集計 |
| 複数圃場の一括選択・保存 | 機械・資材の在庫管理 |
| 作業記録一覧(WorkRecord)への自動反映 | 写真添付 |
| 記録の編集・削除 | GPS軌跡連携 |
| 対象圃場一覧の参照画面 | 汎用作業日誌への完全統合 |
現状システムには畔塗の記録機能があるが、同じトラクター作業である荒代掻き・植代掻き・耕耘は登録できない。
これらは以下の共通点を持つため、統一モデルで管理する。
日付単位のトラクター作業記録。
| フィールド | 型 | 制約 | 説明 |
|---|---|---|---|
| id | int | PK | |
| work_type | varchar(30) | required | 作業種別(下記参照) |
| year | int | required | 年度フィルタ用。原則 date.year と一致させる |
| date | DateField | required | 作業日 |
| title | varchar(100) | required | 一覧表示タイトル。未指定時はサーバー側で work_type に応じたデフォルト値を補完する |
| notes | text | blank | 備考 |
| created_at | datetime | auto | |
| updated_at | datetime | auto |
| work_type | 表示名 | デフォルトタイトル |
|---|---|---|
levee_work |
畔塗 | 水稲畔塗 |
rough_harrowing |
荒代掻き | 水稲荒代掻き |
transplant_harrowing |
植代掻き | 水稲植代掻き |
cultivation |
耕耘 | 水稲耕耘 |
year + date の一意制約は付けないトラクター作業記録に紐づく対象圃場一覧。
| フィールド | 型 | 制約 | 説明 |
|---|---|---|---|
| id | int | PK | |
| session | FK(TractorWorkSession) | CASCADE | 親の作業記録 |
| field | FK(fields.Field) | PROTECT | 対象圃場 |
| plan | FK(plans.Plan) | SET_NULL, nullable | 保存時点の作付け計画参照 |
| crop_name_snapshot | varchar(100) | required | 保存時点の作物名 |
| variety_name_snapshot | varchar(100) | blank | 保存時点の品種名 |
| created_at | datetime | auto | |
| updated_at | datetime | auto |
unique_together = ['session', 'field']Field を参照して表示する既存 apps/workrecords の WorkRecord をトラクター作業に対応させる。
| 変更点 | 内容 |
|---|---|
work_type enum |
TRACTOR_WORK = 'tractor_work' を追加(LEVEE_WORK を置換) |
| FK | tractor_work_session = OneToOneField('tractor_work.TractorWorkSession', ...) に改名 |
制約:
on_delete=CASCADEnull=True, blank=Truerelated_name='work_record'一覧表示時の想定値:
| 項目 | 値 |
|---|---|
| 作業日 | 作業記録の日付 |
| 種別 | トラクター作業(work_type の日本語表示) |
| タイトル | session.title |
| 参照先 | 対象圃場一覧画面 |
候補は作付け計画 Plan から抽出する。
Plan であることcrop.name = "水稲" の圃場であることcrop=水稲 なら候補に含めるfield.display_order, field.id| 項目 | 説明 |
|---|---|
| field_id | 圃場ID |
| field_name | 圃場名 |
| field_area_tan | 面積(反) |
| group_name | グループ名 |
| plan_id | 対応する作付け計画ID |
| crop_name | 作物名 |
| variety_name | 品種名 |
| selected | 初期選択状態(原則 true) |
日付と作業種別を先に決めて対象圃場を選ぶ「日報型UI」。
1回の保存で複数圃場をまとめて記録する。
/tractor-work)表示項目: 作業日 / 作業種別 / タイトル / 対象圃場数 / 面積合計 / 備考
入力項目:
トラクター作業記録作成
[作業種別 荒代掻き ▼]
[日付 2026-04-20]
[タイトル 水稲荒代掻き]
[備考 __________________ ]
対象圃場一覧
[全選択] [全解除]
☑ 田中上 1.2反 上エリア コシヒカリ
☑ 田中下 0.8反 上エリア あきたこまち
☐ 山の前 1.5反 南エリア (未設定)
[保存]
すべて JWT 認証必須。
| メソッド | URL | 説明 |
|---|---|---|
| GET | /api/tractor-work/sessions/?year={year} |
年度別一覧 |
| POST | /api/tractor-work/sessions/ |
新規作成 |
| GET | /api/tractor-work/sessions/{id}/ |
詳細取得 |
| PUT/PATCH | /api/tractor-work/sessions/{id}/ |
更新 |
| DELETE | /api/tractor-work/sessions/{id}/ |
削除 |
| メソッド | URL | 説明 |
|---|---|---|
| GET | /api/tractor-work/candidates/?year={year} |
水稲作付け圃場候補を返す |
{
"work_type": "rough_harrowing",
"year": 2026,
"date": "2026-04-20",
"title": "水稲荒代掻き",
"notes": "",
"items": [
{ "field": 5, "plan": 12 },
{ "field": 6, "plan": 13 }
]
}
crop_name_snapshot / variety_name_snapshot はクライアント送信不要。サーバーが plan から自動設定するplan が null の場合は field に対応する当年 Plan から補完を試みる{
"id": 3,
"work_type": "rough_harrowing",
"year": 2026,
"date": "2026-04-20",
"title": "水稲荒代掻き",
"notes": "",
"work_record_id": 15,
"item_count": 2,
"total_area_tan": "2.0000",
"items": [
{
"id": 11,
"field": 5,
"field_name": "田中上",
"plan": 12,
"crop_name_snapshot": "水稲",
"variety_name_snapshot": "コシヒカリ"
}
],
"created_at": "2026-04-20T08:00:00Z",
"updated_at": "2026-04-20T08:00:00Z"
}
TractorWorkSession を作成するTractorWorkSessionItem を一括作成するcrop_name_snapshot / variety_name_snapshot をサーバー側で自動設定するWorkRecord を自動生成する(update_or_create)WorkRecord 側の作業日・タイトルも同期更新するTractorWorkSessionItem は CASCADE で削除されるWorkRecord は tractor_work_session の on_delete=CASCADE により削除される| enum値 | 表示名 |
|---|---|
tractor_work |
トラクター作業 |
work_date = session.datework_type = tractor_worktitle = session.title(work_type 別デフォルトで補完済み)year = session.yearauto_created = Truetractor_work_session = 対応する作業記録update_or_createon_delete=CASCADE により自動削除work_typeyeardateitems(1件以上)year は原則 date.year と一致しなければならないplan が指定されている場合、plan.field と field は一致しなければならないplan.year は session.year と一致しなければならないIssue #61 では、苗不足判明後に通常計画を飛ばして ToDo または 田植え実績 から着手する導線を追加予定である。
このときトラクター作業は、緊急対応時に必要な場合のみ起票される補助作業として扱う。
想定する扱い:
注意:
Issue #72 の 計画横断調整フロー は、将来的にトラクター作業系の計画整理にも適用する。
本編は実績記録機能なので、ここでの役割は次の 2 点にある。
ロック判定の正本
計画変更と実績記録の分離
TractorWorkSession / TractorWorkSessionItem に正本として残す共通方針は docs/27_マスタードキュメント_計画横断調整編.md を参照。
既存 apps/levee_work を apps/tractor_work にアプリごと改名する。
RenameModel migration でテーブルを改名するwork_type フィールドを追加し、既存レコードは levee_work で埋めるworkrecords の FK名・enum値も migration で更新する/levee-work/ → /tractor-work/ に変更するapp/levee-work/ → app/tractor-work/ に移動するSession / SessionItem 構成を維持するread と write を分離するPlan を起点に組み立てるsync_tractor_work_record(session) で WorkRecord と同期するbackend/apps/tractor_work/
├── models.py # TractorWorkSession, TractorWorkSessionItem
├── serializers.py
├── views.py
├── urls.py
├── admin.py
└── migrations/
├── 0001_initial.py # (levee_work から移行)
└── 0002_rename_and_add_work_type.py
変更ファイル:
backend/apps/workrecords/models.py — FK名・enum更新backend/apps/workrecords/services.py — sync関数改名backend/keinasystem/settings.py — INSTALLED_APPS更新backend/keinasystem/urls.py — URLパス更新frontend/src/app/tractor-work/
└── page.tsx
変更ファイル:
frontend/src/types/index.ts — 型定義更新frontend/src/components/Navbar.tsx — リンク更新frontend/src/app/workrecords/page.tsx — 遷移先更新