Skip to content
Merged
3 changes: 2 additions & 1 deletion core/lexicon.json
Original file line number Diff line number Diff line change
Expand Up @@ -1166,9 +1166,10 @@
{"categories": ["note_type"], "term": "Construction", "definition": "Construction details, well development, drilling notes, etc. Could create separate `types` for each of these if needed."},
{"categories": ["note_type"], "term": "Maintenance", "definition": "Maintenance observations and issues."},
{"categories": ["note_type"], "term": "Historical", "definition": "Historical information or context about the well or location."},
{"categories": ["note_type"], "term": "Other", "definition": "Other types of notes that do not fit into the predefined categories."},
{"categories": ["note_type"], "term": "General", "definition": "Other types of notes that do not fit into the predefined categories."},
{"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": ["note_type"], "term": "Coordinate", "definition": "Notes about a location's coordinates"},
{"categories": ["well_pump_type"], "term": "Submersible", "definition": "Submersible"},
{"categories": ["well_pump_type"], "term": "Jet", "definition": "Jet Pump"},
{"categories": ["well_pump_type"], "term": "Line Shaft", "definition": "Line Shaft"},
Expand Down
12 changes: 7 additions & 5 deletions db/thing.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# ===============================================================================
from typing import List, TYPE_CHECKING
from datetime import date
from sqlalchemy import Integer, ForeignKey, String, Column, Float, Text, Date
from sqlalchemy import Integer, ForeignKey, String, Column, Float, Date
from sqlalchemy.ext.associationproxy import association_proxy, AssociationProxy
from sqlalchemy.orm import relationship, mapped_column, Mapped
from sqlalchemy_utils import TSVectorType
Expand Down Expand Up @@ -117,8 +117,6 @@ class Thing(
comment="Depth of the well casing from ground surface to the bottom of the casing (in feet).",
)

well_construction_notes: Mapped[str] = mapped_column(Text, nullable=True)

well_completion_date: Mapped[date] = mapped_column(
nullable=True, comment="the date the well was completed if known"
)
Expand Down Expand Up @@ -348,7 +346,7 @@ class Thing(
)

# Full-text search vector
search_vector = Column(TSVectorType("name", "well_construction_notes"))
search_vector = Column(TSVectorType("name"))

@property
def current_location(self):
Expand All @@ -372,12 +370,16 @@ def water_notes(self):

@property
def general_notes(self):
return self._get_notes("Other")
return self._get_notes("General")
Comment on lines 371 to +373

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge General notes exclude existing "Other" entries

The general_notes accessor now only returns notes whose note_type is "General". Existing data and fixtures created before this rename still store general notes as "Other" (e.g., prior transfers and tests), and there is no migration or fallback here, so those notes will silently disappear from general_notes in API responses after this change. Please either migrate existing note records or have this accessor include both "General" and legacy "Other" note types.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the transfer is run again the database will be wiped and there will be no "Other" notes, so this isn't an issue.


@property
def measuring_notes(self):
return self._get_notes("Measuring")

@property
def construction_notes(self):
return self._get_notes("Construction")

@property
def well_status(self) -> str | None:
"""
Expand Down
9 changes: 3 additions & 6 deletions schemas/thing.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ class CreateWell(CreateBaseThing, ValidateWell):
hole_depth: float | None = Field(
default=None, gt=0, description="Hole depth in feet"
)
well_construction_notes: str | None = None
well_casing_diameter: float | None = Field(
default=None, gt=0, description="Well casing diameter in inches"
)
Expand Down Expand Up @@ -194,13 +193,11 @@ class BaseThingResponse(BaseResponseModel):
thing_type: str
current_location: LocationGeoJSONResponse
first_visit_date: PastOrTodayDate | None
# The new relationship to the polymorphic Notes table
notes: List[NoteResponse] = []

groups: list[GroupResponse] = []
monitoring_status: str | None
links: list[ThingIdLinkResponse] = Field(default=[], alias="alternate_ids")
monitoring_frequencies: list[MonitoringFrequencyResponse] = []
general_notes: list[NoteResponse] | None = None

@field_validator("monitoring_frequencies", mode="before")
def remove_records_with_end_date(cls, monitoring_frequencies):
Expand Down Expand Up @@ -233,7 +230,6 @@ class WellResponse(BaseThingResponse):
well_casing_depth: float | None = None
well_casing_depth_unit: str = "ft"
well_casing_materials: list[CasingMaterial] = []
well_construction_notes: str | None = None
well_completion_date: PastOrTodayDate | None
well_completion_date_source: str | None
well_driller_name: str | None
Expand All @@ -250,7 +246,8 @@ class WellResponse(BaseThingResponse):
aquifers: list[dict] = []
water_notes: list[NoteResponse] | None = None
measuring_notes: list[NoteResponse] | None = None
general_notes: list[NoteResponse] | None = None

construction_notes: list[NoteResponse] | None = None
permissions: list[PermissionHistoryResponse]
formation_completion_code: FormationCode | None

Expand Down
1 change: 0 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ def water_well_thing(location):
release_status="draft",
well_depth=10,
hole_depth=10,
well_construction_notes="Test well construction notes",
well_casing_diameter=5.0,
well_casing_depth=10.0,
)
Expand Down
6 changes: 3 additions & 3 deletions tests/features/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def add_location(context, session):
session.add(loc)
session.commit()
session.refresh(loc)
n = loc.add_note("Test location", "Other")
n = loc.add_note("Test location", "General")
session.add(n)
session.commit()
session.refresh(loc)
Expand All @@ -92,7 +92,6 @@ def add_well(context, session, location, name_num):
release_status="draft",
well_depth=10,
hole_depth=10,
well_construction_notes="Test well construction notes",
well_casing_diameter=5.0,
well_casing_depth=10.0,
well_completion_date="2013-05-15",
Expand All @@ -114,9 +113,10 @@ def add_well(context, session, location, name_num):
session.refresh(well)

for nt, c in (
("Other", "well notes"),
("General", "well notes"),
("Water", "water notes"),
("Measuring", "measuring notes"),
("Construction", "construction notes"),
):
n = well.add_note(c, nt)
session.add(n)
Expand Down
23 changes: 23 additions & 0 deletions tests/features/geojson-response.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Created by jakeross at 10/22/25
@backend @production
Feature: Geojson Response
# Enter feature description here
Background:
Given a functioning api
And the system has valid well and location data in the database

@positive @happy_path
Scenario: Request all wells as geojson
When the user requests all the wells as geojson
Then the system should return a 200 status code
And the system should return a response in GEOJSON format
And the response should be a feature collection
And the feature collection should have 3 features

@positive @happy_path
Scenario: Request all wells in a group as geojson
When the user requests all the wells for group Collabnet
Then the system should return a 200 status code
And the system should return a response in GEOJSON format
And the response should be a feature collection
And the feature collection should have 2 features
30 changes: 30 additions & 0 deletions tests/features/location-notes.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Created by jakeross at 10/21/25
@backend @BDMS-199 @production
Feature: Retrieve location notes by well name
As a user
I want to retrieve location notes for a given well name
So that I can view important information about the well's location
Background:
Given a functioning api
And the system has valid well and location data in the database

@positive @happy_path
Scenario: Retrieve location notes for an existing well
When the user retrieves the well by ID via path parameter
Then the system should return a 200 status code
And the system should return a response in JSON format
And the response should include a current location
And the current location should include notes
And the notes should be a list of dictionaries
And each note dictionary should have "content" and "note_type" keys
And each note in the notes list should be a non-empty string

@positive @happy_path
Scenario: Retrieve location notes by location ID
When the user retrieves the location by ID via path parameter
Then the system should return a 200 status code
And the system should return a response in JSON format
And the location response should include notes
And the notes should be a list of dictionaries
And each note dictionary should have "content" and "note_type" keys
And each note in the notes list should be a non-empty string
44 changes: 44 additions & 0 deletions tests/features/search-response.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
@backend @BDMS-169
Feature: Unified search API returns grouped results
As a user
I want to search for contacts, wells, and springs
So that I can quickly find relevant information across multiple data types

Background:
Given a functioning api
And the system has valid contact, well, and spring records in the database

@positive @happy_path
Scenario: Retrieve mixed search results
When the user searches for "<search_term>"
Then the system should return a 200 status code
And the system should return a response in JSON format
And the response should include results grouped by:
| Contacts | Wells | Springs |
And each result should include a label, group, and properties

@positive @happy_path
Scenario: Retrieve contact results
When the user searches for "<contact_search_term>"
Then the system should return a 200 status code
And the response should include a "Contacts" group
And each contact result should include:
#| TODO: use correct field name syntax |
| id | first_name | last_name | email | phone | address | associated_things |

@positive @happy_path
Scenario: Retrieve well results
When the user searches for "<well_search_term>"
Then the system should return a 200 status code
And the response should include a "Wells" group
And each well result should include:
#| TODO: use correct field name syntax |
| thing_type | id | name | alternate site name | contact first name | contact last name | contact id | county |

@positive @happy_path
Scenario: Retrieve spring results
When the user searches for "<spring_search_term>"
Then the system should return a 200 status code
And the response should include a "Springs" group
And each spring result should include:
| thing_type | id |
39 changes: 39 additions & 0 deletions tests/features/sensor-notes.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Created by jakeross at 10/21/25
@backend @BDMS-199
Feature: Retrieve sensor notes
As a user
I want to retrieve sensor notes for a given well name
So that I can view important information about the well's deployed sensors
Background:
Given a functioning api
And the system has valid well and location data in the database

# @positive @happy_path
# Scenario: Request sensor notes for an existing well
# When the user requests the sensor for well 1
# Then the system should return a 200 status code
# And the system should return a response in JSON format
# And the response should include notes
# And the notes should be a non-empty string

@positive
Scenario: Request sensor notes by sensor ID
When the user requests the sensor with ID 1
Then the system should return a 200 status code
And the system should return a response in JSON format
And the response should include notes
And the notes should be a non-empty string

@negative
Scenario: Request sensor notes for a non-existing sensor ID
When the user requests the sensor with ID 9999
Then the system should return a 404 status code
And the system should return a response in JSON format
And the response should include an error message indicating the sensor was not found

# @negative @sad_path
# Scenario: Request sensor notes for a non-existing well
# When the user requests the sensor for well 9999
# Then the system should return a 404 status code
# And the system should return a response in JSON format
# And the response should include an error message indicating the well was not found
14 changes: 6 additions & 8 deletions tests/features/steps/well-notes.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,17 @@ def step_impl(context):
)
def step_impl(context):
data = context.response.json()
assert (
"well_construction_notes" in data
), "Response does not include construction notes"
assert data["well_construction_notes"] is not None, "Construction notes is null"
context.notes["construction"] = data["well_construction_notes"]
assert "construction_notes" in data, "Response does not include construction notes"
assert data["construction_notes"] is not None, "Construction notes is null"
context.notes["construction"] = data["construction_notes"]


@then("the response should include general well notes (catch all notes field)")
def step_impl(context):
data = context.response.json()
assert "notes" in data, "Response does not include notes"
assert data["notes"] is not None, "Notes is null"
context.notes["general"] = data["notes"]
assert "general_notes" in data, "Response does not include notes"
assert data["general_notes"] is not None, "Notes is null"
context.notes["general"] = data["general_notes"]


@then(
Expand Down
24 changes: 24 additions & 0 deletions tests/features/thing-query-parameters.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Created by jakeross at 11/2/25
@backend @BDMS-218 @production
Feature: Thing query paramaters
Use query parameters to filter things
Background:
Given a functioning api
And the system has valid well and location data in the database

@positive @happy_path
Scenario: Filter things by type
When the user requests things with type "water well"
Then the system should return a 200 status code
And the system should return a response in JSON format
And the response should include at least one thing
And the response should only include things of type "water well"

@positive @happy_path
Scenario:
When the user requests things with type "spring"
Then the system should return a 200 status code
And the system should return a response in JSON format
And the response should include at least one thing
And the response should only include things of type "spring"

24 changes: 24 additions & 0 deletions tests/features/thing-type-path-parameters.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Created by jakeross at 11/2/25
@backend @BDMS-218 @production
Feature: Thing type path paramaters
Use path parameters to filter things
Background:
Given a functioning api
And the system has valid well and location data in the database

@positive @happy_path
Scenario: Get all Water Well Things
When the user requests things with type "water well"
Then the system should return a 200 status code
And the system should return a response in JSON format
And the response should include at least one thing
And the response should only include things of type "water well"

@positive @happy_path
Scenario:
When the user requests things with type "spring"
Then the system should return a 200 status code
And the system should return a response in JSON format
And the response should include at least one thing
And the response should only include things of type "spring"

30 changes: 30 additions & 0 deletions tests/features/transducer-data-response.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Created by jakeross at 11/4/25
@backend @production
Feature: Transducer Data Response
This feature tests the API's ability to retrieve transducer data for wells.
Background:
Given a functioning api
And the system has valid well and transducer data in the database

@positive @happy_path
Scenario: Retrieve transducer data for an existing well
When the user requests transducer data for a well
Then the system should return a 200 status code
And the system should return a response in JSON format

And the response should be paginated
And each page should be an array of transducer data
And each transducer data entry should include a timestamp, value, status
And the timestamp should be in ISO 8601 format
And the value should be a numeric type
And the status should be one of "approved", "not reviewed"



@negative @sad_path
Scenario: Retrieve transducer data for a non-existing well
When the user requests transducer data for a non-existing well
Then the system should return a 200 status code
And the system should return a response in JSON format
And the response should be paginated
And the items should be an empty list
Loading
Loading