Skip to content

Commit 017b134

Browse files
JoleVLFJoleVLF
andauthored
27 update report for irrigation and farm calendar (#28)
* Readme update * Update data regarding the farm activity calendar * Update report.py File report upsert * Updata data model and logging --------- Co-authored-by: JoleVLF <Jovan@DESKTOP-JTIACNO>
1 parent f5aa0c2 commit 017b134

8 files changed

Lines changed: 158 additions & 69 deletions

File tree

app/api/api_v1/endpoints/report.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -85,19 +85,6 @@ async def generate_generic_observation_report(
8585
8686
8787
"""
88-
possible_names = [
89-
"Pesticides",
90-
"Irrigation",
91-
"Fertilization",
92-
"CropStressIndicator",
93-
"CropGrowthObservation",
94-
]
95-
if observation_type_name not in possible_names:
96-
raise HTTPException(
97-
status_code=400,
98-
detail=f"Observation type name: {observation_type_name} is not inside supported types: {possible_names}",
99-
)
100-
10188
if observation_type_name == "CropGrowthObservation":
10289
observation_type_name = "Crop Growth Stage Observation"
10390

@@ -151,10 +138,11 @@ async def generate_generic_observation_report(
151138

152139
else:
153140
try:
141+
dt = json.load(data.file)
154142
pdf = process_farm_calendar_data(
155143
activity_type_info=observation_type_name,
156-
observations=json.load(data.file)["observations"],
157-
farm_activities=json.load(data.file)["farm_activities"],
144+
observations=dt["observations"],
145+
farm_activities=dt["farm_activities"],
158146
)
159147

160148
except JSONDecodeError as e:

app/init_gatekeeper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def register_apis_to_gatekeeper():
3838
"endpoint": f"api/v1/{api.path.strip('/')}",
3939
"methods": list(api.methods),
4040
}
41-
logger.info("Port registered", settings.REPORTING_SERVICE_PORT)
41+
logger.info("Port registered: %s", settings.REPORTING_SERVICE_PORT)
4242
api_response = requests.post(
4343
url=settings.REPORTING_GATEKEEPER_BASE_URL + "api/register_service/",
4444
headers={

app/schemas/animals.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ class Animal(BaseModel):
2424
birthdate: datetime
2525
isMemberOfAnimalGroup: Optional[AnimalGroup]
2626
status: int
27-
invalidatedAtTime: Optional[datetime]
28-
dateCreated: datetime
29-
dateModified: datetime
27+
invalidatedAtTime: Optional[datetime] = None
28+
dateCreated: Optional[datetime] = None
29+
dateModified: Optional[datetime] = None

app/schemas/compost.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,42 @@
11
from pydantic import BaseModel, Field
2-
from typing import List
2+
from typing import List, Optional
33
from datetime import datetime
44

55

6+
class HasResult(BaseModel):
7+
type: str = Field(alias="@type")
8+
id: str = Field(alias="@id")
9+
unit: Optional[str] = (None,)
10+
hasValue: Optional[str] = None
11+
12+
613
class CropObservation(BaseModel):
714
"""Model for observations"""
815

916
type: str = Field(alias="@type")
1017
id: str = Field(alias="@id")
11-
activityType: str
18+
activityType: dict
1219
title: str
1320
details: str
14-
hasStartDatetime: datetime
15-
hasEndDatetime: datetime
16-
responsibleAgent: str
17-
usesAgriculturalMachinery: List[str]
18-
hasValue: str
19-
isMeasuredIn: str
20-
relatesToProperty: str
21+
hasStartDatetime: Optional[datetime] = None
22+
hasEndDatetime: Optional[datetime] = None
23+
responsibleAgent: Optional[str] = None
24+
usesAgriculturalMachinery: List[dict] = []
25+
hasResult: Optional[HasResult] = None
26+
isMeasuredIn: Optional[str] = None
27+
relatesToProperty: Optional[str] = None
28+
observedProperty: Optional[str] = None
2129

2230

2331
class Operation(BaseModel):
2432
"""Model for farm operations"""
2533

2634
type: str = Field(alias="@type")
2735
id: str = Field(alias="@id")
28-
activityType: str
36+
activityType: dict
2937
title: str
3038
details: str
31-
hasStartDatetime: datetime
32-
hasEndDatetime: datetime
33-
responsibleAgent: str
34-
usesAgriculturalMachinery: List[str]
39+
hasStartDatetime: Optional[datetime] = None
40+
hasEndDatetime: Optional[datetime] = None
41+
responsibleAgent: Optional[str] = None
42+
usesAgriculturalMachinery: List[dict] = []

app/schemas/irrigation.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from datetime import datetime
2-
from typing import List
2+
from typing import List, Optional
33

44
from pydantic import BaseModel, Field
55

@@ -16,13 +16,13 @@ class IrrigationOperation(BaseModel):
1616

1717
type: str = Field(alias="@type")
1818
id: str = Field(alias="@id")
19-
activityType: str
19+
activityType: dict
2020
title: str
2121
details: str
22-
hasStartDatetime: datetime
23-
hasEndDatetime: datetime
24-
responsibleAgent: str
25-
usesAgriculturalMachinery: List[str]
22+
hasStartDatetime: Optional[datetime] = None
23+
hasEndDatetime: Optional[datetime] = None
24+
responsibleAgent: Optional[str] = None
25+
usesAgriculturalMachinery: List[dict] = []
2626
hasAppliedAmount: QuantityValue
2727
usesIrrigationSystem: str
28-
operatedOn: str
28+
operatedOn: Optional[dict] = None

app/utils/animals_report.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def create_pdf_from_animals(animals: List[Animal]):
6565
pdf.cell(
6666
0,
6767
10,
68-
f"Created: {animal.dateCreated} | Modified: {animal.dateModified}",
68+
f"Created: {animal.dateCreated if animal.dateCreated else 'N/A'} | Modified: {animal.dateModified if animal.dateModified else 'N/A'}",
6969
ln=True,
7070
)
7171
pdf.ln(10)

app/utils/farm_calendar_report.py

Lines changed: 80 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,30 +61,96 @@ def create_farm_calendar_pdf(calendar_data: FarmCalendarData) -> EX:
6161

6262
pdf.set_font("FreeSerif", "", 9)
6363
pdf.multi_cell(0, 10, f"Details: {operation.details}", ln=True)
64-
pdf.cell(0, 10, f"Start: {operation.hasStartDatetime}", ln=True)
65-
pdf.cell(0, 10, f"End: {operation.hasEndDatetime}", ln=True)
66-
pdf.cell(0, 10, f"Responsible: {operation.responsibleAgent}", ln=True)
64+
65+
if operation.hasStartDatetime:
66+
pdf.cell(
67+
0,
68+
10,
69+
f"Start: {operation.hasStartDatetime}",
70+
ln=True,
71+
)
72+
73+
if operation.hasEndDatetime:
74+
pdf.cell(
75+
0,
76+
10,
77+
f"End: {operation.hasEndDatetime}",
78+
ln=True,
79+
)
80+
81+
(
82+
pdf.cell(0, 10, f"Responsible: {operation.responsibleAgent}", ln=True)
83+
if operation.responsibleAgent
84+
else None
85+
)
86+
pdf.cell(0, 10, f"Type: {operation.activityType.get('@id', 'N/A')}", ln=True)
6787

6888
if operation.usesAgriculturalMachinery:
69-
pdf.cell(0, 10, "Machinery:", ln=True)
70-
for machinery in operation.usesAgriculturalMachinery:
71-
pdf.cell(0, 10, f" - {machinery.split(':')[3]}", ln=True)
89+
machinery_ids = ", ".join(
90+
[
91+
machinery.get("@id", "N/A").split(":")[3]
92+
for machinery in operation.usesAgriculturalMachinery
93+
]
94+
)
95+
pdf.cell(0, 10, f"Machinery IDs: {machinery_ids}", ln=True)
7296

7397
for x in calendar_data.observations:
7498
pdf.set_font("FreeSerif", "B", 10)
7599
pdf.cell(0, 10, "Observations:", ln=True)
76100
pdf.set_font("FreeSerif", "", 10)
77-
pdf.cell(0, 10, f"Value: {x.hasValue}", ln=True)
78-
pdf.cell(0, 10, f"Property: {x.relatesToProperty}", ln=True)
101+
(
102+
pdf.cell(0, 10, f"Value: {x.hasResult.hasValue}", ln=True)
103+
if x.hasResult
104+
else None
105+
)
106+
(
107+
pdf.cell(0, 10, f"Value unit: {x.hasResult.unit}", ln=True)
108+
if x.hasResult
109+
else None
110+
)
111+
(
112+
pdf.cell(0, 10, f"Property: {x.relatesToProperty}", ln=True)
113+
if x.relatesToProperty
114+
else None
115+
)
116+
(
117+
pdf.cell(0, 10, f"Observed Property: {x.observedProperty}", ln=True)
118+
if x.observedProperty
119+
else None
120+
)
79121
pdf.cell(0, 10, f"Details: {x.details}", ln=True)
80-
pdf.cell(0, 10, f"Start: {x.hasStartDatetime}", ln=True)
81-
pdf.cell(0, 10, f"End: {x.hasEndDatetime}", ln=True)
82-
pdf.cell(0, 10, f"Responsible: {x.responsibleAgent}", ln=True)
122+
123+
if x.hasStartDatetime:
124+
pdf.cell(
125+
0,
126+
10,
127+
f"Start: {x.hasStartDatetime}",
128+
ln=True,
129+
)
130+
131+
if x.hasEndDatetime:
132+
pdf.cell(
133+
0,
134+
10,
135+
f"Start: {x.hasEndDatetime}",
136+
ln=True,
137+
)
138+
139+
(
140+
pdf.cell(0, 10, f"Responsible: {x.responsibleAgent}", ln=True)
141+
if x.responsibleAgent
142+
else None
143+
)
83144

84145
if x.usesAgriculturalMachinery:
85-
pdf.cell(0, 10, "Machinery:", ln=True)
86-
for machinery in operation.usesAgriculturalMachinery:
87-
pdf.cell(0, 10, f" - {machinery.split(':')[3]}", ln=True)
146+
machinery_ids = ", ".join(
147+
[
148+
machinery.get("@id", "N/A").split(":")[3]
149+
for machinery in x.usesAgriculturalMachinery
150+
]
151+
)
152+
pdf.cell(0, 10, f"Machinery IDs: {machinery_ids}", ln=True)
153+
88154
pdf.ln(10)
89155

90156
return pdf

app/utils/irrigation_report.py

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,11 @@
66
from utils import EX, add_fonts
77
from schemas.irrigation import *
88

9-
109
logging.basicConfig(level=logging.INFO)
1110
logger = logging.getLogger(__name__)
1211

1312

14-
def parse_irrigation_operations(
15-
data: dict,
16-
) -> Optional[List[IrrigationOperation]]:
13+
def parse_irrigation_operations(data: dict) -> Optional[List[IrrigationOperation]]:
1714
"""
1815
Parse list of irrigation operations from JSON data
1916
"""
@@ -48,32 +45,63 @@ def create_pdf_from_operations(operations: List[IrrigationOperation]):
4845
pdf.set_font("FreeSerif", "B", 9)
4946
pdf.cell(0, 10, f"Operation: {op.title}", ln=True)
5047

48+
# Activity Type
49+
activity_type = op.activityType.get(
50+
"@id", "N/A"
51+
) # You can adjust this to extract the specific part you need
52+
pdf.set_font("FreeSerif", "B", 9)
53+
pdf.cell(0, 10, f"Activity Type: {activity_type}", ln=True)
54+
5155
# Details
5256
pdf.set_font("FreeSerif", "", 9)
5357
pdf.multi_cell(0, 10, f"Details: {op.details}")
5458
pdf.ln(5)
5559

56-
pdf.cell(0, 10, f"Operated on Parcel: {op.operatedOn.split(':')[3]}", ln=True)
57-
pdf.cell(0, 10, f"Start: {op.hasStartDatetime}", ln=True)
58-
pdf.cell(0, 10, f"End: {op.hasEndDatetime}", ln=True)
60+
# Parcel ID extraction
61+
parcel_id = (
62+
op.operatedOn.get("@id", "N/A").split(":")[3] if op.operatedOn else "N/A"
63+
)
64+
pdf.cell(0, 10, f"Operated on Parcel: {parcel_id}", ln=True)
5965

66+
# Date and Time
67+
pdf.cell(
68+
0,
69+
10,
70+
f"Start: {op.hasStartDatetime if op.hasStartDatetime else 'N/A'}",
71+
ln=True,
72+
)
73+
pdf.cell(
74+
0, 10, f"End: {op.hasEndDatetime if op.hasEndDatetime else 'N/A'}", ln=True
75+
)
76+
77+
# Applied Amount
6078
pdf.cell(
6179
0,
6280
10,
6381
f"Applied Amount: {op.hasAppliedAmount.numericValue} {op.hasAppliedAmount.unit}",
6482
ln=True,
6583
)
6684

85+
# Irrigation System
6786
pdf.cell(0, 10, f"Irrigation System: {op.usesIrrigationSystem}", ln=True)
68-
pdf.cell(0, 10, f"Responsible Agent: {op.responsibleAgent}", ln=True)
6987

88+
# Responsible Agent
89+
pdf.cell(
90+
0,
91+
10,
92+
f"Responsible Agent: {op.responsibleAgent if op.responsibleAgent else 'N/A'}",
93+
ln=True,
94+
)
95+
96+
# Machinery IDs (if any)
7097
if op.usesAgriculturalMachinery:
71-
pdf.cell(
72-
0,
73-
10,
74-
f"Machinery IDs: {', '.join(op.usesAgriculturalMachinery).split(':')[3]}",
75-
ln=True,
98+
machinery_ids = ", ".join(
99+
[
100+
machinery.get("@id", "N/A").split(":")[3]
101+
for machinery in op.usesAgriculturalMachinery
102+
]
76103
)
104+
pdf.cell(0, 10, f"Machinery IDs: {machinery_ids}", ln=True)
77105

78106
pdf.ln(10)
79107

@@ -84,7 +112,6 @@ def process_irrigation_data(json_data: dict):
84112
"""
85113
Process irrigation data and generate PDF report
86114
"""
87-
88115
operations = parse_irrigation_operations(json_data)
89116

90117
if not operations:

0 commit comments

Comments
 (0)