Skip to content
Open
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
48 changes: 47 additions & 1 deletion spp_registrant_gis/models/res_partner.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Part of OpenSPP. See LICENSE file for full copyright and licensing details.
from odoo import fields, models
import json

from odoo import api, fields, models


class ResPartner(models.Model):
Expand All @@ -12,3 +14,47 @@ class ResPartner(models.Model):
help="Geographic coordinates (latitude/longitude) for spatial queries and mapping. "
"Used for proximity-based targeting and geographic analysis of registrants.",
)
# OP#1143: plain latitude/longitude inputs kept in sync with `coordinates`
# so the values can be entered (registry create, change requests) and
# imported without needing the MapTiler map widget configured. Editing the
# map updates these; editing these rebuilds the point.
gis_latitude = fields.Float(
string="Latitude",
digits=(9, 6),
compute="_compute_gis_lat_long",
inverse="_inverse_gis_lat_long",
store=True,
help="Latitude in decimal degrees (WGS84). Kept in sync with GPS Coordinates.",
)
gis_longitude = fields.Float(
string="Longitude",
digits=(9, 6),
compute="_compute_gis_lat_long",
inverse="_inverse_gis_lat_long",
store=True,
help="Longitude in decimal degrees (WGS84). Kept in sync with GPS Coordinates.",
)

@api.depends("coordinates")
def _compute_gis_lat_long(self):
"""Derive latitude/longitude from the point geometry (x=lon, y=lat)."""
for rec in self:
geom = rec.coordinates
if geom and not geom.is_empty and getattr(geom, "geom_type", None) == "Point":
rec.gis_longitude = geom.x
rec.gis_latitude = geom.y
else:
rec.gis_longitude = 0.0
rec.gis_latitude = 0.0

def _inverse_gis_lat_long(self):
"""Rebuild the point geometry when latitude/longitude are entered.

Both values are taken from the record, so filling either field commits
the current pair. (0, 0) is treated as "unset" and clears the point.
"""
for rec in self:
if rec.gis_latitude or rec.gis_longitude:
rec.coordinates = json.dumps({"type": "Point", "coordinates": [rec.gis_longitude, rec.gis_latitude]})
else:
rec.coordinates = False
22 changes: 22 additions & 0 deletions spp_registrant_gis/tests/test_registrant_gis.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,25 @@ def test_coordinates_empty_by_default(self):

# Coordinates should be False/empty by default
self.assertFalse(registrant.coordinates)

# ── OP#1143: visible latitude/longitude inputs synced with coordinates ──
def test_lat_long_computed_from_coordinates(self):
"""Setting coordinates populates the latitude/longitude inputs."""
registrant = self.partner_model.create({"name": "LatLong From Point", "is_registrant": True})
registrant.write({"coordinates": json.dumps({"type": "Point", "coordinates": [121.5, 14.25]})})
self.assertAlmostEqual(registrant.gis_longitude, 121.5, places=5)
self.assertAlmostEqual(registrant.gis_latitude, 14.25, places=5)

def test_coordinates_built_from_lat_long(self):
"""Typing latitude/longitude rebuilds the coordinates point."""
group = self.partner_model.create({"name": "LatLong Group", "is_registrant": True, "is_group": True})
group.write({"gis_latitude": 8.5, "gis_longitude": 124.75})
self.assertTrue(group.coordinates)
self.assertAlmostEqual(group.coordinates.x, 124.75, places=5) # x = longitude
self.assertAlmostEqual(group.coordinates.y, 8.5, places=5) # y = latitude

def test_lat_long_empty_when_no_coordinates(self):
"""With no point set, the latitude/longitude inputs read as 0."""
registrant = self.partner_model.create({"name": "No Coords", "is_registrant": True})
self.assertEqual(registrant.gis_latitude, 0.0)
self.assertEqual(registrant.gis_longitude, 0.0)
10 changes: 10 additions & 0 deletions spp_registrant_gis/views/res_partner_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
>
<separator string="Location" />
<group name="gis_section">
<!-- OP#1143: visible latitude/longitude inputs so the
coordinates can be typed in without the map widget;
they stay in sync with GPS Coordinates below. -->
<field name="gis_latitude" readonly="disabled" />
<field name="gis_longitude" readonly="disabled" />
<field name="coordinates" readonly="disabled" widget="geo_point" />
</group>
</xpath>
Expand All @@ -33,6 +38,11 @@
>
<separator string="Location" />
<group name="group_gis_section">
<!-- OP#1143: visible latitude/longitude inputs so the
coordinates can be typed in without the map widget;
they stay in sync with GPS Coordinates below. -->
<field name="gis_latitude" readonly="disabled" />
<field name="gis_longitude" readonly="disabled" />
<field name="coordinates" readonly="disabled" widget="geo_point" />
</group>
</xpath>
Expand Down
Loading