This commit is contained in:
2026-05-05 21:02:12 +03:30
parent 5301071df5
commit 1679825ae2
47 changed files with 1347 additions and 1403 deletions
+63 -21
View File
@@ -3,8 +3,10 @@ from __future__ import annotations
from decimal import Decimal, ROUND_HALF_UP
from numbers import Number
import logging
import warnings
from django.conf import settings
from django.apps import apps
from django.db import transaction
from django.utils.dateparse import parse_datetime
@@ -40,6 +42,10 @@ class BackendSyncError(Exception):
"""خطا در همگام سازی کاتالوگ گیاه و assignmentها از Backend."""
class LegacyFarmPlantRelationWarning(DeprecationWarning):
"""هشدار برای relation قدیمی SensorData.plants."""
PARAMETER_LABEL_OVERRIDES = {
"soil_moisture": "رطوبت خاک",
"soil_temperature": "دمای خاک",
@@ -187,7 +193,9 @@ def assign_farm_plants_from_backend_ids(farm: SensorData, backend_plant_ids: lis
plant=snapshot_by_backend_id[backend_plant_id],
defaults={"position": position},
)
return [snapshot_by_backend_id[backend_plant_id] for backend_plant_id in normalized_ids]
snapshots_in_order = [snapshot_by_backend_id[backend_plant_id] for backend_plant_id in normalized_ids]
reconcile_legacy_farm_plants_relation(farm, snapshots_in_order)
return snapshots_in_order
def get_farm_plant_assignments(farm: SensorData) -> list[FarmPlantAssignment]:
@@ -200,6 +208,44 @@ def get_farm_plant_snapshots(farm: SensorData) -> list[PlantCatalogSnapshot]:
return [assignment.plant for assignment in get_farm_plant_assignments(farm)]
def reconcile_legacy_farm_plants_relation(
farm: SensorData,
snapshots: list[PlantCatalogSnapshot] | None = None,
) -> None:
snapshots = list(snapshots if snapshots is not None else get_farm_plant_snapshots(farm))
Plant = apps.get_model("plant", "Plant")
if Plant is None:
return
names = [snapshot.name for snapshot in snapshots if snapshot and snapshot.name]
if not names:
farm.plants.clear()
return
legacy_plants = list(Plant.objects.filter(name__in=names).order_by("name", "id"))
farm.plants.set(legacy_plants)
def get_canonical_farm_record(farm_uuid: str) -> SensorData | None:
return (
SensorData.objects.select_related(
"center_location",
"weather_forecast",
"irrigation_method",
)
.prefetch_related("plant_assignments__plant", "center_location__depths")
.filter(farm_uuid=farm_uuid)
.first()
)
def get_legacy_farm_plants(farm: SensorData):
warnings.warn(
"SensorData.plants is deprecated; use farm_data.services canonical plant snapshot helpers instead.",
LegacyFarmPlantRelationWarning,
stacklevel=2,
)
return farm.plants.all()
def get_primary_plant_snapshot(farm: SensorData) -> PlantCatalogSnapshot | None:
assignments = get_farm_plant_assignments(farm)
return assignments[0].plant if assignments else None
@@ -259,6 +305,20 @@ def clone_snapshot_as_runtime_plant(
return runtime
def get_runtime_plant_for_farm(
farm: SensorData,
*,
plant_name: str | None = None,
growth_stage: str | None = None,
):
snapshot = get_farm_plant_snapshot_by_name(farm, plant_name)
return clone_snapshot_as_runtime_plant(snapshot, growth_stage=growth_stage)
def list_runtime_plants_for_farm(farm: SensorData) -> list[object]:
return [clone_snapshot_as_runtime_plant(snapshot) for snapshot in get_farm_plant_snapshots(farm)]
def build_plant_text_from_snapshot(
plant: PlantCatalogSnapshot | None,
growth_stage: str,
@@ -290,16 +350,7 @@ def build_plant_text_from_snapshot(
def build_farm_plant_context(farm_uuid: str) -> dict | None:
farm = (
SensorData.objects.select_related(
"center_location",
"weather_forecast",
"irrigation_method",
)
.prefetch_related("plant_assignments__plant", "center_location__depths")
.filter(farm_uuid=farm_uuid)
.first()
)
farm = get_canonical_farm_record(farm_uuid)
if farm is None:
return None
assignments = get_farm_plant_assignments(farm)
@@ -397,16 +448,7 @@ def get_sensor_parameter_catalog(sensor_payload: dict | None = None) -> dict[str
def get_farm_details(farm_uuid: str):
farm = (
SensorData.objects.select_related(
"center_location",
"weather_forecast",
"irrigation_method",
)
.prefetch_related("plant_assignments__plant", "center_location__depths")
.filter(farm_uuid=farm_uuid)
.first()
)
farm = get_canonical_farm_record(farm_uuid)
if farm is None:
return None