Files
repair/odoo/addons/dsrpt_repair_config/models/fsm_zone.py

99 lines
3.4 KiB
Python

import json
from odoo import api, fields, models
from odoo.exceptions import ValidationError
class RepairFsmZone(models.Model):
_name = "repair.fsm.zone"
_description = "FSM Zone"
_order = "name"
_inherit = ["mail.thread", "mail.activity.mixin"]
name = fields.Char(required=True, tracking=True)
polygon_geojson = fields.Text(
string="Polygon (GeoJSON)",
required=True,
tracking=True,
help="GeoJSON Polygon geometry. Coordinates order: [longitude, latitude].",
)
state = fields.Selection(
selection=[
("active", "Active"),
("archived", "Archived"),
],
default="active",
tracking=True,
)
mapbox_token = fields.Char(compute="_compute_mapbox_token")
@api.depends_context("uid")
def _compute_mapbox_token(self):
token = self.env["ir.config_parameter"].sudo().get_param("dsrpt_repair_config.mapbox_token") or ""
for rec in self:
rec.mapbox_token = token
@staticmethod
def _point_in_polygon(longitude, latitude, points):
inside = False
j = len(points) - 1
for i, (xi, yi) in enumerate(points):
xj, yj = points[j]
intersects = ((yi > latitude) != (yj > latitude)) and (
longitude < (xj - xi) * (latitude - yi) / ((yj - yi) or 1e-12) + xi
)
if intersects:
inside = not inside
j = i
return inside
def _extract_polygon_points(self):
self.ensure_one()
if not self.polygon_geojson:
raise ValidationError("Polygon is required.")
try:
data = json.loads(self.polygon_geojson or "")
except json.JSONDecodeError as exc:
raise ValidationError(f"Invalid GeoJSON: {exc.msg}") from exc
ring = []
if isinstance(data, dict):
if data.get("type") == "Feature":
data = data.get("geometry") or {}
if data.get("type") != "Polygon":
raise ValidationError("GeoJSON must be of type Polygon.")
coords = data.get("coordinates") or []
if not coords or not isinstance(coords[0], list):
raise ValidationError("Polygon coordinates are missing.")
ring = coords[0]
elif isinstance(data, list):
ring = data
else:
raise ValidationError("Polygon must be a GeoJSON object or an array of points.")
points = []
for pair in ring:
if not isinstance(pair, (list, tuple)) or len(pair) < 2:
raise ValidationError("Each polygon point must be [longitude, latitude].")
points.append((float(pair[0]), float(pair[1])))
if len(points) >= 2 and points[0] == points[-1]:
points = points[:-1]
if len(points) < 3:
raise ValidationError("Polygon must contain at least 3 points.")
return points
def contains_point(self, latitude, longitude):
self.ensure_one()
if latitude is None or longitude is None:
return False
if not self.polygon_geojson:
return False
points = self._extract_polygon_points()
return self._point_in_polygon(float(longitude), float(latitude), points)
@api.constrains("polygon_geojson")
def _check_polygon_geojson(self):
for rec in self:
rec._extract_polygon_points()