Skip to content

Commit 96220b4

Browse files
committed
feat: expand well inventory CSV model with additional contact and well details
1 parent 897286c commit 96220b4

1 file changed

Lines changed: 131 additions & 17 deletions

File tree

api/well_inventory.py

Lines changed: 131 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,32 @@
2626
from sqlalchemy import select
2727

2828
from constants import SRID_UTM_ZONE_13N, SRID_UTM_ZONE_12N, SRID_WGS84
29-
from core.dependencies import session_dependency
30-
from core.enums import ContactType, Role, ElevationMethod
29+
from core.dependencies import session_dependency, amp_editor_dependency
30+
from core.enums import (
31+
ContactType,
32+
Role,
33+
ElevationMethod,
34+
WellPurpose as WellPurposeEnum,
35+
PhoneType,
36+
EmailType,
37+
AddressType,
38+
)
3139
from db import (
3240
Group,
3341
ThingIdLink,
3442
GroupThingAssociation,
3543
Location,
3644
LocationThingAssociation,
3745
)
38-
from db.thing import Thing
46+
from db.thing import Thing, WellPurpose
47+
from services.contact_helper import add_contact
3948
from services.util import transform_srid
4049

4150
router = APIRouter(prefix="/well-inventory-csv")
4251

4352

4453
class WellInventoryRow(BaseModel):
54+
# Required fields
4555
project: str
4656
well_name_point_id: str
4757
site_name: str
@@ -54,13 +64,63 @@ class WellInventoryRow(BaseModel):
5464
elevation_method: ElevationMethod
5565
measuring_point_height_ft: float
5666

57-
# Optional lexicon fields
67+
# Optional fields
68+
field_staff_2: Optional[str] = None
69+
field_staff_3: Optional[str] = None
70+
contact_name: Optional[str] = None
71+
contact_organization: Optional[str] = None
5872
contact_role: Optional[Role] = None
59-
contact_type: Optional[ContactType] = None
73+
contact_type: Optional[ContactType] = "Primary"
74+
contact_phone_1: Optional[str] = None
75+
contact_phone_1_type: Optional[PhoneType] = None
76+
contact_phone_2: Optional[str] = None
77+
contact_phone_2_type: Optional[PhoneType] = None
78+
contact_email_1: Optional[str] = None
79+
contact_email_1_type: Optional[EmailType] = None
80+
contact_email_2: Optional[str] = None
81+
contact_email_2_type: Optional[EmailType] = None
82+
contact_address_1_line_1: Optional[str] = None
83+
contact_address_1_line_2: Optional[str] = None
84+
contact_address_1_type: Optional[AddressType] = None
85+
contact_address_1_state: Optional[str] = None
86+
contact_address_1_city: Optional[str] = None
87+
contact_address_1_postal_code: Optional[str] = None
88+
contact_address_2_line_1: Optional[str] = None
89+
contact_address_2_line_2: Optional[str] = None
90+
contact_address_2_type: Optional[AddressType] = None
91+
contact_address_2_state: Optional[str] = None
92+
contact_address_2_city: Optional[str] = None
93+
contact_address_2_postal_code: Optional[str] = None
94+
directions_to_site: Optional[str] = None
95+
specific_location_of_well: Optional[str] = None
96+
repeat_measurement_permission: Optional[bool] = None
97+
sampling_permission: Optional[bool] = None
98+
datalogger_installation_permission: Optional[bool] = None
99+
public_availability_acknowledgement: Optional[bool] = None
100+
special_requests: Optional[str] = None
101+
ose_well_record_id: Optional[str] = None
102+
date_drilled: Optional[datetime] = None
103+
completion_source: Optional[str] = None
104+
total_well_depth_ft: Optional[float] = None
105+
historic_depth_to_water_ft: Optional[float] = None
106+
depth_source: Optional[str] = None
107+
well_pump_type: Optional[str] = None
108+
well_pump_depth_ft: Optional[float] = None
109+
is_open: Optional[bool] = None
110+
datalogger_possible: Optional[bool] = None
111+
casing_diameter_ft: Optional[float] = None
112+
measuring_point_description: Optional[str] = None
113+
well_purpose: Optional[WellPurposeEnum] = None
114+
well_hole_status: Optional[str] = None
115+
monitoring_frequency: Optional[str] = None
60116

61117

62118
@router.post("")
63-
async def well_inventory_csv(session: session_dependency, file: UploadFile = File(...)):
119+
async def well_inventory_csv(
120+
user: amp_editor_dependency,
121+
session: session_dependency,
122+
file: UploadFile = File(...),
123+
):
64124
if not file.content_type.startswith("text/csv") or not file.filename.endswith(
65125
".csv"
66126
):
@@ -90,7 +150,7 @@ async def well_inventory_csv(session: session_dependency, file: UploadFile = Fil
90150
raise ValueError("Duplicate value for well_name_point_id")
91151
seen_ids.add(well_id)
92152
model = WellInventoryRow(**row)
93-
models.append(model.model_dump())
153+
models.append(model)
94154

95155
except ValidationError as e:
96156
for err in e.errors():
@@ -110,7 +170,7 @@ def convert_f_to_m(r):
110170
return r * 0.3048
111171

112172
for project, items in groupby(
113-
sorted(models, key=lambda x: x["project"]), key=lambda x: x["project"]
173+
sorted(models, key=lambda x: x.project), key=lambda x: x.project
114174
):
115175
# get project and add if does not exist
116176
sql = select(Group).where(Group.name == project)
@@ -120,14 +180,14 @@ def convert_f_to_m(r):
120180
session.add(group)
121181

122182
for model in items:
123-
name = model.get("well_name_point_id")
124-
site_name = model.get("site_name")
125-
date_time = model.get("date_time")
183+
name = model.well_name_point_id
184+
site_name = model.site_name
185+
date_time = model.date_time
126186

127-
# field_staff: str
187+
# add field staff
128188

129-
point = Point(model.get("utm_easting"), model.get("utm_northing"))
130-
if model.get("utm_zone") == 13:
189+
point = Point(model.utm_easting, model.utm_northing)
190+
if model.utm_zone == 13:
131191
source_srid = SRID_UTM_ZONE_13N
132192
else:
133193
source_srid = SRID_UTM_ZONE_12N
@@ -136,10 +196,10 @@ def convert_f_to_m(r):
136196
transformed_point = transform_srid(
137197
point, source_srid=source_srid, target_srid=SRID_WGS84
138198
)
139-
elevation_ft = float(model.get("elevation_ft"))
199+
elevation_ft = float(model.elevation_ft)
140200
elevation_m = convert_f_to_m(elevation_ft)
141-
elevation_method = model.get("elevation_method")
142-
measuring_point_height_ft = model.get("measuring_point_height_ft")
201+
elevation_method = model.elevation_method
202+
measuring_point_height_ft = model.measuring_point_height_ft
143203

144204
loc = Location(
145205
point=transformed_point.wkt,
@@ -155,6 +215,9 @@ def convert_f_to_m(r):
155215
first_visit_date=date_time.date(),
156216
)
157217
session.add(well)
218+
if model.well_purpose:
219+
well_purpose = WellPurpose(purpose=model.well_purpose, thing=well)
220+
session.add(well_purpose)
158221

159222
assoc = LocationThingAssociation(location=loc, thing=well)
160223
assoc.effective_start = date_time
@@ -171,6 +234,57 @@ def convert_f_to_m(r):
171234
relation="same_as",
172235
)
173236
)
237+
session.flush()
238+
239+
# add contact
240+
emails = []
241+
phones = []
242+
addresses = []
243+
for i in (1, 2):
244+
email = getattr(model, f"contact_email_{i}")
245+
etype = getattr(model, f"contact_email_{i}_type")
246+
if email and etype:
247+
emails.append({"email": email, "email_type": etype})
248+
phone = getattr(model, f"contact_phone_{i}")
249+
ptype = getattr(model, f"contact_phone_{i}_type")
250+
if phone and ptype:
251+
phones.append({"phone_number": phone, "phone_type": ptype})
252+
253+
address_line_1 = getattr(model, f"contact_address_{i}_line_1")
254+
address_line_2 = getattr(model, f"contact_address_{i}_line_2")
255+
city = getattr(model, f"contact_address_{i}_city")
256+
state = getattr(model, f"contact_address_{i}_state")
257+
postal_code = getattr(model, f"contact_address_{i}_postal_code")
258+
address_type = getattr(model, f"contact_address_{i}_type")
259+
if address_line_1 and city and state and postal_code and address_type:
260+
addresses.append(
261+
{
262+
"address": {
263+
"address_line_1": address_line_1,
264+
"address_line_2": address_line_2,
265+
"city": city,
266+
"state": state,
267+
"postal_code": postal_code,
268+
"address_type": address_type,
269+
}
270+
}
271+
)
272+
273+
add_contact(
274+
session,
275+
{
276+
"thing_id": well.id,
277+
"name": model.contact_name,
278+
"organization": model.contact_organization,
279+
"role": model.contact_role,
280+
"contact_type": model.contact_type,
281+
"emails": emails,
282+
"phones": phones,
283+
"addresses": addresses,
284+
},
285+
user,
286+
)
287+
174288
session.commit()
175289

176290
if validation_errors:

0 commit comments

Comments
 (0)