This commit is contained in:
2026-05-02 06:16:36 +03:30
parent bd02c8342a
commit f34d5dd198
38 changed files with 71 additions and 69 deletions
+5 -5
View File
@@ -17,9 +17,9 @@
| `POST /api/farm-data/` | بله | `farm_hub/services.py:166`, `farm_hub/services.py:89`, `sensor_external_api/services.py:165`, `sensor_external_api/services.py:125` | | `POST /api/farm-data/` | بله | `farm_hub/services.py:166`, `farm_hub/services.py:89`, `sensor_external_api/services.py:165`, `sensor_external_api/services.py:125` |
| `POST /api/weather/water-need-prediction/` | بله | `water/views.py:136` | | `POST /api/weather/water-need-prediction/` | بله | `water/views.py:136` |
| `POST /api/economy/overview/` | بله | `economic_overview/views.py:73` | | `POST /api/economy/overview/` | بله | `economic_overview/views.py:73` |
| `GET /api/irrigation/` | بله | `irrigation_recommendation/views.py:78` | | `GET /api/irrigation/` | بله | `irrigation/views.py:78` |
| `POST /api/irrigation/recommend/` | بله | `irrigation_recommendation/views.py:165` | | `POST /api/irrigation/recommend/` | بله | `irrigation/views.py:165` |
| `POST /api/fertilization/recommend/` | بله | `fertilization_recommendation/views.py:122` | | `POST /api/fertilization/recommend/` | بله | `fertilization/views.py:122` |
| `POST /api/crop-simulation/growth/` | بله | `yield_harvest/views.py:247` | | `POST /api/crop-simulation/growth/` | بله | `yield_harvest/views.py:247` |
| `GET /api/crop-simulation/growth/<task_id>/status/` | بله | `yield_harvest/views.py:293` | | `GET /api/crop-simulation/growth/<task_id>/status/` | بله | `yield_harvest/views.py:293` |
| `POST /api/crop-simulation/current-farm-chart/` | بله | `yield_harvest/views.py:145`, `yield_harvest/views.py:162` | | `POST /api/crop-simulation/current-farm-chart/` | بله | `yield_harvest/views.py:145`, `yield_harvest/views.py:162` |
@@ -31,12 +31,12 @@
| API درخواستی | وضعیت | route واقعی AI در کد | شواهد | | API درخواستی | وضعیت | route واقعی AI در کد | شواهد |
|---|---|---|---| |---|---|---|---|
| `POST /api/weather/farm-card/` | با همین route به AI وصل نیست | `GET /weather-forecast/card` | `water/views.py:49` | | `POST /api/weather/farm-card/` | با همین route به AI وصل نیست | `GET /weather-forecast/card` | `water/views.py:49` |
| `POST /api/irrigation/water-stress/` | با همین route به AI وصل نیست | `GET /api/water/stress-index/` | `irrigation_recommendation/views.py:246` | | `POST /api/irrigation/water-stress/` | با همین route به AI وصل نیست | `GET /api/water/stress-index/` | `irrigation/views.py:246` |
| `POST /api/pest-disease/detect/` | با همین route به AI وصل نیست | `POST /api/pest-detection/analyze/` | `pest_detection/views.py:161` | | `POST /api/pest-disease/detect/` | با همین route به AI وصل نیست | `POST /api/pest-detection/analyze/` | `pest_detection/views.py:161` |
| `POST /api/pest-disease/risk/` | با همین route به AI وصل نیست | `POST /api/pest-detection/risk/` | `pest_detection/views.py:202` | | `POST /api/pest-disease/risk/` | با همین route به AI وصل نیست | `POST /api/pest-detection/risk/` | `pest_detection/views.py:202` |
| `POST /api/pest-disease/risk-summary/` | با همین route به AI وصل نیست | `GET /api/pest-detection/risk-summary/` | `pest_detection/views.py:235` | | `POST /api/pest-disease/risk-summary/` | با همین route به AI وصل نیست | `GET /api/pest-detection/risk-summary/` | `pest_detection/views.py:235` |
| `POST /api/soil-data/ndvi-health/` | با همین route به AI وصل نیست | برای این path اتصال AI پیدا نشد؛ endpoint محلی پروژه با path دیگری ارائه شده | `crop_health/urls.py:6`, `crop_health/tests.py:82` | | `POST /api/soil-data/ndvi-health/` | با همین route به AI وصل نیست | برای این path اتصال AI پیدا نشد؛ endpoint محلی پروژه با path دیگری ارائه شده | `crop_health/urls.py:6`, `crop_health/tests.py:82` |
| `POST /api/irrigation/` | route به AI با همین method پیدا نشد | فقط `GET /api/irrigation/` در کد استفاده می‌شود | `irrigation_recommendation/views.py:78` | | `POST /api/irrigation/` | route به AI با همین method پیدا نشد | فقط `GET /api/irrigation/` در کد استفاده می‌شود | `irrigation/views.py:78` |
## متصل نیستند ## متصل نیستند
+9 -9
View File
@@ -14,10 +14,10 @@
|---|---|---| |---|---|---|
| `POST /api/weather/farm-card/` | فعال و استفاده‌شده | `water/weather_urls.py`, `water/views.py`, `water/tests.py` | | `POST /api/weather/farm-card/` | فعال و استفاده‌شده | `water/weather_urls.py`, `water/views.py`, `water/tests.py` |
| `POST /api/economy/overview/` | فعال و استفاده‌شده | `economic_overview/urls.py`, `economic_overview/views.py`, `FRONTEND_PAGES_APIS_GUIDE.md` | | `POST /api/economy/overview/` | فعال و استفاده‌شده | `economic_overview/urls.py`, `economic_overview/views.py`, `FRONTEND_PAGES_APIS_GUIDE.md` |
| `GET /api/irrigation/` | فعال و استفاده‌شده | `irrigation_recommendation/urls.py`, `irrigation_recommendation/views.py`, `API_DATA_SOURCE_AUDIT_FA.md` | | `GET /api/irrigation/` | فعال و استفاده‌شده | `irrigation/urls.py`, `irrigation/views.py`, `API_DATA_SOURCE_AUDIT_FA.md` |
| `POST /api/irrigation/recommend/` | فعال و استفاده‌شده | `irrigation_recommendation/urls.py`, `irrigation_recommendation/views.py`, `irrigation_recommendation/tests.py` | | `POST /api/irrigation/recommend/` | فعال و استفاده‌شده | `irrigation/urls.py`, `irrigation/views.py`, `irrigation/tests.py` |
| `POST /api/irrigation/water-stress/` | فعال و استفاده‌شده | `irrigation_recommendation/urls.py`, `irrigation_recommendation/tests.py` | | `POST /api/irrigation/water-stress/` | فعال و استفاده‌شده | `irrigation/urls.py`, `irrigation/tests.py` |
| `POST /api/fertilization/recommend/` | فعال و استفاده‌شده | `fertilization_recommendation/urls.py`, `fertilization_recommendation/views.py`, `API_DATA_SOURCE_AUDIT_FA.md` | | `POST /api/fertilization/recommend/` | فعال و استفاده‌شده | `fertilization/urls.py`, `fertilization/views.py`, `API_DATA_SOURCE_AUDIT_FA.md` |
## 2) در پروژه استفاده شده‌اند، اما به عنوان endpoint مستقیم backend اکسپوز نیستند ## 2) در پروژه استفاده شده‌اند، اما به عنوان endpoint مستقیم backend اکسپوز نیستند
@@ -61,11 +61,11 @@
| `POST /api/pest-disease/detect/` | استفاده نمی‌شود | endpoint واقعی پروژه `POST /api/pest-detection/analyze/` است | `pest_detection/urls.py`, `pest_detection/views.py` | | `POST /api/pest-disease/detect/` | استفاده نمی‌شود | endpoint واقعی پروژه `POST /api/pest-detection/analyze/` است | `pest_detection/urls.py`, `pest_detection/views.py` |
| `POST /api/pest-disease/risk/` | استفاده نمی‌شود | endpoint واقعی پروژه `POST /api/pest-detection/risk/` است | `pest_detection/urls.py`, `pest_detection/views.py` | | `POST /api/pest-disease/risk/` | استفاده نمی‌شود | endpoint واقعی پروژه `POST /api/pest-detection/risk/` است | `pest_detection/urls.py`, `pest_detection/views.py` |
| `POST /api/pest-disease/risk-summary/` | استفاده نمی‌شود | path و method هر دو متفاوت‌اند؛ endpoint واقعی `GET /api/pest-detection/risk-summary/` است | `pest_detection/urls.py`, `pest_detection/views.py`, `pest_detection/tests.py` | | `POST /api/pest-disease/risk-summary/` | استفاده نمی‌شود | path و method هر دو متفاوت‌اند؛ endpoint واقعی `GET /api/pest-detection/risk-summary/` است | `pest_detection/urls.py`, `pest_detection/views.py`, `pest_detection/tests.py` |
| `POST /api/irrigation/` | استفاده نمی‌شود | path وجود دارد ولی فقط `GET` list پیاده‌سازی شده | `irrigation_recommendation/urls.py`, `irrigation_recommendation/views.py` | | `POST /api/irrigation/` | استفاده نمی‌شود | path وجود دارد ولی فقط `GET` list پیاده‌سازی شده | `irrigation/urls.py`, `irrigation/views.py` |
| `GET /api/irrigation/<pk>/` | استفاده نمی‌شود | route detail پیدا نشد | `irrigation_recommendation/urls.py` | | `GET /api/irrigation/<pk>/` | استفاده نمی‌شود | route detail پیدا نشد | `irrigation/urls.py` |
| `PUT /api/irrigation/<pk>/` | استفاده نمی‌شود | route detail/update پیدا نشد | `irrigation_recommendation/urls.py` | | `PUT /api/irrigation/<pk>/` | استفاده نمی‌شود | route detail/update پیدا نشد | `irrigation/urls.py` |
| `PATCH /api/irrigation/<pk>/` | استفاده نمی‌شود | route detail/update پیدا نشد | `irrigation_recommendation/urls.py` | | `PATCH /api/irrigation/<pk>/` | استفاده نمی‌شود | route detail/update پیدا نشد | `irrigation/urls.py` |
| `DELETE /api/irrigation/<pk>/` | استفاده نمی‌شود | route detail/delete پیدا نشد | `irrigation_recommendation/urls.py` | | `DELETE /api/irrigation/<pk>/` | استفاده نمی‌شود | route detail/delete پیدا نشد | `irrigation/urls.py` |
## 4) جمع‌بندی سریع ## 4) جمع‌بندی سریع
+12 -12
View File
@@ -2,8 +2,8 @@
این فایل تغییرات مربوط به سه فایل زیر را نسبت به **۶ کامیت قبل** (`HEAD~6`) مستند می‌کند: این فایل تغییرات مربوط به سه فایل زیر را نسبت به **۶ کامیت قبل** (`HEAD~6`) مستند می‌کند:
- `irrigation_recommendation/urls.py` - `irrigation/urls.py`
- `fertilization_recommendation/apps.py` - `fertilization/apps.py`
- `farm_ai_assistant/views.py` - `farm_ai_assistant/views.py`
## بازه مقایسه ## بازه مقایسه
@@ -11,11 +11,11 @@
- مقصد: `HEAD` - مقصد: `HEAD`
## نتیجه سریع ## نتیجه سریع
- در `irrigation_recommendation/urls.py`، API آبیاری از مدل دارای endpoint بررسی وضعیت task فاصله گرفته و دو endpoint جدید برای لیست روش‌های آبیاری و water stress اضافه شده است. - در `irrigation/urls.py`، API آبیاری از مدل دارای endpoint بررسی وضعیت task فاصله گرفته و دو endpoint جدید برای لیست روش‌های آبیاری و water stress اضافه شده است.
- در `fertilization_recommendation/apps.py`، در این بازه **هیچ تغییری** ثبت نشده است. - در `fertilization/apps.py`، در این بازه **هیچ تغییری** ثبت نشده است.
- در `farm_ai_assistant/views.py`، API چت از flow مبتنی بر task/polling به flow مستقیم request/response تغییر کرده و پشتیبانی از `history`، `image_urls` و ورودی‌های multipart/JSON بهتر شده است. - در `farm_ai_assistant/views.py`، API چت از flow مبتنی بر task/polling به flow مستقیم request/response تغییر کرده و پشتیبانی از `history`، `image_urls` و ورودی‌های multipart/JSON بهتر شده است.
## 1) تغییرات `irrigation_recommendation/urls.py` ## 1) تغییرات `irrigation/urls.py`
### وضعیت قبلی ### وضعیت قبلی
مسیرهای زیر وجود داشتند: مسیرهای زیر وجود داشتند:
@@ -33,7 +33,7 @@
### تغییرات دقیق ### تغییرات دقیق
#### الف) اضافه شدن endpoint ریشه برای لیست روش‌های آبیاری #### الف) اضافه شدن endpoint ریشه برای لیست روش‌های آبیاری
مسیر جدید: مسیر جدید:
- `GET irrigation_recommendation/` - `GET irrigation/`
- view: `IrrigationMethodListView` - view: `IrrigationMethodListView`
- name: `irrigation-method-list` - name: `irrigation-method-list`
@@ -52,7 +52,7 @@
#### ج) اضافه شدن endpoint جدید water stress #### ج) اضافه شدن endpoint جدید water stress
مسیر جدید: مسیر جدید:
- `POST irrigation_recommendation/water-stress/` - `POST irrigation/water-stress/`
- view: `WaterStressView` - view: `WaterStressView`
- name: `irrigation-water-stress` - name: `irrigation-water-stress`
@@ -63,18 +63,18 @@
- `config/` - `config/`
- `recommend/` - `recommend/`
## 2) تغییرات `fertilization_recommendation/apps.py` ## 2) تغییرات `fertilization/apps.py`
در بازه `HEAD~6..HEAD` برای این فایل **هیچ diffای وجود ندارد**. در بازه `HEAD~6..HEAD` برای این فایل **هیچ diffای وجود ندارد**.
### وضعیت فعلی و قبلی یکسان است ### وضعیت فعلی و قبلی یکسان است
مقدارهای مهم بدون تغییر مانده‌اند: مقدارهای مهم بدون تغییر مانده‌اند:
- `default_auto_field = "django.db.models.BigAutoField"` - `default_auto_field = "django.db.models.BigAutoField"`
- `name = "fertilization_recommendation"` - `name = "fertilization"`
- `verbose_name = "Fertilization Recommendation"` - `verbose_name = "Fertilization Recommendation"`
### نتیجه ### نتیجه
- از نظر ثبت app در Django، در این ۶ کامیت اخیر تغییری در `fertilization_recommendation/apps.py` اعمال نشده است. - از نظر ثبت app در Django، در این ۶ کامیت اخیر تغییری در `fertilization/apps.py` اعمال نشده است.
- اگر منظورت بررسی APIهای recommendation بوده، این فایل خودش route یا view API ندارد و فقط تنظیمات app را نگه می‌دارد. - اگر منظورت بررسی APIهای recommendation بوده، این فایل خودش route یا view API ندارد و فقط تنظیمات app را نگه می‌دارد.
## 3) تغییرات `farm_ai_assistant/views.py` ## 3) تغییرات `farm_ai_assistant/views.py`
@@ -215,12 +215,12 @@ API چت از این مدل:
## جمع‌بندی نهایی ## جمع‌بندی نهایی
در این ۶ کامیت اخیر: در این ۶ کامیت اخیر:
- `irrigation_recommendation/urls.py` - `irrigation/urls.py`
- endpoint بررسی وضعیت task حذف شده - endpoint بررسی وضعیت task حذف شده
- endpoint ریشه برای لیست روش‌های آبیاری اضافه شده - endpoint ریشه برای لیست روش‌های آبیاری اضافه شده
- endpoint جدید `water-stress/` اضافه شده - endpoint جدید `water-stress/` اضافه شده
- `fertilization_recommendation/apps.py` - `fertilization/apps.py`
- هیچ تغییری نداشته است - هیچ تغییری نداشته است
- `farm_ai_assistant/views.py` - `farm_ai_assistant/views.py`
Binary file not shown.
+2 -2
View File
@@ -9,8 +9,8 @@
"plant_simulator": "plant_simulator", "plant_simulator": "plant_simulator",
"pest_detection": "pest_detection", "pest_detection": "pest_detection",
"sensor_7_in_1": "sensor-7-in-1", "sensor_7_in_1": "sensor-7-in-1",
"irrigation_recommendation": "irrigation_recommendation", "irrigation": "irrigation",
"fertilization_recommendation": "fertilization_recommendation", "fertilization": "fertilization",
"farm_ai_assistant": "farm_ai_assistant", "farm_ai_assistant": "farm_ai_assistant",
"notifications": "notifications", "notifications": "notifications",
"external_api_adapter": "external_api_adapter", "external_api_adapter": "external_api_adapter",
+2 -2
View File
@@ -49,11 +49,11 @@ INSTALLED_APPS = [
"pest_detection", "pest_detection",
"sensor_7_in_1.apps.Sensor7In1Config", "sensor_7_in_1.apps.Sensor7In1Config",
"water.apps.WaterConfig", "water.apps.WaterConfig",
"irrigation_recommendation", "irrigation",
"yield_harvest.apps.YieldHarvestConfig", "yield_harvest.apps.YieldHarvestConfig",
"economic_overview.apps.EconomicOverviewConfig", "economic_overview.apps.EconomicOverviewConfig",
"farm_alerts.apps.FarmAlertsConfig", "farm_alerts.apps.FarmAlertsConfig",
"fertilization_recommendation", "fertilization",
"farm_ai_assistant", "farm_ai_assistant",
"notifications.apps.NotificationsConfig", "notifications.apps.NotificationsConfig",
"plants.apps.PlantsConfig", "plants.apps.PlantsConfig",
+2 -2
View File
@@ -25,13 +25,13 @@ urlpatterns = [
path("api/pest-disease/", include("pest_detection.pest_disease_urls")), path("api/pest-disease/", include("pest_detection.pest_disease_urls")),
path("api/sensor-7-in-1/", include("sensor_7_in_1.urls")), path("api/sensor-7-in-1/", include("sensor_7_in_1.urls")),
path("api/sensors/", include("sensor_7_in_1.comparison_urls")), path("api/sensors/", include("sensor_7_in_1.comparison_urls")),
path("api/irrigation/", include("irrigation_recommendation.urls")), path("api/irrigation/", include("irrigation.urls")),
path("api/weather/", include("water.weather_urls")), path("api/weather/", include("water.weather_urls")),
path("api/water/", include("water.urls")), path("api/water/", include("water.urls")),
path("api/economy/", include("economic_overview.urls")), path("api/economy/", include("economic_overview.urls")),
path("api/fertilization/", include("fertilization_recommendation.urls")), path("api/fertilization/", include("fertilization.urls")),
path("api/farm-ai-assistant/", include("farm_ai_assistant.urls")), path("api/farm-ai-assistant/", include("farm_ai_assistant.urls")),
path("api/notifications/", include("notifications.urls")), path("api/notifications/", include("notifications.urls")),
path("api/farm-alerts/", include("farm_alerts.urls")), path("api/farm-alerts/", include("farm_alerts.urls")),
+2 -2
View File
@@ -12,8 +12,8 @@ from farm_alerts.services import (
get_alert_tracker_data, get_alert_tracker_data,
get_recommendations_list_data, get_recommendations_list_data,
) )
from fertilization_recommendation.services import get_fertilization_dashboard_recommendation from fertilization.services import get_fertilization_dashboard_recommendation
from irrigation_recommendation.services import get_irrigation_dashboard_recommendation from irrigation.services import get_irrigation_dashboard_recommendation
from pest_detection.services import get_risk_summary_data from pest_detection.services import get_risk_summary_data
from sensor_7_in_1.services import ( from sensor_7_in_1.services import (
get_sensor_7_in_1_summary_data, get_sensor_7_in_1_summary_data,
+6 -6
View File
@@ -109,10 +109,10 @@
- app aggregator call: `water` - app aggregator call: `water`
- service: `water/services.py` -> `get_water_need_prediction_data` - service: `water/services.py` -> `get_water_need_prediction_data`
- source واقعی داده: `irrigation_recommendation.models.IrrigationRecommendationRequest` - source واقعی داده: `irrigation.models.IrrigationRecommendationRequest`
- منطق: از `response_payload` آخرین recommendation آبیاری، `water_balance.daily` را می خواند. - منطق: از `response_payload` آخرین recommendation آبیاری، `water_balance.daily` را می خواند.
نکته مهم: تابعی با همین نام در `irrigation_recommendation/services.py` هم وجود دارد، اما داشبورد فعلی نسخه `water` را صدا می زند. پس منبع business data عملا app آبیاری است، ولی facade فعلی داخل app `water` قرار دارد. نکته مهم: تابعی با همین نام در `irrigation/services.py` هم وجود دارد، اما داشبورد فعلی نسخه `water` را صدا می زند. پس منبع business data عملا app آبیاری است، ولی facade فعلی داخل app `water` قرار دارد.
### 10) `harvestPredictionCard` ### 10) `harvestPredictionCard`
@@ -150,10 +150,10 @@
- `farm_alerts.services.get_recommendations_list_data` - `farm_alerts.services.get_recommendations_list_data`
- model/source: `farm_alerts.models.Recommendation` - model/source: `farm_alerts.models.Recommendation`
- `irrigation_recommendation.services.get_irrigation_dashboard_recommendation` - `irrigation.services.get_irrigation_dashboard_recommendation`
- model/source: `irrigation_recommendation.models.IrrigationRecommendationRequest` - model/source: `irrigation.models.IrrigationRecommendationRequest`
- `fertilization_recommendation.services.get_fertilization_dashboard_recommendation` - `fertilization.services.get_fertilization_dashboard_recommendation`
- model/source: `fertilization_recommendation.models.FertilizationRecommendationRequest` - model/source: `fertilization.models.FertilizationRecommendationRequest`
- `yield_harvest.services.get_yield_harvest_summary_data` - `yield_harvest.services.get_yield_harvest_summary_data`
- برای ساخت recommendation مرتبط با بازه برداشت - برای ساخت recommendation مرتبط با بازه برداشت
@@ -1,6 +1,6 @@
# Recommend Task Status API Guide # Recommend Task Status API Guide
این فایل برای تیم فرانت‌اند توضیح می‌دهد که برای ماژول‌های `fertilization_recommendation` و `irrigation_recommendation` چه درخواست‌هایی باید به بک‌اند ارسال شود و چه پاسخ‌هایی باید دریافت شود. این فایل برای تیم فرانت‌اند توضیح می‌دهد که برای ماژول‌های `fertilization` و `irrigation` چه درخواست‌هایی باید به بک‌اند ارسال شود و چه پاسخ‌هایی باید دریافت شود.
## Fertilization Recommendation ## Fertilization Recommendation
@@ -1,7 +1,8 @@
from django.apps import AppConfig from django.apps import AppConfig
class FertilizationRecommendationConfig(AppConfig): class FertilizationConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField" default_auto_field = "django.db.models.BigAutoField"
name = "fertilization_recommendation" name = "fertilization"
label = "fertilization_recommendation"
verbose_name = "Fertilization Recommendation & Plan Parser" verbose_name = "Fertilization Recommendation & Plan Parser"
@@ -28,13 +28,13 @@ class Migration(migrations.Migration):
"farm", "farm",
models.ForeignKey( models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, on_delete=django.db.models.deletion.CASCADE,
related_name="fertilization_recommendations", related_name="fertilizations",
to="farm_hub.farmhub", to="farm_hub.farmhub",
), ),
), ),
], ],
options={ options={
"db_table": "fertilization_recommendation_requests", "db_table": "fertilization_requests",
"ordering": ["-created_at", "-id"], "ordering": ["-created_at", "-id"],
}, },
), ),
@@ -6,7 +6,7 @@ OLD_STATUSES = {"", "success", "error", None}
def migrate_existing_statuses(apps, schema_editor): def migrate_existing_statuses(apps, schema_editor):
Recommendation = apps.get_model("fertilization_recommendation", "FertilizationRecommendationRequest") Recommendation = apps.get_model("fertilization", "FertilizationRecommendationRequest")
Recommendation.objects.filter(status__in=[status for status in OLD_STATUSES if status is not None]).update( Recommendation.objects.filter(status__in=[status for status in OLD_STATUSES if status is not None]).update(
status=PENDING_STATUS status=PENDING_STATUS
) )
@@ -15,7 +15,7 @@ def migrate_existing_statuses(apps, schema_editor):
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("fertilization_recommendation", "0001_initial"), ("fertilization", "0001_initial"),
] ]
operations = [ operations = [
@@ -19,7 +19,7 @@ class FertilizationRecommendationRequest(models.Model):
farm = models.ForeignKey( farm = models.ForeignKey(
FarmHub, FarmHub,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name="fertilization_recommendations", related_name="fertilizations",
) )
crop_id = models.CharField(max_length=255, blank=True, default="") crop_id = models.CharField(max_length=255, blank=True, default="")
growth_stage = models.CharField(max_length=255, blank=True, default="") growth_stage = models.CharField(max_length=255, blank=True, default="")
@@ -36,7 +36,7 @@ class FertilizationRecommendationRequest(models.Model):
updated_at = models.DateTimeField(auto_now=True) updated_at = models.DateTimeField(auto_now=True)
class Meta: class Meta:
db_table = "fertilization_recommendation_requests" db_table = "fertilization_requests"
ordering = ["-created_at", "-id"] ordering = ["-created_at", "-id"]
def __str__(self): def __str__(self):
@@ -21,7 +21,7 @@ class FertilizationRecommendViewTests(TestCase):
self.farm_type = FarmType.objects.create(name="زراعی") self.farm_type = FarmType.objects.create(name="زراعی")
self.farm = FarmHub.objects.create(owner=self.user, farm_type=self.farm_type, name="fert-farm") self.farm = FarmHub.objects.create(owner=self.user, farm_type=self.farm_type, name="fert-farm")
@patch("fertilization_recommendation.views.external_api_request") @patch("fertilization.views.external_api_request")
def test_plan_from_text_proxies_to_ai_service(self, mock_external_api_request): def test_plan_from_text_proxies_to_ai_service(self, mock_external_api_request):
mock_external_api_request.return_value = AdapterResponse( mock_external_api_request.return_value = AdapterResponse(
status_code=200, status_code=200,
@@ -67,7 +67,7 @@ class FertilizationRecommendViewTests(TestCase):
self.assertEqual(response.status_code, 400) self.assertEqual(response.status_code, 400)
self.assertIn("non_field_errors", response.data) self.assertIn("non_field_errors", response.data)
@patch("fertilization_recommendation.views.external_api_request") @patch("fertilization.views.external_api_request")
def test_recommend_returns_updated_response_shape(self, mock_external_api_request): def test_recommend_returns_updated_response_shape(self, mock_external_api_request):
mock_external_api_request.return_value = AdapterResponse( mock_external_api_request.return_value = AdapterResponse(
status_code=200, status_code=200,
@@ -166,7 +166,7 @@ class FertilizationRecommendViewTests(TestCase):
}, },
) )
@patch("fertilization_recommendation.views.external_api_request") @patch("fertilization.views.external_api_request")
def test_recommend_accepts_plant_name_and_passes_it_directly_to_ai(self, mock_external_api_request): def test_recommend_accepts_plant_name_and_passes_it_directly_to_ai(self, mock_external_api_request):
mock_external_api_request.return_value = AdapterResponse(status_code=200, data={"data": {}}) mock_external_api_request.return_value = AdapterResponse(status_code=200, data={"data": {}})
@@ -436,7 +436,7 @@ class RecommendationListView(FarmAccessMixin, APIView):
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
farm = self._get_farm(request, serializer.validated_data["farm_uuid"]) farm = self._get_farm(request, serializer.validated_data["farm_uuid"])
recommendations = farm.fertilization_recommendations.all().order_by("-created_at", "-id") recommendations = farm.fertilizations.all().order_by("-created_at", "-id")
paginator = self.pagination_class() paginator = self.pagination_class()
page = paginator.paginate_queryset(recommendations, request, view=self) page = paginator.paginate_queryset(recommendations, request, view=self)
@@ -3,7 +3,7 @@
این فایل برای تحویل به فرانت نوشته شده و endpointهای مرتبط با آبیاری را به‌صورت کامل توضیح می‌دهد. این فایل برای تحویل به فرانت نوشته شده و endpointهای مرتبط با آبیاری را به‌صورت کامل توضیح می‌دهد.
محدوده این مستند: محدوده این مستند:
- همه endpointهای `irrigation_recommendation/urls.py` - همه endpointهای `irrigation/urls.py`
- endpoint دریافت محصولات انتخاب‌شده مزرعه: `GET /api/plants/selected/` - endpoint دریافت محصولات انتخاب‌شده مزرعه: `GET /api/plants/selected/`
## نکات عمومی ## نکات عمومی
@@ -1,7 +1,8 @@
from django.apps import AppConfig from django.apps import AppConfig
class IrrigationRecommendationConfig(AppConfig): class IrrigationConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField" default_auto_field = "django.db.models.BigAutoField"
name = "irrigation_recommendation" name = "irrigation"
label = "irrigation_recommendation"
verbose_name = "Irrigation Recommendation & Plan Parser" verbose_name = "Irrigation Recommendation & Plan Parser"
@@ -27,13 +27,13 @@ class Migration(migrations.Migration):
"farm", "farm",
models.ForeignKey( models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, on_delete=django.db.models.deletion.CASCADE,
related_name="irrigation_recommendations", related_name="irrigations",
to="farm_hub.farmhub", to="farm_hub.farmhub",
), ),
), ),
], ],
options={ options={
"db_table": "irrigation_recommendation_requests", "db_table": "irrigation_requests",
"ordering": ["-created_at", "-id"], "ordering": ["-created_at", "-id"],
}, },
), ),
@@ -3,7 +3,7 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("irrigation_recommendation", "0001_initial"), ("irrigation", "0001_initial"),
] ]
operations = [ operations = [
@@ -21,7 +21,7 @@ class IrrigationRecommendationRequest(models.Model):
farm = models.ForeignKey( farm = models.ForeignKey(
FarmHub, FarmHub,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name="irrigation_recommendations", related_name="irrigations",
) )
crop_id = models.CharField(max_length=255, blank=True, default="") crop_id = models.CharField(max_length=255, blank=True, default="")
growth_stage = models.CharField(max_length=255, blank=True, default="") growth_stage = models.CharField(max_length=255, blank=True, default="")
@@ -38,7 +38,7 @@ class IrrigationRecommendationRequest(models.Model):
updated_at = models.DateTimeField(auto_now=True) updated_at = models.DateTimeField(auto_now=True)
class Meta: class Meta:
db_table = "irrigation_recommendation_requests" db_table = "irrigation_requests"
ordering = ["-created_at", "-id"] ordering = ["-created_at", "-id"]
def __str__(self): def __str__(self):
@@ -37,7 +37,7 @@ class WaterStressViewTests(TestCase):
self.farm = FarmHub.objects.create(owner=self.user, farm_type=self.farm_type, name="Farm 1") self.farm = FarmHub.objects.create(owner=self.user, farm_type=self.farm_type, name="Farm 1")
self.other_farm = FarmHub.objects.create(owner=self.other_user, farm_type=self.farm_type, name="Farm 2") self.other_farm = FarmHub.objects.create(owner=self.other_user, farm_type=self.farm_type, name="Farm 2")
@patch("irrigation_recommendation.views.external_api_request") @patch("irrigation.views.external_api_request")
def test_post_proxies_request_to_ai_service(self, mock_external_api_request): def test_post_proxies_request_to_ai_service(self, mock_external_api_request):
mock_external_api_request.return_value = AdapterResponse( mock_external_api_request.return_value = AdapterResponse(
status_code=200, status_code=200,
@@ -102,7 +102,7 @@ class IrrigationPlanFromTextViewTests(TestCase):
self.farm_type = FarmType.objects.create(name="گلخانه ای") self.farm_type = FarmType.objects.create(name="گلخانه ای")
self.farm = FarmHub.objects.create(owner=self.user, farm_type=self.farm_type, name="Plan Parser Farm") self.farm = FarmHub.objects.create(owner=self.user, farm_type=self.farm_type, name="Plan Parser Farm")
@patch("irrigation_recommendation.views.external_api_request") @patch("irrigation.views.external_api_request")
def test_plan_from_text_proxies_to_ai_service(self, mock_external_api_request): def test_plan_from_text_proxies_to_ai_service(self, mock_external_api_request):
mock_external_api_request.return_value = AdapterResponse( mock_external_api_request.return_value = AdapterResponse(
status_code=200, status_code=200,
@@ -153,7 +153,7 @@ class IrrigationMethodListViewTests(TestCase):
def setUp(self): def setUp(self):
self.factory = APIRequestFactory() self.factory = APIRequestFactory()
@patch("irrigation_recommendation.views.external_api_request") @patch("irrigation.views.external_api_request")
def test_get_proxies_irrigation_methods_from_ai(self, mock_external_api_request): def test_get_proxies_irrigation_methods_from_ai(self, mock_external_api_request):
mock_external_api_request.return_value = AdapterResponse( mock_external_api_request.return_value = AdapterResponse(
status_code=200, status_code=200,
@@ -182,7 +182,7 @@ class IrrigationMethodListViewTests(TestCase):
method="GET", method="GET",
) )
@patch("irrigation_recommendation.views.external_api_request") @patch("irrigation.views.external_api_request")
def test_post_proxies_irrigation_method_creation_to_ai(self, mock_external_api_request): def test_post_proxies_irrigation_method_creation_to_ai(self, mock_external_api_request):
mock_external_api_request.return_value = AdapterResponse( mock_external_api_request.return_value = AdapterResponse(
status_code=201, status_code=201,
@@ -226,7 +226,7 @@ class RecommendViewTests(TestCase):
irrigation_method_name="آبیاری قطره ای", irrigation_method_name="آبیاری قطره ای",
) )
@patch("irrigation_recommendation.views.external_api_request") @patch("irrigation.views.external_api_request")
def test_post_returns_full_recommendation_shape(self, mock_external_api_request): def test_post_returns_full_recommendation_shape(self, mock_external_api_request):
mock_external_api_request.return_value = AdapterResponse( mock_external_api_request.return_value = AdapterResponse(
status_code=200, status_code=200,
@@ -428,7 +428,7 @@ class IrrigationRecommendationHistoryTests(TestCase):
self.assertEqual(response.status_code, 404) self.assertEqual(response.status_code, 404)
self.assertEqual(response.data["msg"], "Recommendation not found.") self.assertEqual(response.data["msg"], "Recommendation not found.")
@patch("irrigation_recommendation.views.external_api_request") @patch("irrigation.views.external_api_request")
def test_post_accepts_sensor_uuid_as_farm_uuid_alias(self, mock_external_api_request): def test_post_accepts_sensor_uuid_as_farm_uuid_alias(self, mock_external_api_request):
mock_external_api_request.return_value = AdapterResponse( mock_external_api_request.return_value = AdapterResponse(
status_code=200, status_code=200,
@@ -250,7 +250,7 @@ class RecommendationListView(FarmAccessMixin, APIView):
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
farm = self._get_farm(request, serializer.validated_data["farm_uuid"]) farm = self._get_farm(request, serializer.validated_data["farm_uuid"])
recommendations = farm.irrigation_recommendations.all().order_by("-created_at", "-id") recommendations = farm.irrigations.all().order_by("-created_at", "-id")
paginator = self.pagination_class() paginator = self.pagination_class()
page = paginator.paginate_queryset(recommendations, request, view=self) page = paginator.paginate_queryset(recommendations, request, view=self)
+1 -1
View File
@@ -1,6 +1,6 @@
from copy import deepcopy from copy import deepcopy
from irrigation_recommendation.models import IrrigationRecommendationRequest from irrigation.models import IrrigationRecommendationRequest
from .mock_data import FARM_WEATHER_CARD, WATER_NEED_PREDICTION, WATER_STRESS_INDEX from .mock_data import FARM_WEATHER_CARD, WATER_NEED_PREDICTION, WATER_STRESS_INDEX
from .models import WeatherForecastLog from .models import WeatherForecastLog