From ced10b947629847e94cbd12c8b45225eeae94041 Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Wed, 19 Nov 2025 16:56:06 -0700 Subject: [PATCH 01/13] feat: transfer water level sample permissions --- schemas/thing.py | 2 +- transfers/permissions_transfer.py | 52 +++++++++++++++++++++++++++++++ transfers/transfer.py | 4 +++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 transfers/permissions_transfer.py diff --git a/schemas/thing.py b/schemas/thing.py index 50f56e7c4..a8cac2523 100644 --- a/schemas/thing.py +++ b/schemas/thing.py @@ -130,7 +130,7 @@ class CreateWell(CreateBaseThing, ValidateWell): measuring_point_height: float = Field( ge=0, description="Measuring point height in feet" ) - measuring_point_description: str | None + measuring_point_description: str | None = None notes: list[CreateNote] | None = None diff --git a/transfers/permissions_transfer.py b/transfers/permissions_transfer.py new file mode 100644 index 000000000..e1f7bd069 --- /dev/null +++ b/transfers/permissions_transfer.py @@ -0,0 +1,52 @@ +from sqlalchemy.orm import Session +from datetime import datetime + +from db import Thing, PermissionHistory +from transfers.util import read_csv, logger, replace_nans + + +def transfer_permissions(session: Session): + """ + The transferred wells and contacts need to be queried to know who gave + permission to which well since contact_id is required for PermissionHistory + """ + wdf = read_csv("WellData", dtype={"OSEWelltagID": str}) + wdf = replace_nans(wdf) + + transferred_wells = ( + session.query(Thing).filter(Thing.thing_type == "water well").all() + ) + + for well in transferred_wells: + if len(well.contacts) == 0: + logger.critical( + f"Well {well.name} has no associated contacts; skipping permission transfer." + ) + continue + else: + # Assuming the first contact is the relevant one + contact_id = well.contacts[0].id + + allow_water_level_samples = wdf.loc[ + wdf["PointID"] == well.name, "MonitorOK" + ].values + if len(allow_water_level_samples) > 0 and allow_water_level_samples is not None: + try: + permission_allowed = bool(allow_water_level_samples[0]) + permission = PermissionHistory( + contact_id=contact_id, + permission_type="Water Level Sample", + permission_allowed=permission_allowed, + start_date=datetime.today().date(), + target_id=well.id, + target_table="thing", + ) + session.add(permission) + logger.info( + f"Transferred Water Level Sample permission for well {well.name}: {permission_allowed}." + ) + except Exception as e: + logger.error(f"Error transferring permission for well {well.name}: {e}") + session.rollback() + continue + session.commit() diff --git a/transfers/transfer.py b/transfers/transfer.py index 77275ed35..2b576a4b2 100644 --- a/transfers/transfer.py +++ b/transfers/transfer.py @@ -36,6 +36,7 @@ transfer_wells, transfer_wellscreens, ) +from transfers.permissions_transfer import transfer_permissions from transfers.asset_transfer import transfer_assets from transfers.util import timeit, timeit_direct @@ -124,6 +125,9 @@ def transfer_all(sess, limit=100): message("TRANSFERRING ASSETS") timeit_direct(transfer_assets, sess) + message("TRANSFERRING PERMISSIONS") + results = timeit_direct(transfer_permissions, sess) + def transfer_debugging(sess, limit=100): message("STARTING TRANSFER DEBUG", new_line_at_top=False) From e48b71eea39c1ccb83bdf0d2581feb1296fc49b0 Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Thu, 20 Nov 2025 08:13:43 -0700 Subject: [PATCH 02/13] feat: transfer permissions from legacy db --- transfers/permissions_transfer.py | 55 ++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/transfers/permissions_transfer.py b/transfers/permissions_transfer.py index e1f7bd069..d07c2cbe2 100644 --- a/transfers/permissions_transfer.py +++ b/transfers/permissions_transfer.py @@ -48,5 +48,58 @@ def transfer_permissions(session: Session): except Exception as e: logger.error(f"Error transferring permission for well {well.name}: {e}") session.rollback() - continue + pass + + allow_water_chemistry_samples = wdf.loc[ + wdf["PointID"] == well.name, "SampleOK" + ].values + if ( + len(allow_water_chemistry_samples) > 0 + and allow_water_chemistry_samples is not None + ): + try: + permission_allowed = bool(allow_water_chemistry_samples[0]) + permission = PermissionHistory( + contact_id=contact_id, + permission_type="Water Chemistry Sample", + permission_allowed=permission_allowed, + start_date=datetime.today().date(), + target_id=well.id, + target_table="thing", + ) + session.add(permission) + logger.info( + f"Transferred Water Chemistry Sample permission for well {well.name}: {permission_allowed}." + ) + except Exception as e: + logger.error(f"Error transferring permission for well {well.name}: {e}") + session.rollback() + pass + + allow_datalogger_installation = wdf.loc[ + wdf["PointID"] == well.name, "OpenWellLoggerOK" + ].values + if ( + len(allow_datalogger_installation) > 0 + and allow_datalogger_installation is not None + ): + try: + permission_allowed = bool(allow_datalogger_installation[0]) + permission = PermissionHistory( + contact_id=contact_id, + permission_type="Datalogger Installation", + permission_allowed=permission_allowed, + start_date=datetime.today().date(), + target_id=well.id, + target_table="thing", + ) + session.add(permission) + logger.info( + f"Transferred Datalogger Installation permission for well {well.name}: {permission_allowed}." + ) + except Exception as e: + logger.error(f"Error transferring permission for well {well.name}: {e}") + session.rollback() + pass + session.commit() From 171b41b6da02d35b850aa9deec50e9daa4977040 Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Thu, 20 Nov 2025 10:44:20 -0700 Subject: [PATCH 03/13] feat: transfer well construction information --- schemas/thing.py | 3 +++ transfers/well_transfer.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/schemas/thing.py b/schemas/thing.py index a8cac2523..2438c50c4 100644 --- a/schemas/thing.py +++ b/schemas/thing.py @@ -132,6 +132,9 @@ class CreateWell(CreateBaseThing, ValidateWell): ) measuring_point_description: str | None = None notes: list[CreateNote] | None = None + well_completion_date: PastOrTodayDate | None = None + well_driller_name: str | None = None + well_construction_method: WellConstructionMethod | None = None class CreateSpring(CreateBaseThing): diff --git a/transfers/well_transfer.py b/transfers/well_transfer.py index ee54d0216..d2cb4b186 100644 --- a/transfers/well_transfer.py +++ b/transfers/well_transfer.py @@ -257,6 +257,9 @@ def transfer_wells(session: Session, flags: dict = None, limit: int = 0) -> None notes=( [{"content": row.Notes, "note_type": "Other"}] if row.Notes else [] ), + well_completion_date=row.CompletionDate, + well_driller_name=row.DrillerName, + well_construction_method=row.ConstructionMethod, ) CreateWell.model_validate(data) From a9cec8ad1c9359351517ccf3820b23f4f88a7468 Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Thu, 20 Nov 2025 12:32:13 -0700 Subject: [PATCH 04/13] WIP: transfers for well additional info --- schemas/thing.py | 2 ++ transfers/well_transfer.py | 53 ++++++++++++++++++++++++++++---------- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/schemas/thing.py b/schemas/thing.py index 2438c50c4..b23ae7d4f 100644 --- a/schemas/thing.py +++ b/schemas/thing.py @@ -133,8 +133,10 @@ class CreateWell(CreateBaseThing, ValidateWell): measuring_point_description: str | None = None notes: list[CreateNote] | None = None well_completion_date: PastOrTodayDate | None = None + well_completion_date_source: str | None = None well_driller_name: str | None = None well_construction_method: WellConstructionMethod | None = None + well_construction_method_source: str | None = None class CreateSpring(CreateBaseThing): diff --git a/transfers/well_transfer.py b/transfers/well_transfer.py index d2cb4b186..e41cf789a 100644 --- a/transfers/well_transfer.py +++ b/transfers/well_transfer.py @@ -36,6 +36,7 @@ StatusHistory, MonitoringFrequencyHistory, MeasuringPointHistory, + DataProvenance, ) from schemas.thing import CreateWell, CreateWellScreen from services.gcs_helper import get_storage_bucket @@ -280,6 +281,8 @@ def transfer_wells(session: Session, flags: dict = None, limit: int = 0) -> None "well_casing_materials", "measuring_point_height", "measuring_point_description", + "well_completion_date_source", + "well_construction_method_source", ] ) well_data["thing_type"] = "water well" @@ -288,17 +291,6 @@ def transfer_wells(session: Session, flags: dict = None, limit: int = 0) -> None well_data.pop("notes") well = Thing(**well_data) session.add(well) - # logger.info(f"Created well for {row.PointID}") - - # flush well to access its ID for status_history - # session.flush() - - # session.commit() - # session.refresh(well) - # if notes: - # for ni in notes: - # nn = well.add_note(ni['content'], ni['note_type']) - # session.add(nn) if well_purposes: for wp in well_purposes: @@ -350,11 +342,44 @@ def transfer_wells(session: Session, flags: dict = None, limit: int = 0) -> None for dp in data_provenances: session.add(dp) + if not isna(row.CompletionSource): + dp = DataProvenance( + target_id=well.id, + target_table="thing", + field_name="well_completion_date", + origin_source=lexicon_mapper.map_value( + f"LU_Depth_CompletionSource:{row.CompletionSource}" + ), + ) + session.add(dp) + + if not isna(row.DataSource): + dp = DataProvenance( + target_id=well.id, + target_table="thing", + field_name="well_construction_method", + origin_source=lexicon_mapper.map_value( + f"LU_DataSource:{row.DataSource}" + ), + ) + session.add(dp) + + if not isna(row.DepthSource): + dp = DataProvenance( + target_id=well.id, + target_table="thing", + field_name="well_depth", + origin_source=lexicon_mapper.map_value( + f"LU_Depth_CompletionSource:{row.DepthSource}" + ), + ) + session.add(dp) + """ - Developer's note + Developer's note - It's not clear when the measuring point from NM_Aquifer was - determined, so I'm setting start_date to the day of the transfer + It's not clear when the measuring point from NM_Aquifer was + determined, so I'm setting start_date to the day of the transfer """ measuring_point_history = MeasuringPointHistory( thing_id=well.id, From 75265f335802dd267342d07387049b030ca9c18c Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Thu, 20 Nov 2025 13:56:23 -0700 Subject: [PATCH 05/13] feat: transfer well source information --- transfers/util.py | 1 - transfers/well_transfer.py | 16 ++++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/transfers/util.py b/transfers/util.py index cbf0f2b17..c4b423250 100644 --- a/transfers/util.py +++ b/transfers/util.py @@ -369,7 +369,6 @@ def make_location_data_provenance( target_id=location.id, target_table="location", field_name="point", - origin_source=None, collection_method=coordinate_method, accuracy_value=accuracy_value, accuracy_unit=accuracy_unit, diff --git a/transfers/well_transfer.py b/transfers/well_transfer.py index e41cf789a..2c0073f03 100644 --- a/transfers/well_transfer.py +++ b/transfers/well_transfer.py @@ -260,7 +260,13 @@ def transfer_wells(session: Session, flags: dict = None, limit: int = 0) -> None ), well_completion_date=row.CompletionDate, well_driller_name=row.DrillerName, - well_construction_method=row.ConstructionMethod, + well_construction_method=( + lexicon_mapper.map_value( + f"LU_ConstructionMethod:{row.ConstructionMethod}" + ) + if not isna(row.ConstructionMethod) + else None + ), ) CreateWell.model_validate(data) @@ -347,7 +353,7 @@ def transfer_wells(session: Session, flags: dict = None, limit: int = 0) -> None target_id=well.id, target_table="thing", field_name="well_completion_date", - origin_source=lexicon_mapper.map_value( + origin_type=lexicon_mapper.map_value( f"LU_Depth_CompletionSource:{row.CompletionSource}" ), ) @@ -358,9 +364,7 @@ def transfer_wells(session: Session, flags: dict = None, limit: int = 0) -> None target_id=well.id, target_table="thing", field_name="well_construction_method", - origin_source=lexicon_mapper.map_value( - f"LU_DataSource:{row.DataSource}" - ), + origin_source=row.DataSource, ) session.add(dp) @@ -369,7 +373,7 @@ def transfer_wells(session: Session, flags: dict = None, limit: int = 0) -> None target_id=well.id, target_table="thing", field_name="well_depth", - origin_source=lexicon_mapper.map_value( + origin_type=lexicon_mapper.map_value( f"LU_Depth_CompletionSource:{row.DepthSource}" ), ) From 2b90f869e6cdb633750f9f41cee9011a8471e9df Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Thu, 20 Nov 2025 14:00:30 -0700 Subject: [PATCH 06/13] feat: add Quemado Mutual Water and Sewage Works Association to organizations for contacts --- core/lexicon.json | 1 + transfers/data/owners_organization_mapper.json | 1 + 2 files changed, 2 insertions(+) diff --git a/core/lexicon.json b/core/lexicon.json index ba4fd8f7e..46033eee5 100644 --- a/core/lexicon.json +++ b/core/lexicon.json @@ -574,6 +574,7 @@ {"categories": ["organization"], "term": "Yates Petroleum Corporation", "definition": "Yates Petroleum Corporation"}, {"categories": ["organization"], "term": "Zamora Accounting Services", "definition": "Zamora Accounting Services"}, {"categories": ["organization"], "term": "PLSS", "definition": "Public Land Survey System"}, + {"categories": ["organization"], "term": "Quemado Municipal Water & SWA", "definition": "Quemado Municipal Water & SWA"}, {"categories": ["collection_method"], "term": "Altimeter", "definition": "ALtimeter"}, {"categories": ["collection_method"], "term": "Differentially corrected GPS", "definition": "Differentially corrected GPS"}, {"categories": ["collection_method"], "term": "Survey-grade GPS", "definition": "Survey-grade GPS"}, diff --git a/transfers/data/owners_organization_mapper.json b/transfers/data/owners_organization_mapper.json index 5ce45a8bf..b4f29bd7b 100644 --- a/transfers/data/owners_organization_mapper.json +++ b/transfers/data/owners_organization_mapper.json @@ -89,6 +89,7 @@ "Pecos Trail Inn": "Pecos Trail Inn", "Pelican Spa": "Pelican Spa", "Pistachio Tree Ranch": "Pistachio Tree Ranch", + "Quemado Mutual Water and Sewage Works Association": "Quemado Municipal Water & SWA", "Rancho Encantado": "Rancho Encantado", "Rancho San Lucas": "Rancho San Lucas", "Rancho San Marcos": "Rancho San Marcos", From cf72461be26acf99f7b682f8b5d30cd709fa6169 Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Thu, 20 Nov 2025 14:20:26 -0700 Subject: [PATCH 07/13] fix: remove erroneous or check --- transfers/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/transfers/util.py b/transfers/util.py index c4b423250..9b2afc84c 100644 --- a/transfers/util.py +++ b/transfers/util.py @@ -275,7 +275,7 @@ def make_location_data_provenance( ) -> list[DataProvenance]: provenance_records = [] - if row.AltitudeAccuracy or row.CoordinateAccuracy: + if row.AltitudeAccuracy: provenance = DataProvenance( target_id=location.id, target_table="location", From 58b92f884bd7165c029dd15be7635911070f7175 Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Fri, 21 Nov 2025 11:53:18 -0700 Subject: [PATCH 08/13] feat: transfer well pump type parse the construction notes field to get pump types. this can be more sophisticated, but that's a future problem. for now just check for some basic pump type string patterns --- core/lexicon.json | 4 ++-- schemas/thing.py | 1 + transfers/well_transfer.py | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/core/lexicon.json b/core/lexicon.json index 46033eee5..21666bccd 100644 --- a/core/lexicon.json +++ b/core/lexicon.json @@ -714,9 +714,9 @@ {"categories": ["note_type"], "term": "Water", "definition": "Water bearing zone information and other info from ose reports"}, {"categories": ["note_type"], "term": "Measuring", "definition": "Notes about measuring/visiting the well, on Access form"}, {"categories": ["well_pump_type"], "term": "Submersible", "definition": "Submersible"}, - {"categories": ["well_pump_type"], "term": "Jet Pump", "definition": "Jet Pump"}, + {"categories": ["well_pump_type"], "term": "Jet", "definition": "Jet Pump"}, {"categories": ["well_pump_type"], "term": "Line Shaft", "definition": "Line Shaft"}, - {"categories": ["well_pump_type"], "term": "Hand Pump", "definition": "Hand Pump"}, + {"categories": ["well_pump_type"], "term": "Hand", "definition": "Hand Pump"}, {"categories": ["permission_type"], "term": "Water Level Sample", "definition": "Permissions for taking water level samples"}, {"categories": ["permission_type"], "term": "Water Chemistry Sample", "definition": "Permissions for water taking chemistry samples"}, {"categories": ["permission_type"], "term": "Datalogger Installation", "definition": "Permissions for installing dataloggers"} diff --git a/schemas/thing.py b/schemas/thing.py index b23ae7d4f..48c055cd8 100644 --- a/schemas/thing.py +++ b/schemas/thing.py @@ -137,6 +137,7 @@ class CreateWell(CreateBaseThing, ValidateWell): well_driller_name: str | None = None well_construction_method: WellConstructionMethod | None = None well_construction_method_source: str | None = None + well_pump_type: WellPumpType | None = None class CreateSpring(CreateBaseThing): diff --git a/transfers/well_transfer.py b/transfers/well_transfer.py index 2c0073f03..346d91629 100644 --- a/transfers/well_transfer.py +++ b/transfers/well_transfer.py @@ -118,6 +118,21 @@ def _extract_casing_materials(row) -> list[str]: return materials +def _extract_well_pump_type(row) -> str | None: + construction_notes = row.ConstructionNotes.lower() + if "pump" in construction_notes: + if "submersible" in construction_notes: + return "Submersible" + elif "jet" in construction_notes: + return "Jet" + elif "line shaft" in construction_notes or "lineshaft" in construction_notes: + return "Line Shaft" + elif "hand" in construction_notes: + return "Hand" + else: + return None + + def get_wells_to_transfer( sess: Session, flags: dict = None ) -> tuple[pd.DataFrame, pd.DataFrame]: @@ -237,6 +252,9 @@ def transfer_wells(session: Session, flags: dict = None, limit: int = 0) -> None well_casing_materials = ( [] if isna(row.CasingDescription) else _extract_casing_materials(row) ) + well_pump_type = ( + _extract_well_pump_type(row) if row.ConstructionNotes else None + ) # manually add the well rather than add_well from services/thing_helper.py # so that effective_start can be set on the location assocation @@ -267,6 +285,7 @@ def transfer_wells(session: Session, flags: dict = None, limit: int = 0) -> None if not isna(row.ConstructionMethod) else None ), + well_pump_type=well_pump_type, ) CreateWell.model_validate(data) From 4e9876e1f23369283ba9588c834c6d54b5744ef6 Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Fri, 21 Nov 2025 11:55:58 -0700 Subject: [PATCH 09/13] fix: change Air-rotary to Air-Rotary to correspond with lu table This can be updated later on but should be "Air-Rotary" for the transfer --- core/lexicon.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lexicon.json b/core/lexicon.json index 21666bccd..5821330b5 100644 --- a/core/lexicon.json +++ b/core/lexicon.json @@ -81,7 +81,7 @@ {"categories": ["elevation_method"], "term": "Survey-grade Global Navigation Satellite Sys, Lvl1", "definition": "Survey-grade Global Navigation Satellite Sys, Lvl1"}, {"categories": ["elevation_method"], "term": "USGS National Elevation Dataset (NED)", "definition": "USGS National Elevation Dataset (NED)"}, {"categories": ["elevation_method", "sample_method", "coordinate_method", "well_purpose", "status", "organization", "role"], "term": "Unknown", "definition": "Unknown"}, - {"categories": ["well_construction_method"], "term": "Air-rotary", "definition": "Air-rotary"}, + {"categories": ["well_construction_method"], "term": "Air-Rotary", "definition": "Air-Rotary"}, {"categories": ["well_construction_method"], "term": "Bored or augered", "definition": "Bored or augered"}, {"categories": ["well_construction_method"], "term": "Cable-tool", "definition": "Cable-tool"}, {"categories": ["well_construction_method"], "term": "Hydraulic rotary (mud or water)", "definition": "Hydraulic rotary (mud or water)"}, From fbfa9089c29e9539025cec8cb8bf60195fb0520b Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Mon, 24 Nov 2025 16:20:35 -0700 Subject: [PATCH 10/13] fix: remove duplicate well pump types in lexicon this was an artifact from merge conflicts --- core/lexicon.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/lexicon.json b/core/lexicon.json index 990a5d657..8ef165e1a 100644 --- a/core/lexicon.json +++ b/core/lexicon.json @@ -699,10 +699,6 @@ {"categories": ["monitoring_frequency"], "term": "Annual", "definition": "Location is monitored once a year."}, {"categories": ["monitoring_frequency"], "term": "Decadal", "definition": "Location is monitored once every ten years."}, {"categories": ["monitoring_frequency"], "term": "Event-based", "definition": "Location is monitored based on specific events or triggers rather than a fixed schedule."}, - {"categories": ["well_pump_type"], "term": "Submersible", "definition": "Submersible"}, - {"categories": ["well_pump_type"], "term": "Jet Pump", "definition": "Jet Pump"}, - {"categories": ["well_pump_type"], "term": "Line Shaft", "definition": "Line Shaft"}, - {"categories": ["well_pump_type"], "term": "Hand Pump", "definition": "Hand Pump"}, {"categories": ["aquifer_type"], "term": "Artesian", "definition": "Artesian"}, {"categories": ["aquifer_type"], "term": "Confined, single", "definition": "Confined single aquifer"}, {"categories": ["aquifer_type"], "term": "Confined, multiple", "definition": "Confined multiple aquifers"}, From e6af5e6aefe3452881fc078d6615a0b2caf66a35 Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Mon, 24 Nov 2025 16:42:50 -0700 Subject: [PATCH 11/13] fix: use OpenWellLoggerOK for is_suitable_for_datalogger field Laila indicated that this just describes if a datalogger can be physically installed at the well. It does not pertain to permissions --- schemas/thing.py | 1 + transfers/permissions_transfer.py | 34 ++++++++----------------------- transfers/well_transfer.py | 5 +++++ 3 files changed, 14 insertions(+), 26 deletions(-) diff --git a/schemas/thing.py b/schemas/thing.py index 977bf0c45..07e7e93ce 100644 --- a/schemas/thing.py +++ b/schemas/thing.py @@ -144,6 +144,7 @@ class CreateWell(CreateBaseThing, ValidateWell): well_construction_method: WellConstructionMethod | None = None well_construction_method_source: str | None = None well_pump_type: WellPumpType | None = None + is_suitable_for_datalogger: bool | None = None class CreateSpring(CreateBaseThing): diff --git a/transfers/permissions_transfer.py b/transfers/permissions_transfer.py index d07c2cbe2..1dcca2b8f 100644 --- a/transfers/permissions_transfer.py +++ b/transfers/permissions_transfer.py @@ -4,6 +4,14 @@ from db import Thing, PermissionHistory from transfers.util import read_csv, logger, replace_nans +""" +Developer's notes + +According to Laila the column WellData.OpenWellLoggerOK only pertains to the +physical properties of a well (that is, if a datalogger can be installed). It +does not pertain to permissions. +""" + def transfer_permissions(session: Session): """ @@ -76,30 +84,4 @@ def transfer_permissions(session: Session): session.rollback() pass - allow_datalogger_installation = wdf.loc[ - wdf["PointID"] == well.name, "OpenWellLoggerOK" - ].values - if ( - len(allow_datalogger_installation) > 0 - and allow_datalogger_installation is not None - ): - try: - permission_allowed = bool(allow_datalogger_installation[0]) - permission = PermissionHistory( - contact_id=contact_id, - permission_type="Datalogger Installation", - permission_allowed=permission_allowed, - start_date=datetime.today().date(), - target_id=well.id, - target_table="thing", - ) - session.add(permission) - logger.info( - f"Transferred Datalogger Installation permission for well {well.name}: {permission_allowed}." - ) - except Exception as e: - logger.error(f"Error transferring permission for well {well.name}: {e}") - session.rollback() - pass - session.commit() diff --git a/transfers/well_transfer.py b/transfers/well_transfer.py index 346d91629..9e684cc8d 100644 --- a/transfers/well_transfer.py +++ b/transfers/well_transfer.py @@ -286,6 +286,11 @@ def transfer_wells(session: Session, flags: dict = None, limit: int = 0) -> None else None ), well_pump_type=well_pump_type, + is_suitable_for_datalogger=( + bool(row.OpenWellLoggerOK) + if not isna(row.OpenWellLoggerOK) + else None + ), ) CreateWell.model_validate(data) From d3c8101cf156c7608752bbaa943881c5a8057755 Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Mon, 24 Nov 2025 17:00:14 -0700 Subject: [PATCH 12/13] feat: update CreateWell for transfers --- schemas/thing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schemas/thing.py b/schemas/thing.py index 07e7e93ce..1baf324c3 100644 --- a/schemas/thing.py +++ b/schemas/thing.py @@ -144,7 +144,7 @@ class CreateWell(CreateBaseThing, ValidateWell): well_construction_method: WellConstructionMethod | None = None well_construction_method_source: str | None = None well_pump_type: WellPumpType | None = None - is_suitable_for_datalogger: bool | None = None + is_suitable_for_datalogger: bool | None class CreateSpring(CreateBaseThing): From 2ea4cb16d9f8b896b23dc59eddc3ed916dedd434 Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Tue, 25 Nov 2025 07:57:26 -0700 Subject: [PATCH 13/13] fix: return aquifer/geology str instead of full response the well screen response includes the aquifer and geology information, but just as strings of names and codes instead of the full nested response objects. --- schemas/thing.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/schemas/thing.py b/schemas/thing.py index 1baf324c3..77df8c316 100644 --- a/schemas/thing.py +++ b/schemas/thing.py @@ -33,11 +33,6 @@ from schemas.group import GroupResponse from schemas.location import LocationGeoJSONResponse from schemas.notes import NoteResponse, CreateNote -from schemas.aquifer_system import AquiferSystemGeoJSONResponse - -# from schemas.geologic_formation import ( -# GeologicFormationResponse, -# ) # -------- VALIDATE ---------- @@ -308,10 +303,10 @@ class WellScreenResponse(BaseResponseModel): thing_id: int thing: WellResponse aquifer_system_id: int | None = None - aquifer_system: AquiferSystemGeoJSONResponse | None = None + aquifer_system: str | None = None aquifer_type: str | None = None geologic_formation_id: int | None = None - # geologic_formation: GeologicFormationResponse | None = None + geologic_formation: str | None = None screen_depth_bottom: float screen_depth_bottom_unit: str = "ft" screen_depth_top: float @@ -319,6 +314,24 @@ class WellScreenResponse(BaseResponseModel): screen_type: str | None = None screen_description: str | None = None + @field_validator("aquifer_system", mode="before") + def populate_aquifer_system_with_name(cls, aquifer_system): + if aquifer_system is not None: + return aquifer_system.name + return None + + @field_validator("aquifer_type", mode="before") + def populate_aquifer_type_with_name(cls, aquifer_type): + if aquifer_type is not None: + return aquifer_type.name + return None + + @field_validator("geologic_formation_id", mode="before") + def populate_geologic_formation_with_code(cls, geologic_formation): + if geologic_formation is not None: + return geologic_formation.formation_code + return None + class GeoJSONGeometry(BaseModel): """