From 644448658498f73a244132ef3730944a8ef0cac4 Mon Sep 17 00:00:00 2001 From: Shayan Mouktar <119674649+Shayan105@users.noreply.github.com> Date: Wed, 26 Nov 2025 17:32:44 +0100 Subject: [PATCH 01/17] [FIX] Add obfuscated location to the project model --- child_compassion/models/project_compassion.py | 42 +++++++++++++++++++ .../models/compassion_project.py | 20 +++++++++ 2 files changed, 62 insertions(+) diff --git a/child_compassion/models/project_compassion.py b/child_compassion/models/project_compassion.py index d4c2f7f5d..af4c7c03b 100644 --- a/child_compassion/models/project_compassion.py +++ b/child_compassion/models/project_compassion.py @@ -85,6 +85,8 @@ class CompassionProject(models.Model): zip_code = fields.Char(readonly=True) gps_latitude = fields.Float(readonly=True) gps_longitude = fields.Float(readonly=True) + gps_latitude_obfuscated = fields.Float(readonly=True) + gps_longitude_obfuscated = fields.Float(readonly=True) google_link = fields.Char(readonly=True, compute="_compute_google_link") timezone = fields.Char(readonly=True, compute="_compute_timezone", store=True) cluster = fields.Char(readonly=True) @@ -510,6 +512,46 @@ def _get_materials(self): ("Plastic", _("Plastic")), ] + def update_obfuscated_coordinates(self): + api_key = self.env["ir.config_parameter"].sudo().get_param( + "google_maps_api_key") + if not api_key: + return + + base_url = "https://maps.googleapis.com/maps/api/geocode/json" + + for project in self: + # Check if we already have coords to avoid wasting API calls + if project.gps_latitude_obfuscated or project.gps_longitude_obfuscated: + continue + + # Build the list of available address parts + parts = [ + project.closest_city, + project.state_province, + project.country_id.name + ] + address_string = ", ".join(filter(None, parts)) + if not address_string: + continue + params = { + "address": address_string, + "key": api_key + } + + try: + response = requests.get(base_url, params=params) + data = response.json() + + if data["status"] == "OK": + location = data["results"][0]["geometry"]["location"] + project.gps_latitude_obfuscated = location["lat"] + project.gps_longitude_obfuscated = location["lng"] + else: + logging.error(f"Geocoding error for {project.id}: {data['status']}") + + except Exception as e: + logging.error(f"Request failed: {e}") @api.depends("gps_longitude", "gps_latitude") def _compute_timezone(self): tf = TimezoneFinder() diff --git a/mobile_app_connector/models/compassion_project.py b/mobile_app_connector/models/compassion_project.py index 0c5cb2dae..39f8ee56b 100644 --- a/mobile_app_connector/models/compassion_project.py +++ b/mobile_app_connector/models/compassion_project.py @@ -29,6 +29,26 @@ def get_location_json(self, multi=False): data = self[:1].data_to_json("mobile_app_project") return data + + + def get_obfuscated_coordinates_json(self): + """ + Return the obfuscated coordinates in a json format + :return: dictionary with JSON data of the obfuscated coordinates + """ + self.update_obfuscated_coordinates() + + if not self.gps_latitude_obfuscated or not self.gps_longitude_obfuscated: + return { + "Latitude": int(self.gps_latitude), + "Longitude": int(self.gps_longitude_obfuscated), + } + + return { + "Latitude": self.gps_latitude_obfuscated, + "Longitude": self.gps_longitude_obfuscated, + } + def get_weather_json(self, multi=False): if not self: return {} From 6db1890aa3d909399ac61ed4f662aafc3b70a7bb Mon Sep 17 00:00:00 2001 From: Shayan Mouktar <119674649+Shayan105@users.noreply.github.com> Date: Wed, 26 Nov 2025 17:47:39 +0100 Subject: [PATCH 02/17] [STYLE] Add comments --- child_compassion/models/project_compassion.py | 21 ++++++++++++------- .../models/compassion_project.py | 10 ++++----- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/child_compassion/models/project_compassion.py b/child_compassion/models/project_compassion.py index af4c7c03b..013cbd75f 100644 --- a/child_compassion/models/project_compassion.py +++ b/child_compassion/models/project_compassion.py @@ -513,8 +513,17 @@ def _get_materials(self): ] def update_obfuscated_coordinates(self): - api_key = self.env["ir.config_parameter"].sudo().get_param( - "google_maps_api_key") + """ + Update obfuscated coordinates using Google Maps Geocoding API. + 1. Check if API key is configured. + 2. If the current project has no obfuscated coordinates, build the address str. + 3. Make a request to Google Maps Geocoding API. + 4. If successful, update the obfuscated coordinates. + Used in compassion-modules/mobile_app_connector/models/compassion_project.py + """ + api_key = ( + self.env["ir.config_parameter"].sudo().get_param("google_maps_api_key") + ) if not api_key: return @@ -529,15 +538,12 @@ def update_obfuscated_coordinates(self): parts = [ project.closest_city, project.state_province, - project.country_id.name + project.country_id.name, ] address_string = ", ".join(filter(None, parts)) if not address_string: continue - params = { - "address": address_string, - "key": api_key - } + params = {"address": address_string, "key": api_key} try: response = requests.get(base_url, params=params) @@ -552,6 +558,7 @@ def update_obfuscated_coordinates(self): except Exception as e: logging.error(f"Request failed: {e}") + @api.depends("gps_longitude", "gps_latitude") def _compute_timezone(self): tf = TimezoneFinder() diff --git a/mobile_app_connector/models/compassion_project.py b/mobile_app_connector/models/compassion_project.py index 39f8ee56b..eba1035d6 100644 --- a/mobile_app_connector/models/compassion_project.py +++ b/mobile_app_connector/models/compassion_project.py @@ -29,15 +29,15 @@ def get_location_json(self, multi=False): data = self[:1].data_to_json("mobile_app_project") return data - - def get_obfuscated_coordinates_json(self): """ Return the obfuscated coordinates in a json format :return: dictionary with JSON data of the obfuscated coordinates + If the obfuscated coordinates are not available, return the integer part of the real coordinates + This gives a rough location without revealing the exact position (100km precision) """ self.update_obfuscated_coordinates() - + # If the obfuscated coord. are not available, return the integer part. if not self.gps_latitude_obfuscated or not self.gps_longitude_obfuscated: return { "Latitude": int(self.gps_latitude), @@ -45,8 +45,8 @@ def get_obfuscated_coordinates_json(self): } return { - "Latitude": self.gps_latitude_obfuscated, - "Longitude": self.gps_longitude_obfuscated, + "Latitude": self.gps_latitude_obfuscated, + "Longitude": self.gps_longitude_obfuscated, } def get_weather_json(self, multi=False): From 860c19e158e4c11851e9be5fa7841db644918eba Mon Sep 17 00:00:00 2001 From: Shayan Mouktar <119674649+Shayan105@users.noreply.github.com> Date: Thu, 27 Nov 2025 09:38:07 +0100 Subject: [PATCH 03/17] [STYLE] Refactor comments --- mobile_app_connector/models/compassion_project.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mobile_app_connector/models/compassion_project.py b/mobile_app_connector/models/compassion_project.py index eba1035d6..e8024032c 100644 --- a/mobile_app_connector/models/compassion_project.py +++ b/mobile_app_connector/models/compassion_project.py @@ -33,8 +33,9 @@ def get_obfuscated_coordinates_json(self): """ Return the obfuscated coordinates in a json format :return: dictionary with JSON data of the obfuscated coordinates - If the obfuscated coordinates are not available, return the integer part of the real coordinates - This gives a rough location without revealing the exact position (100km precision) + If the obfuscated coordinates are not available, return the integer part of the + real coordinates + This gives a rough location without revealing the exact position (100km accur.) """ self.update_obfuscated_coordinates() # If the obfuscated coord. are not available, return the integer part. From 392226b365aac80bb20b59bf6a2d2da6fa9b0067 Mon Sep 17 00:00:00 2001 From: Shayan Mouktar <119674649+Shayan105@users.noreply.github.com> Date: Thu, 27 Nov 2025 09:52:21 +0100 Subject: [PATCH 04/17] [FIX] Add timeout for the geocode API request --- child_compassion/models/project_compassion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/child_compassion/models/project_compassion.py b/child_compassion/models/project_compassion.py index 013cbd75f..06ff93ab1 100644 --- a/child_compassion/models/project_compassion.py +++ b/child_compassion/models/project_compassion.py @@ -546,7 +546,7 @@ def update_obfuscated_coordinates(self): params = {"address": address_string, "key": api_key} try: - response = requests.get(base_url, params=params) + response = requests.get(base_url, params=params, timeout=10) data = response.json() if data["status"] == "OK": From bea08c7da8661455ffcefa6c2a6333d1e117f467 Mon Sep 17 00:00:00 2001 From: Shayan Mouktar <119674649+Shayan105@users.noreply.github.com> Date: Thu, 27 Nov 2025 09:52:49 +0100 Subject: [PATCH 05/17] [FIX] Fix typos --- mobile_app_connector/models/compassion_project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile_app_connector/models/compassion_project.py b/mobile_app_connector/models/compassion_project.py index e8024032c..813f10110 100644 --- a/mobile_app_connector/models/compassion_project.py +++ b/mobile_app_connector/models/compassion_project.py @@ -42,7 +42,7 @@ def get_obfuscated_coordinates_json(self): if not self.gps_latitude_obfuscated or not self.gps_longitude_obfuscated: return { "Latitude": int(self.gps_latitude), - "Longitude": int(self.gps_longitude_obfuscated), + "Longitude": int(self.gps_longitude), } return { From 0cf7de9fd2804d40a6eddf379d641f6ddd94b821 Mon Sep 17 00:00:00 2001 From: Shayan Mouktar <119674649+Shayan105@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:09:10 +0100 Subject: [PATCH 06/17] Update child_compassion/models/project_compassion.py Co-authored-by: ecino --- child_compassion/models/project_compassion.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/child_compassion/models/project_compassion.py b/child_compassion/models/project_compassion.py index 06ff93ab1..e6483b0af 100644 --- a/child_compassion/models/project_compassion.py +++ b/child_compassion/models/project_compassion.py @@ -512,7 +512,8 @@ def _get_materials(self): ("Plastic", _("Plastic")), ] - def update_obfuscated_coordinates(self): + @api.onchange("gps_latitude", "gps_longitude") + def _compute_gps_obfuscated(self): """ Update obfuscated coordinates using Google Maps Geocoding API. 1. Check if API key is configured. From 2129d78e680e2f5c855ddf9e4a9dceb0b10780d2 Mon Sep 17 00:00:00 2001 From: Shayan Mouktar <119674649+Shayan105@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:09:55 +0100 Subject: [PATCH 07/17] [T2792][FIX] Make obfuscated coord computed fields Co-authored-by: ecino --- child_compassion/models/project_compassion.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/child_compassion/models/project_compassion.py b/child_compassion/models/project_compassion.py index e6483b0af..28e02232c 100644 --- a/child_compassion/models/project_compassion.py +++ b/child_compassion/models/project_compassion.py @@ -85,8 +85,8 @@ class CompassionProject(models.Model): zip_code = fields.Char(readonly=True) gps_latitude = fields.Float(readonly=True) gps_longitude = fields.Float(readonly=True) - gps_latitude_obfuscated = fields.Float(readonly=True) - gps_longitude_obfuscated = fields.Float(readonly=True) + gps_latitude_obfuscated = fields.Float(compute="_compute_gps_obfuscated") + gps_longitude_obfuscated = fields.Float(compute="_compute_gps_obfuscated") google_link = fields.Char(readonly=True, compute="_compute_google_link") timezone = fields.Char(readonly=True, compute="_compute_timezone", store=True) cluster = fields.Char(readonly=True) From 62a085533526a0ab75381d1e9faafb319370140c Mon Sep 17 00:00:00 2001 From: Shayan Mouktar <119674649+Shayan105@users.noreply.github.com> Date: Thu, 8 Jan 2026 14:57:25 +0100 Subject: [PATCH 08/17] [T2792][FIX] Make the obfuscated coords computed fields --- child_compassion/models/project_compassion.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/child_compassion/models/project_compassion.py b/child_compassion/models/project_compassion.py index 28e02232c..3cef4b006 100644 --- a/child_compassion/models/project_compassion.py +++ b/child_compassion/models/project_compassion.py @@ -85,8 +85,12 @@ class CompassionProject(models.Model): zip_code = fields.Char(readonly=True) gps_latitude = fields.Float(readonly=True) gps_longitude = fields.Float(readonly=True) - gps_latitude_obfuscated = fields.Float(compute="_compute_gps_obfuscated") - gps_longitude_obfuscated = fields.Float(compute="_compute_gps_obfuscated") + gps_latitude_obfuscated = fields.Float( + compute="_compute_gps_obfuscated", store=True + ) + gps_longitude_obfuscated = fields.Float( + compute="_compute_gps_obfuscated", store=True + ) google_link = fields.Char(readonly=True, compute="_compute_google_link") timezone = fields.Char(readonly=True, compute="_compute_timezone", store=True) cluster = fields.Char(readonly=True) From b1b6fcb9333fffc1b424f7389adfb7ae9c7a76e9 Mon Sep 17 00:00:00 2001 From: Shayan Mouktar <119674649+Shayan105@users.noreply.github.com> Date: Thu, 8 Jan 2026 14:57:28 +0100 Subject: [PATCH 09/17] [T2792][STYLE] Add comments --- child_compassion/models/project_compassion.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/child_compassion/models/project_compassion.py b/child_compassion/models/project_compassion.py index 3cef4b006..a3f3e931a 100644 --- a/child_compassion/models/project_compassion.py +++ b/child_compassion/models/project_compassion.py @@ -525,6 +525,14 @@ def _compute_gps_obfuscated(self): 3. Make a request to Google Maps Geocoding API. 4. If successful, update the obfuscated coordinates. Used in compassion-modules/mobile_app_connector/models/compassion_project.py + + Note : This method has to be called on everytime the obfuscated coords + are required. + + Upon migration to 14.0.1.0.2, the obfuscated coords empty columns are created + to prevent odoo from sending an api request for each project when updating the + first time. + see my_compassion/migrations/14.0.1.0.2/pre-migration.py """ api_key = ( self.env["ir.config_parameter"].sudo().get_param("google_maps_api_key") @@ -536,7 +544,7 @@ def _compute_gps_obfuscated(self): for project in self: # Check if we already have coords to avoid wasting API calls - if project.gps_latitude_obfuscated or project.gps_longitude_obfuscated: + if project.gps_latitude_obfuscated and project.gps_longitude_obfuscated: continue # Build the list of available address parts @@ -551,7 +559,7 @@ def _compute_gps_obfuscated(self): params = {"address": address_string, "key": api_key} try: - response = requests.get(base_url, params=params, timeout=10) + response = requests.get(base_url, params=params, timeout=3) data = response.json() if data["status"] == "OK": From 5b5c134c97393f5b27e458f6f2f74ca10e512c4f Mon Sep 17 00:00:00 2001 From: Shayan Mouktar <119674649+Shayan105@users.noreply.github.com> Date: Thu, 8 Jan 2026 15:00:13 +0100 Subject: [PATCH 10/17] [T2792][STYLE] Remove useless get method --- .../models/compassion_project.py | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/mobile_app_connector/models/compassion_project.py b/mobile_app_connector/models/compassion_project.py index 813f10110..0c5cb2dae 100644 --- a/mobile_app_connector/models/compassion_project.py +++ b/mobile_app_connector/models/compassion_project.py @@ -29,27 +29,6 @@ def get_location_json(self, multi=False): data = self[:1].data_to_json("mobile_app_project") return data - def get_obfuscated_coordinates_json(self): - """ - Return the obfuscated coordinates in a json format - :return: dictionary with JSON data of the obfuscated coordinates - If the obfuscated coordinates are not available, return the integer part of the - real coordinates - This gives a rough location without revealing the exact position (100km accur.) - """ - self.update_obfuscated_coordinates() - # If the obfuscated coord. are not available, return the integer part. - if not self.gps_latitude_obfuscated or not self.gps_longitude_obfuscated: - return { - "Latitude": int(self.gps_latitude), - "Longitude": int(self.gps_longitude), - } - - return { - "Latitude": self.gps_latitude_obfuscated, - "Longitude": self.gps_longitude_obfuscated, - } - def get_weather_json(self, multi=False): if not self: return {} From 1f8f76a3c7b0165ed8ad0e4f55f21317ddf2e8ca Mon Sep 17 00:00:00 2001 From: Shayan Mouktar <119674649+Shayan105@users.noreply.github.com> Date: Thu, 8 Jan 2026 16:35:56 +0100 Subject: [PATCH 11/17] [T2792][STYLE] Use proper randomization of coordinates --- child_compassion/models/project_compassion.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/child_compassion/models/project_compassion.py b/child_compassion/models/project_compassion.py index a3f3e931a..7e9598d9b 100644 --- a/child_compassion/models/project_compassion.py +++ b/child_compassion/models/project_compassion.py @@ -11,6 +11,7 @@ import logging import re from datetime import datetime, timedelta +from random import random import requests @@ -567,7 +568,16 @@ def _compute_gps_obfuscated(self): project.gps_latitude_obfuscated = location["lat"] project.gps_longitude_obfuscated = location["lng"] else: - logging.error(f"Geocoding error for {project.id}: {data['status']}") + # Fallback to randomized gps coords + project.gps_latitude_obfuscated = ( + int(project.gps_latitude) + random() + ) + project.gps_longitude_obfuscated = ( + int(project.gps_longitude) + random() + ) + raise UserError( + f"Geocoding error for {project.id}: {data['status']}" + ) except Exception as e: logging.error(f"Request failed: {e}") From 92e0ea037cd6362ab60df60ecca8505b279d0093 Mon Sep 17 00:00:00 2001 From: Shayan Mouktar <119674649+Shayan105@users.noreply.github.com> Date: Thu, 8 Jan 2026 17:30:29 +0100 Subject: [PATCH 12/17] [T2792][FIX] Updates conditionning of the updates --- child_compassion/models/project_compassion.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/child_compassion/models/project_compassion.py b/child_compassion/models/project_compassion.py index 7e9598d9b..5644cfb93 100644 --- a/child_compassion/models/project_compassion.py +++ b/child_compassion/models/project_compassion.py @@ -518,7 +518,7 @@ def _get_materials(self): ] @api.onchange("gps_latitude", "gps_longitude") - def _compute_gps_obfuscated(self): + def _compute_gps_obfuscated(self, is_onchange_call=True): """ Update obfuscated coordinates using Google Maps Geocoding API. 1. Check if API key is configured. @@ -545,8 +545,13 @@ def _compute_gps_obfuscated(self): for project in self: # Check if we already have coords to avoid wasting API calls - if project.gps_latitude_obfuscated and project.gps_longitude_obfuscated: - continue + # If this method is called by onchange, update teh coords anyway + if ( + project.gps_latitude_obfuscated + and project.gps_longitude_obfuscated + and not is_onchange_call + ): + return # Build the list of available address parts parts = [ From 20a59fa143332e3d3c96b642bede60275bb10af1 Mon Sep 17 00:00:00 2001 From: Shayan Mouktar <119674649+Shayan105@users.noreply.github.com> Date: Fri, 9 Jan 2026 09:05:22 +0100 Subject: [PATCH 13/17] [T2792][FIX] Add lat long 0 fallback when no data are provided --- child_compassion/models/project_compassion.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/child_compassion/models/project_compassion.py b/child_compassion/models/project_compassion.py index 5644cfb93..966227831 100644 --- a/child_compassion/models/project_compassion.py +++ b/child_compassion/models/project_compassion.py @@ -575,10 +575,14 @@ def _compute_gps_obfuscated(self, is_onchange_call=True): else: # Fallback to randomized gps coords project.gps_latitude_obfuscated = ( - int(project.gps_latitude) + random() + (int(project.gps_latitude) + random()) + if project.gps_latitude + else 0 ) project.gps_longitude_obfuscated = ( - int(project.gps_longitude) + random() + (int(project.gps_longitude) + random()) + if project.gps_longitude + else 0 ) raise UserError( f"Geocoding error for {project.id}: {data['status']}" From 68bb8630eb43d42680b703e6b57f15b5d5f37e10 Mon Sep 17 00:00:00 2001 From: Shayan Mouktar <119674649+Shayan105@users.noreply.github.com> Date: Tue, 13 Jan 2026 17:23:02 +0100 Subject: [PATCH 14/17] [T2793][STYLE] Modularize calls to _compute_gps_obfuscated --- child_compassion/models/project_compassion.py | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/child_compassion/models/project_compassion.py b/child_compassion/models/project_compassion.py index 966227831..23b326eb6 100644 --- a/child_compassion/models/project_compassion.py +++ b/child_compassion/models/project_compassion.py @@ -517,8 +517,39 @@ def _get_materials(self): ("Plastic", _("Plastic")), ] + def _update_gps_obfuscated(self, force=False): + """ + Triggers the update of obfuscated GPS coordinates. + + This method serves as a manual trigger to calculate and store the obfuscated + coordinates (latitude and longitude). By default, it skips the update if + valid obfuscated coordinates already exist to avoid unnecessary API calls. + + :param force: If True, forces the re-computation of obfuscated coordinates + via the API even if they are already set. + :type force: bool + + .. note:: + This method is distinct from ``_compute_gps_obfuscated``. + - ``_compute_gps_obfuscated``: Performs the actual API call and logic to + calculate values. It is typically triggered automatically when standard + coordinates (gps_latitude/gps_longitude) change. + - ``_update_gps_obfuscated``: A wrapper to safely invoke the computation + manually, adding a check to prevent redundant updates unless forced. + """ + for project in self: + # Check if values exist and we are not forcing an update + if ( + project.gps_latitude_obfuscated + and project.gps_longitude_obfuscated + and not force + ): + continue + + project._compute_gps_obfuscated() + @api.onchange("gps_latitude", "gps_longitude") - def _compute_gps_obfuscated(self, is_onchange_call=True): + def _compute_gps_obfuscated(self): """ Update obfuscated coordinates using Google Maps Geocoding API. 1. Check if API key is configured. @@ -546,13 +577,6 @@ def _compute_gps_obfuscated(self, is_onchange_call=True): for project in self: # Check if we already have coords to avoid wasting API calls # If this method is called by onchange, update teh coords anyway - if ( - project.gps_latitude_obfuscated - and project.gps_longitude_obfuscated - and not is_onchange_call - ): - return - # Build the list of available address parts parts = [ project.closest_city, From f82ddde55a54e3313887b27c4298c7e943603b08 Mon Sep 17 00:00:00 2001 From: Shayan Mouktar <119674649+Shayan105@users.noreply.github.com> Date: Wed, 14 Jan 2026 09:24:42 +0100 Subject: [PATCH 15/17] [T2792][FIX] Use proper compute method on the gps_obfuscated --- child_compassion/models/project_compassion.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/child_compassion/models/project_compassion.py b/child_compassion/models/project_compassion.py index 23b326eb6..d892793fe 100644 --- a/child_compassion/models/project_compassion.py +++ b/child_compassion/models/project_compassion.py @@ -86,11 +86,9 @@ class CompassionProject(models.Model): zip_code = fields.Char(readonly=True) gps_latitude = fields.Float(readonly=True) gps_longitude = fields.Float(readonly=True) - gps_latitude_obfuscated = fields.Float( - compute="_compute_gps_obfuscated", store=True - ) + gps_latitude_obfuscated = fields.Float(compute="_update_gps_obfuscated", store=True) gps_longitude_obfuscated = fields.Float( - compute="_compute_gps_obfuscated", store=True + compute="_update_gps_obfuscated", store=True ) google_link = fields.Char(readonly=True, compute="_compute_google_link") timezone = fields.Char(readonly=True, compute="_compute_timezone", store=True) From 11e2f3d6aaab95c8adc677abc5e01103e719fd34 Mon Sep 17 00:00:00 2001 From: Shayan Mouktar <119674649+Shayan105@users.noreply.github.com> Date: Wed, 14 Jan 2026 09:45:22 +0100 Subject: [PATCH 16/17] [T2792][Refactor] Renames compute functions --- child_compassion/models/project_compassion.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/child_compassion/models/project_compassion.py b/child_compassion/models/project_compassion.py index d892793fe..12eb6ff49 100644 --- a/child_compassion/models/project_compassion.py +++ b/child_compassion/models/project_compassion.py @@ -86,9 +86,11 @@ class CompassionProject(models.Model): zip_code = fields.Char(readonly=True) gps_latitude = fields.Float(readonly=True) gps_longitude = fields.Float(readonly=True) - gps_latitude_obfuscated = fields.Float(compute="_update_gps_obfuscated", store=True) + gps_latitude_obfuscated = fields.Float( + compute="_compute_gps_obfuscated", store=True + ) gps_longitude_obfuscated = fields.Float( - compute="_update_gps_obfuscated", store=True + compute="_compute_gps_obfuscated", store=True ) google_link = fields.Char(readonly=True, compute="_compute_google_link") timezone = fields.Char(readonly=True, compute="_compute_timezone", store=True) @@ -515,7 +517,7 @@ def _get_materials(self): ("Plastic", _("Plastic")), ] - def _update_gps_obfuscated(self, force=False): + def _compute_gps_obfuscated(self, force=False): """ Triggers the update of obfuscated GPS coordinates. @@ -529,10 +531,10 @@ def _update_gps_obfuscated(self, force=False): .. note:: This method is distinct from ``_compute_gps_obfuscated``. - - ``_compute_gps_obfuscated``: Performs the actual API call and logic to + - ``_fetch_gps_obfuscated_cords``: Performs the actual API call and logic to calculate values. It is typically triggered automatically when standard coordinates (gps_latitude/gps_longitude) change. - - ``_update_gps_obfuscated``: A wrapper to safely invoke the computation + - ``_compute_gps_obfuscated``: A wrapper to safely invoke the computation manually, adding a check to prevent redundant updates unless forced. """ for project in self: @@ -544,10 +546,10 @@ def _update_gps_obfuscated(self, force=False): ): continue - project._compute_gps_obfuscated() + project._fetch_gps_obfuscated_cords() @api.onchange("gps_latitude", "gps_longitude") - def _compute_gps_obfuscated(self): + def _fetch_gps_obfuscated_cords(self): """ Update obfuscated coordinates using Google Maps Geocoding API. 1. Check if API key is configured. @@ -556,9 +558,6 @@ def _compute_gps_obfuscated(self): 4. If successful, update the obfuscated coordinates. Used in compassion-modules/mobile_app_connector/models/compassion_project.py - Note : This method has to be called on everytime the obfuscated coords - are required. - Upon migration to 14.0.1.0.2, the obfuscated coords empty columns are created to prevent odoo from sending an api request for each project when updating the first time. From ae6350cff4e99b7da0829a94e55ecd91d0bccdee Mon Sep 17 00:00:00 2001 From: Emanuel Cino Date: Thu, 12 Feb 2026 14:09:32 +0100 Subject: [PATCH 17/17] FIX obfuscation --- child_compassion/__manifest__.py | 2 +- .../migrations/14.0.1.5.0/pre-migration.py | 23 ++++ child_compassion/models/project_compassion.py | 104 ++++-------------- .../views/compassion_intervention_view.xml | 5 +- 4 files changed, 52 insertions(+), 82 deletions(-) create mode 100644 child_compassion/migrations/14.0.1.5.0/pre-migration.py diff --git a/child_compassion/__manifest__.py b/child_compassion/__manifest__.py index 0dbc7f16d..7f3aefd60 100644 --- a/child_compassion/__manifest__.py +++ b/child_compassion/__manifest__.py @@ -29,7 +29,7 @@ # pylint: disable=C8101 { "name": "Compassion Children", - "version": "14.0.1.4.0", + "version": "14.0.1.5.0", "category": "Compassion", "author": "Compassion CH", "license": "AGPL-3", diff --git a/child_compassion/migrations/14.0.1.5.0/pre-migration.py b/child_compassion/migrations/14.0.1.5.0/pre-migration.py new file mode 100644 index 000000000..cb6a83a99 --- /dev/null +++ b/child_compassion/migrations/14.0.1.5.0/pre-migration.py @@ -0,0 +1,23 @@ +from openupgradelib import openupgrade + + +def migrate(cr, version): + if not openupgrade.column_exists( + cr, "compassion_project", "gps_latitude_obfuscated" + ): + openupgrade.logged_query( + cr, + """ + ALTER TABLE compassion_project + ADD COLUMN gps_latitude_obfuscated float, + ADD COLUMN gps_longitude_obfuscated float; + """, + ) + openupgrade.logged_query( + cr, + """ + UPDATE compassion_project + SET gps_longitude_obfuscated = TRUNC(CAST(gps_longitude AS numeric), 0), + gps_latitude_obfuscated = TRUNC(CAST(gps_latitude AS numeric), 0); +""", + ) diff --git a/child_compassion/models/project_compassion.py b/child_compassion/models/project_compassion.py index 12eb6ff49..38c226ca2 100644 --- a/child_compassion/models/project_compassion.py +++ b/child_compassion/models/project_compassion.py @@ -517,100 +517,44 @@ def _get_materials(self): ("Plastic", _("Plastic")), ] - def _compute_gps_obfuscated(self, force=False): + @api.depends("gps_latitude", "gps_longitude", "closest_city") + def _compute_gps_obfuscated(self): """ - Triggers the update of obfuscated GPS coordinates. - - This method serves as a manual trigger to calculate and store the obfuscated - coordinates (latitude and longitude). By default, it skips the update if - valid obfuscated coordinates already exist to avoid unnecessary API calls. - - :param force: If True, forces the re-computation of obfuscated coordinates - via the API even if they are already set. - :type force: bool - - .. note:: - This method is distinct from ``_compute_gps_obfuscated``. - - ``_fetch_gps_obfuscated_cords``: Performs the actual API call and logic to - calculate values. It is typically triggered automatically when standard - coordinates (gps_latitude/gps_longitude) change. - - ``_compute_gps_obfuscated``: A wrapper to safely invoke the computation - manually, adding a check to prevent redundant updates unless forced. - """ - for project in self: - # Check if values exist and we are not forcing an update - if ( - project.gps_latitude_obfuscated - and project.gps_longitude_obfuscated - and not force - ): - continue - - project._fetch_gps_obfuscated_cords() - - @api.onchange("gps_latitude", "gps_longitude") - def _fetch_gps_obfuscated_cords(self): - """ - Update obfuscated coordinates using Google Maps Geocoding API. - 1. Check if API key is configured. - 2. If the current project has no obfuscated coordinates, build the address str. - 3. Make a request to Google Maps Geocoding API. - 4. If successful, update the obfuscated coordinates. - Used in compassion-modules/mobile_app_connector/models/compassion_project.py - - Upon migration to 14.0.1.0.2, the obfuscated coords empty columns are created - to prevent odoo from sending an api request for each project when updating the - first time. - see my_compassion/migrations/14.0.1.0.2/pre-migration.py + This method calculates and stores the obfuscated coordinates + (latitude and longitude). """ api_key = ( self.env["ir.config_parameter"].sudo().get_param("google_maps_api_key") ) - if not api_key: - return - base_url = "https://maps.googleapis.com/maps/api/geocode/json" - for project in self: - # Check if we already have coords to avoid wasting API calls - # If this method is called by onchange, update teh coords anyway - # Build the list of available address parts - parts = [ - project.closest_city, - project.state_province, - project.country_id.name, - ] - address_string = ", ".join(filter(None, parts)) - if not address_string: - continue - params = {"address": address_string, "key": api_key} - try: + parts = [ + project.closest_city, + project.state_province, + project.country_id.name, + ] + address_string = ", ".join(filter(None, parts)) + params = {"address": address_string, "key": api_key} response = requests.get(base_url, params=params, timeout=3) data = response.json() - if data["status"] == "OK": location = data["results"][0]["geometry"]["location"] project.gps_latitude_obfuscated = location["lat"] project.gps_longitude_obfuscated = location["lng"] - else: - # Fallback to randomized gps coords - project.gps_latitude_obfuscated = ( - (int(project.gps_latitude) + random()) - if project.gps_latitude - else 0 - ) - project.gps_longitude_obfuscated = ( - (int(project.gps_longitude) + random()) - if project.gps_longitude - else 0 - ) - raise UserError( - f"Geocoding error for {project.id}: {data['status']}" - ) - - except Exception as e: - logging.error(f"Request failed: {e}") + except Exception: + # Fallback to randomized gps coords + logging.warning("Request failed", exc_info=True) + project.gps_latitude_obfuscated = ( + (int(project.gps_latitude) + random()) + if project.gps_latitude + else 0 + ) + project.gps_longitude_obfuscated = ( + (int(project.gps_longitude) + random()) + if project.gps_longitude + else 0 + ) @api.depends("gps_longitude", "gps_latitude") def _compute_timezone(self): diff --git a/intervention_compassion/views/compassion_intervention_view.xml b/intervention_compassion/views/compassion_intervention_view.xml index 0fd0644f5..07b8baa01 100644 --- a/intervention_compassion/views/compassion_intervention_view.xml +++ b/intervention_compassion/views/compassion_intervention_view.xml @@ -98,7 +98,10 @@ - +