2626from sqlalchemy import select
2727
2828from 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+ )
3139from 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
3948from services .util import transform_srid
4049
4150router = APIRouter (prefix = "/well-inventory-csv" )
4251
4352
4453class 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