Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions core/lexicon.json
Original file line number Diff line number Diff line change
Expand Up @@ -335,12 +335,18 @@
{"categories": ["status_type"], "term": "Well Status", "definition": "Defines the well's operational condition as reported by the owner"},
{"categories": ["status_type"], "term": "Monitoring Status", "definition": "Defines the well's current monitoring status by NMBGMR."},
{"categories": ["status_type"], "term": "Access Status", "definition": "Defines the well's access status for field personnel."},
{"categories": ["status_type"], "term": "Open Status", "definition": "Defines if the well is open or closed"},
{"categories": ["status_type"], "term": "Datalogger Suitability Status", "definition": "Defines if a datalogger can or cannot be installed at the well"},
{"categories": ["status_value"], "term": "Abandoned", "definition": "The well has been properly decommissioned."},
{"categories": ["status_value"], "term": "Active, pumping well", "definition": "This well is in use."},
{"categories": ["status_value"], "term": "Destroyed, exists but not usable", "definition": "The well structure is physically present but is damaged, collapsed, or otherwise compromised to the point that it is non-functional."},
{"categories": ["status_value"], "term": "Inactive, exists but not used", "definition": "The well is not currently in use but is believed to be in a usable condition; it has not been permanently decommissioned/abandoned."},
{"categories": ["status_value"], "term": "Currently monitored", "definition": "The well is currently being monitored by AMMP."},
{"categories": ["status_value"], "term": "Not currently monitored", "definition": "The well is not currently being monitored by AMMP."},
{"categories": ["status_value"], "term": "Open", "definition": "The well is open."},
{"categories": ["status_value"], "term": "Closed", "definition": "The well is closed."},
{"categories": ["status_value"], "term": "Datalogger can be installed", "definition": "A datalogger can be installed at the well"},
{"categories": ["status_value"], "term": "Datalogger cannot be installed", "definition": "A datalogger cannot be installed at the well"},
{"categories": ["sample_method"], "term": "Airline measurement", "definition": "Airline measurement"},
{"categories": ["sample_method"], "term": "Analog or graphic recorder", "definition": "Analog or graphic recorder"},
{"categories": ["sample_method"], "term": "Calibrated airline measurement", "definition": "Calibrated airline measurement"},
Expand Down
26 changes: 26 additions & 0 deletions db/thing.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,32 @@ def monitoring_status(self) -> str | None:
)
return latest_status.status_value if latest_status else None

@property
def open_status(self) -> str | None:
"""
Returns the open status from the most recent status history entry
where status_type is "Open Status".

Since status_history is eagerly loaded, this should not introduce N+1 query issues.
"""
latest_status = retrieve_latest_polymorphic_history_table_record(
self, "status_history", "Open Status"
)
return latest_status.status_value if latest_status else None

@property
def datalogger_suitability_status(self) -> str | None:
"""
Returns the datalogger installation status from the most recent status history entry
where status_type is "Datalogger Suitability Status".

Since status_history is eagerly loaded, this should not introduce N+1 query issues.
"""
latest_status = retrieve_latest_polymorphic_history_table_record(
self, "status_history", "Datalogger Suitability Status"
)
return latest_status.status_value if latest_status else None

@property
def measuring_point_height(self) -> int | None:
"""
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ services:
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_HOST=db
- POSTGRES_PORT=5432
- MODE=${MODE}
- AUTHENTIK_DISABLE_AUTHENTICATION=${AUTHENTIK_DISABLE_AUTHENTICATION}
ports:
Expand Down
4 changes: 2 additions & 2 deletions schemas/thing.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ 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
formation_completion_code: FormationCode | None = None


Expand Down Expand Up @@ -238,8 +237,9 @@ class WellResponse(BaseThingResponse):
well_pump_type: WellPumpType | None
well_pump_depth: float | None
well_pump_depth_unit: str = "ft"
is_suitable_for_datalogger: bool | None
well_status: str | None
open_status: str | None
datalogger_suitability_status: str | None
measuring_point_height: float
measuring_point_height_unit: str = "ft"
measuring_point_description: str | None
Expand Down
29 changes: 23 additions & 6 deletions tests/features/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,9 +501,9 @@ def add_geologic_formation(context, session, formation_code, well):
def before_all(context):
context.objects = {}

rebuild = False
rebuild = True
# rebuild = True
erase_data = True
erase_data = False
if rebuild:
erase_and_rebuild_db()
elif erase_data:
Expand Down Expand Up @@ -581,14 +581,31 @@ def before_all(context):
target_table="thing",
)

for value, start, end in (
("Currently monitored", datetime(2020, 1, 1), datetime(2021, 1, 1)),
("Not currently monitored", datetime(2021, 1, 1), None),
for value, status_type, start, end in (
(
"Currently monitored",
"Monitoring Status",
datetime(2020, 1, 1),
datetime(2021, 1, 1),
),
(
"Not currently monitored",
"Monitoring Status",
datetime(2021, 1, 1),
None,
),
("Open", "Open Status", datetime(2020, 1, 1), None),
(
"Datalogger can be installed",
"Datalogger Suitability Status",
datetime(2020, 1, 1),
None,
),
):
add_status_history(
context,
session,
status_type="Monitoring Status",
status_type=status_type,
status_value=value,
start_date=start,
end_date=end,
Expand Down
11 changes: 8 additions & 3 deletions tests/features/steps/well-additional-information.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,15 @@ def step_impl(context):
"the response should include whether the well is open and suitable for a datalogger"
)
def step_impl(context):
assert "is_suitable_for_datalogger" in context.water_well_data
assert "datalogger_installation_status" in context.water_well_data
assert "open_status" in context.water_well_data
assert (
context.water_well_data["is_suitable_for_datalogger"]
== context.objects["wells"][0].is_suitable_for_datalogger
context.water_well_data["datalogger_installation_status"]
== context.objects["wells"][0].datalogger_installation_status
)
assert (
context.water_well_data["open_status"]
== context.objects["wells"][0].open_status
)


Expand Down
42 changes: 36 additions & 6 deletions transfers/well_transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,6 @@ def _step(self, session: Session, df: pd.DataFrame, i: int, row: pd.Series):
row, f"LU_ConstructionMethod:{row.ConstructionMethod}", "Unknown"
)

is_suitable_for_datalogger = False
if notna(row.OpenWellLoggerOK):
is_suitable_for_datalogger = bool(row.OpenWellLoggerOK)

mpheight = row.MPHeight
mpheight_description = row.MeasuringPoint
if mpheight is None:
Expand Down Expand Up @@ -321,7 +317,6 @@ def _step(self, session: Session, df: pd.DataFrame, i: int, row: pd.Series):
well_driller_name=row.DrillerName,
well_construction_method=wcm,
well_pump_type=well_pump_type,
is_suitable_for_datalogger=is_suitable_for_datalogger,
)

CreateWell.model_validate(data)
Expand Down Expand Up @@ -425,6 +420,9 @@ def _extract_well_purposes(self, row) -> list[str]:
else:
purposes = []
for cui in cu:
if cui == "A":
# skip "Open, unequipped well" as that gets mapped to the status_history table
continue
p = self._get_lexicon_value(row, f"LU_CurrentUse:{cui}")
if p is not None:
purposes.append(p)
Expand Down Expand Up @@ -819,7 +817,6 @@ def _after_hook_chunk(self, well, formations):
)

if notna(row.Status):

status_value = self._get_lexicon_value(row, f"LU_Status:{row.Status}")
if status_value is not None:
status_history = StatusHistory(
Expand All @@ -835,6 +832,39 @@ def _after_hook_chunk(self, well, formations):
logger.info(
f" Added well status for well {well.name}: {status_value}"
)

if notna(row.OpenWellLoggerOK):
if bool(row.OpenWellLoggerOK):
status_value = "Datalogger can be installed"
else:
status_value = "Datalogger cannot be installed"
status_history = StatusHistory(
status_type="Datalogger Suitability Status",
status_value=status_value,
reason=None,
start_date=datetime.now(tz=UTC),
target_id=target_id,
target_table=target_table,
)
objs.append(status_history)
if self.verbose:
logger.info(
f" Added datalogger suitability status for well {well.name}: {status_value}"
)

if notna(row.CurrentUse) and "A" in row.CurrentUse:
status_history = StatusHistory(
status_type="Open Status",
status_value="Open",
reason=None,
start_date=datetime.now(tz=UTC),
target_id=target_id,
target_table=target_table,
)
objs.append(status_history)
if self.verbose:
logger.info(f" Added open open status for well {well.name}")

return objs


Expand Down
Loading