diff --git a/partner_external_map/__init__.py b/partner_external_map/__init__.py index 143d98dd5..18c7dccd6 100644 --- a/partner_external_map/__init__.py +++ b/partner_external_map/__init__.py @@ -1,3 +1,2 @@ - from . import models from .hooks import set_default_map_settings diff --git a/partner_external_map/__manifest__.py b/partner_external_map/__manifest__.py index acf220ddb..19f1d497b 100644 --- a/partner_external_map/__manifest__.py +++ b/partner_external_map/__manifest__.py @@ -4,26 +4,22 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - 'name': 'Partner External Maps', - 'version': '12.0.1.0.1', - 'category': 'Extra Tools', - 'license': 'AGPL-3', - 'summary': 'Add Map and Map Routing buttons on partner form to ' - 'open GMaps, OSM, Bing and others', - 'author': 'Akretion, ' - 'Tecnativa, ' - 'Odoo Community Association (OCA)', - 'website': 'https://github.com/OCA/partner-contact', - 'depends': [ - 'base', + "name": "Partner External Maps", + "version": "12.0.1.0.1", + "category": "Extra Tools", + "license": "AGPL-3", + "summary": "Add Map and Map Routing buttons on partner form to " + "open GMaps, OSM, Bing and others", + "author": "Akretion, " "Tecnativa, " "Odoo Community Association (OCA)", + "website": "https://github.com/OCA/partner-contact", + "depends": ["base",], + "data": [ + "views/res_partner_view.xml", + "views/map_website_view.xml", + "data/map_website_data.xml", + "views/res_users_view.xml", + "security/ir.model.access.csv", ], - 'data': [ - 'views/res_partner_view.xml', - 'views/map_website_view.xml', - 'data/map_website_data.xml', - 'views/res_users_view.xml', - 'security/ir.model.access.csv', - ], - 'post_init_hook': 'set_default_map_settings', - 'installable': True, + "post_init_hook": "set_default_map_settings", + "installable": True, } diff --git a/partner_external_map/data/map_website_data.xml b/partner_external_map/data/map_website_data.xml index 747d1785b..85cd789a8 100644 --- a/partner_external_map/data/map_website_data.xml +++ b/partner_external_map/data/map_website_data.xml @@ -1,55 +1,76 @@ - + - - - - - Google Maps - https://www.google.com/maps?ie=UTF8&q={ADDRESS} - https://www.google.com/maps?z=15&q={LATITUDE},{LONGITUDE} - https://www.google.com/maps?saddr={START_ADDRESS}&daddr={DEST_ADDRESS}&directionsmode=driving - https://www.google.com/maps?saddr={START_LATITUDE},{START_LONGITUDE}&daddr={DEST_LATITUDE},{DEST_LONGITUDE}&directionsmode=driving - - - - OpenStreetMap - https://nominatim.openstreetmap.org/search?q={ADDRESS} - https://www.openstreetmap.org/?zoom=15&mlat={LATITUDE}&mlon={LONGITUDE} - https://www.openstreetmap.org/directions/?engine=orsm_car&route={START_LATITUDE},{START_LONGITUDE};{DEST_LATITUDE},{DEST_LONGITUDE} - - - - OpenStreetMap FR - http://tile.openstreetmap.fr/?q={ADDRESS} - http://tile.openstreetmap.fr/?zoom=15&lat={LATITUDE}&lon={LONGITUDE} - - - - Bing Maps - https://www.bing.com/maps/default.aspx?where1={ADDRESS} - https://www.bing.com/maps/default.aspx?where1={LATITUDE},{LONGITUDE}&lvl=15 - - - - Here Maps - https://here.com/search/{ADDRESS} - https://www.here.com/?map={LATITUDE},{LONGITUDE},15,normal - - https://www.here.com/directions/drive/:{START_LATITUDE},{START_LONGITUDE}/:{DEST_LATITUDE},{DEST_LONGITUDE} - - - - MapQuest - https://www.mapquest.com/?center={ADDRESS} - https://www.mapquest.com/?center={LATITUDE},{LONGITUDE} - https://www.mapquest.com/directions?q1={START_ADDRESS}&q2={DEST_ADDRESS} - https://www.mapquest.com/directions/from/near-{START_LATITUDE},{START_LONGITUDE}/to/near-{DEST_LATITUDE},{DEST_LONGITUDE} - - - + + Google Maps + https://www.google.com/maps?ie=UTF8&q={ADDRESS} + https://www.google.com/maps?z=15&q={LATITUDE},{LONGITUDE} + https://www.google.com/maps?saddr={START_ADDRESS}&daddr={DEST_ADDRESS}&directionsmode=driving + https://www.google.com/maps?saddr={START_LATITUDE},{START_LONGITUDE}&daddr={DEST_LATITUDE},{DEST_LONGITUDE}&directionsmode=driving + + + OpenStreetMap + https://nominatim.openstreetmap.org/search?q={ADDRESS} + https://www.openstreetmap.org/?zoom=15&mlat={LATITUDE}&mlon={LONGITUDE} + https://www.openstreetmap.org/directions/?engine=orsm_car&route={START_LATITUDE},{START_LONGITUDE};{DEST_LATITUDE},{DEST_LONGITUDE} + + + OpenStreetMap FR + http://tile.openstreetmap.fr/?q={ADDRESS} + http://tile.openstreetmap.fr/?zoom=15&lat={LATITUDE}&lon={LONGITUDE} + + + Bing Maps + https://www.bing.com/maps/default.aspx?where1={ADDRESS} + https://www.bing.com/maps/default.aspx?where1={LATITUDE},{LONGITUDE}&lvl=15 + + + Here Maps + https://here.com/search/{ADDRESS} + https://www.here.com/?map={LATITUDE},{LONGITUDE},15,normal + + https://www.here.com/directions/drive/:{START_LATITUDE},{START_LONGITUDE}/:{DEST_LATITUDE},{DEST_LONGITUDE} + + + MapQuest + https://www.mapquest.com/?center={ADDRESS} + https://www.mapquest.com/?center={LATITUDE},{LONGITUDE} + https://www.mapquest.com/directions?q1={START_ADDRESS}&q2={DEST_ADDRESS} + https://www.mapquest.com/directions/from/near-{START_LATITUDE},{START_LONGITUDE}/to/near-{DEST_LATITUDE},{DEST_LONGITUDE} + + - diff --git a/partner_external_map/hooks.py b/partner_external_map/hooks.py index 1ee83cadc..7c2015b6c 100644 --- a/partner_external_map/hooks.py +++ b/partner_external_map/hooks.py @@ -2,9 +2,9 @@ # Copyright 2016 Pedro M. Baeza # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api, SUPERUSER_ID import logging +from odoo import SUPERUSER_ID, api logger = logging.getLogger(__name__) @@ -16,17 +16,22 @@ def set_default_map_settings(cr, registry): value""" with api.Environment.manage(): env = api.Environment(cr, SUPERUSER_ID, {}) - user_model = env['res.users'] - users = user_model.search([('context_map_website_id', '=', False)]) - logger.info('Updating user settings for maps...') - users.write({ - 'context_map_website_id': user_model._default_map_website().id, - 'context_route_map_website_id': ( - user_model._default_route_map_website().id), - }) + user_model = env["res.users"] + users = user_model.search([("context_map_website_id", "=", False)]) + logger.info("Updating user settings for maps...") + users.write( + { + "context_map_website_id": user_model._default_map_website().id, + "context_route_map_website_id": ( + user_model._default_route_map_website().id + ), + } + ) # Update the starting partner this way that is faster - cr.execute(""" + cr.execute( + """ UPDATE res_users SET context_route_start_partner_id = partner_id WHERE context_route_start_partner_id IS NULL; - """) + """ + ) diff --git a/partner_external_map/models/__init__.py b/partner_external_map/models/__init__.py index 3693814db..d8cc7d7ee 100644 --- a/partner_external_map/models/__init__.py +++ b/partner_external_map/models/__init__.py @@ -1,4 +1,3 @@ - from . import map_website from . import res_partner from . import res_users diff --git a/partner_external_map/models/map_website.py b/partner_external_map/models/map_website.py index 640bd401c..6b34e6ba1 100644 --- a/partner_external_map/models/map_website.py +++ b/partner_external_map/models/map_website.py @@ -3,28 +3,32 @@ # Copyright 2016 Pedro M. Baeza # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models, fields +from odoo import fields, models class MapWebsite(models.Model): - _name = 'map.website' - _description = 'Map Website' + _name = "map.website" + _description = "Map Website" - name = fields.Char(string='Map Website Name', required=True) + name = fields.Char(string="Map Website Name", required=True) address_url = fields.Char( - string='URL that uses the address', - help="In this URL, {ADDRESS} will be replaced by the address.") + string="URL that uses the address", + help="In this URL, {ADDRESS} will be replaced by the address.", + ) lat_lon_url = fields.Char( - string='URL that uses latitude and longitude', + string="URL that uses latitude and longitude", help="In this URL, {LATITUDE} and {LONGITUDE} will be replaced by " - "the latitude and longitude (requires the module 'base_geolocalize')") + "the latitude and longitude (requires the module 'base_geolocalize')", + ) route_address_url = fields.Char( - string='Route URL that uses the addresses', + string="Route URL that uses the addresses", help="In this URL, {START_ADDRESS} and {DEST_ADDRESS} will be " - "replaced by the start and destination addresses.") + "replaced by the start and destination addresses.", + ) route_lat_lon_url = fields.Char( - string='Route URL that uses latitude and longitude', + string="Route URL that uses latitude and longitude", help="In this URL, {START_LATITUDE}, {START_LONGITUDE}, " "{DEST_LATITUDE} and {DEST_LONGITUDE} will be replaced by the " "latitude and longitude of the start and destination adresses " - "(requires the module 'base_geolocalize').") + "(requires the module 'base_geolocalize').", + ) diff --git a/partner_external_map/models/res_partner.py b/partner_external_map/models/res_partner.py index e1f63c834..913a26232 100644 --- a/partner_external_map/models/res_partner.py +++ b/partner_external_map/models/res_partner.py @@ -3,16 +3,16 @@ # Copyright 2016 Pedro M. Baeza # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models, api, _ -from odoo.exceptions import UserError import logging +from odoo import _, api, models +from odoo.exceptions import UserError logger = logging.getLogger(__name__) class ResPartner(models.Model): - _inherit = 'res.partner' + _inherit = "res.partner" @api.multi def _address_as_string(self): @@ -30,17 +30,17 @@ class ResPartner(models.Model): addr.append(self.country_id.name) if not addr: raise UserError(_("Address missing on partner '%s'.") % self.name) - return ' '.join(addr) + return " ".join(addr) @api.model def _prepare_url(self, url, replace): - assert url, 'Missing URL' + assert url, "Missing URL" for key, value in replace.items(): if not isinstance(value, str): # for latitude and longitude which are floats value = str(value) url = url.replace(key, value) - logger.debug('Final URL: %s', url) + logger.debug("Final URL: %s", url) return url @api.multi @@ -49,26 +49,37 @@ class ResPartner(models.Model): map_website = self.env.user.context_map_website_id if not map_website: raise UserError( - _('Missing map provider: ' - 'you should set it in your preferences.')) - if (map_website.lat_lon_url and hasattr(self, 'partner_latitude') and - self.partner_latitude and self.partner_longitude): + _("Missing map provider: " "you should set it in your preferences.") + ) + if ( + map_website.lat_lon_url + and hasattr(self, "partner_latitude") + and self.partner_latitude + and self.partner_longitude + ): url = self._prepare_url( - map_website.lat_lon_url, { - '{LATITUDE}': self.partner_latitude, - '{LONGITUDE}': self.partner_longitude}) + map_website.lat_lon_url, + { + "{LATITUDE}": self.partner_latitude, + "{LONGITUDE}": self.partner_longitude, + }, + ) else: if not map_website.address_url: raise UserError( - _("Missing parameter 'URL that uses the address' " - "for map website '%s'.") % map_website.name) + _( + "Missing parameter 'URL that uses the address' " + "for map website '%s'." + ) + % map_website.name + ) url = self._prepare_url( - map_website.address_url, - {'{ADDRESS}': self._address_as_string()}) + map_website.address_url, {"{ADDRESS}": self._address_as_string()} + ) return { - 'type': 'ir.actions.act_url', - 'url': url, - 'target': 'new', + "type": "ir.actions.act_url", + "url": url, + "target": "new", } @api.multi @@ -76,36 +87,55 @@ class ResPartner(models.Model): self.ensure_one() if not self.env.user.context_route_map_website_id: raise UserError( - _('Missing route map website: ' - 'you should set it in your preferences.')) + _( + "Missing route map website: " + "you should set it in your preferences." + ) + ) map_website = self.env.user.context_route_map_website_id if not self.env.user.context_route_start_partner_id: raise UserError( - _('Missing start address for route map: ' - 'you should set it in your preferences.')) + _( + "Missing start address for route map: " + "you should set it in your preferences." + ) + ) start_partner = self.env.user.context_route_start_partner_id - if (map_website.route_lat_lon_url and - hasattr(self, 'partner_latitude') and - self.partner_latitude and self.partner_longitude and - start_partner.partner_latitude and - start_partner.partner_longitude): + if ( + map_website.route_lat_lon_url + and hasattr(self, "partner_latitude") + and self.partner_latitude + and self.partner_longitude + and start_partner.partner_latitude + and start_partner.partner_longitude + ): url = self._prepare_url( # pragma: no cover - map_website.route_lat_lon_url, { - '{START_LATITUDE}': start_partner.partner_latitude, - '{START_LONGITUDE}': start_partner.partner_longitude, - '{DEST_LATITUDE}': self.partner_latitude, - '{DEST_LONGITUDE}': self.partner_longitude}) + map_website.route_lat_lon_url, + { + "{START_LATITUDE}": start_partner.partner_latitude, + "{START_LONGITUDE}": start_partner.partner_longitude, + "{DEST_LATITUDE}": self.partner_latitude, + "{DEST_LONGITUDE}": self.partner_longitude, + }, + ) else: if not map_website.route_address_url: raise UserError( - _("Missing route URL that uses the addresses " - "for the map website '%s'") % map_website.name) + _( + "Missing route URL that uses the addresses " + "for the map website '%s'" + ) + % map_website.name + ) url = self._prepare_url( - map_website.route_address_url, { - '{START_ADDRESS}': start_partner._address_as_string(), - '{DEST_ADDRESS}': self._address_as_string()}) + map_website.route_address_url, + { + "{START_ADDRESS}": start_partner._address_as_string(), + "{DEST_ADDRESS}": self._address_as_string(), + }, + ) return { - 'type': 'ir.actions.act_url', - 'url': url, - 'target': 'new', + "type": "ir.actions.act_url", + "url": url, + "target": "new", } diff --git a/partner_external_map/models/res_users.py b/partner_external_map/models/res_users.py index a43a80691..248f39760 100644 --- a/partner_external_map/models/res_users.py +++ b/partner_external_map/models/res_users.py @@ -3,43 +3,57 @@ # Copyright 2016 Pedro M. Baeza # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models, fields, api import logging +from odoo import api, fields, models + logger = logging.getLogger(__name__) class ResUsers(models.Model): - _inherit = 'res.users' + _inherit = "res.users" @api.model def _default_map_website(self): - return self.env['map.website'].search([ - '|', ('address_url', '!=', False), ('lat_lon_url', '!=', False)], - limit=1) + return self.env["map.website"].search( + ["|", ("address_url", "!=", False), ("lat_lon_url", "!=", False)], limit=1 + ) @api.model def _default_route_map_website(self): - return self.env['map.website'].search([ - '|', ('route_address_url', '!=', False), - ('route_lat_lon_url', '!=', False)], limit=1) + return self.env["map.website"].search( + [ + "|", + ("route_address_url", "!=", False), + ("route_lat_lon_url", "!=", False), + ], + limit=1, + ) # begin with context_ to allow user to change it by himself context_map_website_id = fields.Many2one( - 'map.website', string='Map Website', default=_default_map_website, - domain=['|', ('address_url', '!=', False), - ('lat_lon_url', '!=', False)]) + "map.website", + string="Map Website", + default=_default_map_website, + domain=["|", ("address_url", "!=", False), ("lat_lon_url", "!=", False)], + ) # We want to give the possibility to the user to have one map provider for # regular maps and another one for routing context_route_map_website_id = fields.Many2one( - 'map.website', string='Route Map Website', - domain=['|', ('route_address_url', '!=', False), - ('route_lat_lon_url', '!=', False)], + "map.website", + string="Route Map Website", + domain=[ + "|", + ("route_address_url", "!=", False), + ("route_lat_lon_url", "!=", False), + ], default=_default_route_map_website, help="Map provided used when you click on the car icon on the partner " - "form to display an itinerary.") + "form to display an itinerary.", + ) context_route_start_partner_id = fields.Many2one( - 'res.partner', string='Start Address for Route Map') + "res.partner", string="Start Address for Route Map" + ) @api.model def create(self, vals): @@ -47,6 +61,6 @@ class ResUsers(models.Model): created one. """ user = super(ResUsers, self).create(vals) - if not vals.get('context_route_start_partner_id'): + if not vals.get("context_route_start_partner_id"): user.context_route_start_partner_id = user.partner_id.id return user diff --git a/partner_external_map/tests/__init__.py b/partner_external_map/tests/__init__.py index 38052c83d..d108e8e64 100644 --- a/partner_external_map/tests/__init__.py +++ b/partner_external_map/tests/__init__.py @@ -1,2 +1 @@ - from . import test_partner_external_map diff --git a/partner_external_map/tests/test_partner_external_map.py b/partner_external_map/tests/test_partner_external_map.py index 3918c04e8..43bf00e3a 100644 --- a/partner_external_map/tests/test_partner_external_map.py +++ b/partner_external_map/tests/test_partner_external_map.py @@ -1,57 +1,66 @@ # Copyright 2016 Pedro M. Baeza # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo.tests import common from odoo.exceptions import UserError +from odoo.tests import common + from ..hooks import set_default_map_settings class TestPartnerExternalMap(common.TransactionCase): def setUp(self): super(TestPartnerExternalMap, self).setUp() - self.user = self.env['res.users'].create({ - 'name': 'Test user', - 'login': 'test_login', - 'context_map_website_id': self.ref( - 'partner_external_map.google_maps'), - 'context_route_map_website_id': self.ref( - 'partner_external_map.google_maps'), - }) - self.user.partner_id.city = 'Tomelloso' - self.partner = self.env['res.partner'].create({ - 'name': 'Test partner', - 'city': 'Madrid', - 'street': 'street_test', - 'street2': 'street2_test', - 'state_id': self.ref('base.state_es_m'), - 'country_id': self.ref('base.es'), - }) + self.user = self.env["res.users"].create( + { + "name": "Test user", + "login": "test_login", + "context_map_website_id": self.ref("partner_external_map.google_maps"), + "context_route_map_website_id": self.ref( + "partner_external_map.google_maps" + ), + } + ) + self.user.partner_id.city = "Tomelloso" + self.partner = self.env["res.partner"].create( + { + "name": "Test partner", + "city": "Madrid", + "street": "street_test", + "street2": "street2_test", + "state_id": self.ref("base.state_es_m"), + "country_id": self.ref("base.es"), + } + ) def test_post_init_hook(self): # Call this again for coverage purposes, but it has been already run set_default_map_settings(self.cr, self.registry) - usrs = self.env['res.users'].search([]) + usrs = self.env["res.users"].search([]) self.assertTrue(all([u.context_map_website_id.id for u in usrs])) self.assertTrue(all([u.context_route_map_website_id.id for u in usrs])) - self.assertEqual(self.env.user.partner_id, - self.env.user.context_route_start_partner_id) + self.assertEqual( + self.env.user.partner_id, self.env.user.context_route_start_partner_id + ) def test_create_user(self): - self.assertEqual( - self.user.partner_id, self.user.context_route_start_partner_id) + self.assertEqual(self.user.partner_id, self.user.context_route_start_partner_id) def test_open_map(self): action = self.partner.sudo(self.user.id).open_map() self.assertEqual( - action['url'], "https://www.google.com/maps?ie=UTF8" - "&q=street_test street2_test Madrid Madrid Spain") + action["url"], + "https://www.google.com/maps?ie=UTF8" + "&q=street_test street2_test Madrid Madrid Spain", + ) def test_open_route_map(self): action = self.partner.sudo(self.user.id).open_route_map() self.assertEqual( - action['url'], "https://www.google.com/maps?saddr=Tomelloso" - "&daddr=street_test street2_test Madrid Madrid " - "Spain&directionsmode=driving") + action["url"], + "https://www.google.com/maps?saddr=Tomelloso" + "&daddr=street_test street2_test Madrid Madrid " + "Spain&directionsmode=driving", + ) def test_open_map_with_coordinates(self): # Simulate that we have the base_geolocalize module installed creating @@ -60,19 +69,20 @@ class TestPartnerExternalMap(common.TransactionCase): partner.partner_latitude = 39.15837 partner.partner_longitude = -3.02145 action = partner.open_map() - self.assertTrue( - action["url"].startswith("https://www.google.com/maps?z=")) - self.assertIn("39.15837", action['url']) - self.assertIn("-3.02145", action['url']) + self.assertTrue(action["url"].startswith("https://www.google.com/maps?z=")) + self.assertIn("39.15837", action["url"]) + self.assertIn("-3.02145", action["url"]) def test_exception_no_addr(self): - self.partner.write({ - 'city': False, - 'street': False, - 'street2': False, - 'state_id': False, - 'country_id': False, - }) + self.partner.write( + { + "city": False, + "street": False, + "street2": False, + "state_id": False, + "country_id": False, + } + ) with self.assertRaises(UserError): self.partner.sudo(self.user.id).open_route_map() diff --git a/partner_external_map/views/map_website_view.xml b/partner_external_map/views/map_website_view.xml index 8d86cb6c2..4e3adee2b 100644 --- a/partner_external_map/views/map_website_view.xml +++ b/partner_external_map/views/map_website_view.xml @@ -1,51 +1,52 @@ - + - - - - map.website.form - map.website - -
- - - - - - - -
-
-
- - - map.website.tree - map.website - - - - - - - - - - Map Websites - map.website - tree,form - - - - - - - + +
diff --git a/partner_external_map/views/res_partner_view.xml b/partner_external_map/views/res_partner_view.xml index 6fdd156ce..27e9f2baa 100644 --- a/partner_external_map/views/res_partner_view.xml +++ b/partner_external_map/views/res_partner_view.xml @@ -1,28 +1,33 @@ - + - - - - - map.button.res.partner.form - res.partner - - - -