Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[10.0][MIG] geoengine_base_geolocalize migration #155

Merged
merged 7 commits into from
Jun 19, 2020
Merged
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
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ install:
- git clone https://github.com/OCA/maintainer-quality-tools.git ${HOME}/maintainer-quality-tools
- export PATH=${HOME}/maintainer-quality-tools/travis:${PATH}
- travis_install_nightly
- pip install geojson Shapely sphinx sphinx_bootstrap_theme sphinx-intl odoo-sphinx-autodoc
- pip install geojson Shapely sphinx sphinx_bootstrap_theme sphinx-intl odoo-sphinx-autodoc responses
# This is to solve an issue with stdout file descriptor
# raising a BlockingIOError while executing pylint and returns an exit -1
# seems related to the numerous lint errors on web_view_google_map module
Expand Down
49 changes: 38 additions & 11 deletions base_geoengine/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

logger = logging.getLogger(__name__)
try:
from shapely.geometry import asShape
from shapely.geometry import Point
from shapely.geometry.base import BaseGeometry
from shapely.wkb import loads as wkbloads
Expand All @@ -20,6 +21,7 @@
logger.warning('Shapely or geojson are not available in the sys path')


# pylint: disable=sql-injection, invalid-commit
class GeoField(Field):
""" The field descriptor contains the field definition common to all
specialized fields for geolocalization. Subclasses must define a type
Expand All @@ -39,7 +41,7 @@ def column_type(self):

_slots = {
'dim': 2,
'srid': 900913,
'srid': 3857,
'gist_index': True,
'manual': True,
}
Expand All @@ -54,8 +56,7 @@ def convert_to_column(self, value, record):
shape_to_write = self.entry_to_shape(value, same_type=True)
if shape_to_write.is_empty:
return None
else:
return shape_to_write.wkt
return shape_to_write.wkt

def convert_to_cache(self, value, record, validate=True):
val = value
Expand All @@ -64,15 +65,14 @@ def convert_to_cache(self, value, record, validate=True):
return val

def convert_to_record(self, value, record):
""" Value may be:
- a GeoJSON string when field onchange is triggered
- a geometry object hexcode from cache
- a unicode containing dict
"""
if not value:
return False
if isinstance(value, str):
# Geometry object hexcode from cache
shape = self.load_geo(value)
else:
# Might be unicode containing dict
shape = convert.value_to_shape(value)
return shape
return convert.value_to_shape(value, use_wkb=True)

def convert_to_read(self, value, record, use_name_get=True):
if not isinstance(value, BaseGeometry):
Expand All @@ -96,6 +96,8 @@ def convert_to_read(self, value, record, use_name_get=True):
@classmethod
def load_geo(cls, wkb):
"""Load geometry into browse record after read was done"""
if isinstance(wkb, BaseGeometry):
return wkb
return wkbloads(wkb, hex=True) if wkb else False

def create_geo_column(self, cr, col_name, table, model):
Expand All @@ -115,7 +117,6 @@ def create_geo_column(self, cr, col_name, table, model):
raise
finally:
cr.commit()

return True

def entry_to_shape(self, value, same_type=False):
Expand Down Expand Up @@ -188,6 +189,7 @@ def update_geo_column(self, cr, col_name, table, model):

class GeoLine(GeoField):
"""Field for POSTGIS geometry Line type"""

type = 'geo_line'
geo_type = 'LINESTRING'

Expand Down Expand Up @@ -255,6 +257,31 @@ def from_latlon(cls, cr, latitude, longitude):
res = cr.fetchone()
return cls.load_geo(res[0])

@classmethod
def to_latlon(cls, cr, geopoint):
""" Convert a UTM coordinate point to (latitude, longitude):
"""
# Line to execute to retrieve longitude, latitude from UTM
# in postgres command line:
# SELECT ST_X(geom), ST_Y(geom) FROM (SELECT ST_TRANSFORM(ST_SetSRID(
# ST_MakePoint(601179.61612, 6399375,681364), 3847), 4326) as geom) g;
if isinstance(geopoint, BaseGeometry):
geo_point_instance = geopoint
else:
geo_point_instance = asShape(geojson.loads(geopoint))
cr.execute("""
SELECT
ST_TRANSFORM(
ST_SetSRID(ST_MakePoint(%(coord_x)s, %(coord_y)s),
%(srid)s), 4326)""",
{'coord_x': geo_point_instance.x,
'coord_y': geo_point_instance.y,
'srid': cls._slots['srid']})

res = cr.fetchone()
point_latlon = cls.load_geo(res[0])
return point_latlon.x, point_latlon.y


class GeoPolygon(GeoField):
"""Field for POSTGIS geometry Polygon type"""
Expand Down
19 changes: 11 additions & 8 deletions base_geoengine/geo_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"""Helper to setup Postgis"""
import logging

from odoo import _
from odoo.exceptions import MissingError

logger = logging.getLogger('geoengine.sql')
Expand Down Expand Up @@ -33,12 +34,14 @@ def init_postgis(cr):
""")
except Exception:
raise MissingError(
"Error, can not automatically initialize spatial postgis support. "
"Database user may have to be superuser and postgres/postgis "
"extentions with their devel header have to be installed. "
"If you do not want Odoo to connect with a super user "
"you can manually prepare your database. To do this"
"open a client to your database using a super user and run: \n"
"CREATE EXTENSION postgis;\n"
"CREATE EXTENSION postgis_topology;\n"
_("Error,"
"can not automatically initialize spatial postgis support."
"Database user may have to be superuser and postgres/postgis "
"extentions with their devel header have to be installed. "
"If you do not want Odoo to connect with a super user "
"you can manually prepare your database. To do this"
"open a client to your database using a super user and run: \n"
"CREATE EXTENSION postgis;\n"
"CREATE EXTENSION postgis_topology;\n")

)
6 changes: 4 additions & 2 deletions base_geoengine/geo_helper/geo_convertion_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import logging

try:
from shapely import wkt
from shapely import wkt, wkb
from shapely.geometry import asShape
from shapely.geometry.base import BaseGeometry
import geojson
Expand All @@ -13,7 +13,7 @@
logger.warning('Shapely or geojson are not available in the sys path')


def value_to_shape(value):
def value_to_shape(value, use_wkb=False):
"""Transforms input into a Shapely object"""
if not value:
return wkt.loads('GEOMETRYCOLLECTION EMPTY')
Expand All @@ -23,6 +23,8 @@ def value_to_shape(value):
if '{' in value:
geo_dict = geojson.loads(value)
return asShape(geo_dict)
elif use_wkb:
return wkb.loads(value, hex=True)
else:
return wkt.loads(value)
elif hasattr(value, 'wkt'):
Expand Down
4 changes: 4 additions & 0 deletions base_geoengine/geo_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def geo_search(model, domain=None, geo_domain=None, offset=0,
* geo_contains
* geo_intersect
"""

cr = model._cr
domain = domain or []
geo_domain = geo_domain or []
Expand Down Expand Up @@ -114,9 +115,12 @@ def geo_search(model, domain=None, geo_domain=None, offset=0,
where_statement = " WHERE %s" % (u' '.join(where_clause_arr))
else:
where_statement = u''

# pylint: disable=sql-injection
sql = 'SELECT "%s".id FROM ' % model._table + from_clause + \
where_statement + order_by + limit_str + offset_str
# logger.debug(cursor.mogrify(sql, where_clause_params))

cr.execute(sql, where_clause_params)
res = cr.fetchall()
if res:
Expand Down
4 changes: 2 additions & 2 deletions base_geoengine/tests/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
"the_geom": {
"geo_type": {
"dim": 2,
"srid": 900913,
"srid": 3857,
"type": "geo_multi_polygon"
},
"required": False,
Expand All @@ -138,5 +138,5 @@
'default_extent':
u'-123164.85222423, 5574694.9538936, 1578017.6490538, 6186191.1800898',
'geo_type': 'MULTIPOLYGON',
'srid': 900913
'srid': 3857
}
27 changes: 25 additions & 2 deletions base_geoengine/tests/test_geoengine.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
from odoo import fields
from odoo.exceptions import MissingError

from odoo.addons.base_geoengine.geo_model import GeoModel
from odoo.addons.base_geoengine import fields as geo_fields
from ..geo_model import GeoModel
from .. import fields as geo_fields
from ..fields import GeoPoint
from .data import MULTIPOLYGON_1, GEO_VIEW, FORM_VIEW
from .data import EXPECTED_GEO_COLUMN_MULTIPOLYGON

Expand Down Expand Up @@ -272,3 +273,25 @@ def test_create_line_from_points(self):
geo_line = geo_fields.GeoLine.from_points(
self.env.cr, geo_point_1, geo_point_2)
self.assertEqual(geo_line, expected_line)

def test_from_lat_lon(self):
latitude = 49.72842315886126
longitude = 5.400488376617026

# This is computed with postgis in postgres:

expected_coordinates = [601179.61612, 6399375.681364]

geo_point = GeoPoint.from_latlon(self.env.cr, latitude, longitude)

self.assertAlmostEqual(geo_point.x, expected_coordinates[0], 4)
self.assertAlmostEqual(geo_point.y, expected_coordinates[1], 4)

def test_to_lat_lon(self):

geo_point = Point(601179.61612, 6399375.681364)

longitude, latitude = GeoPoint.to_latlon(self.env.cr, geo_point)

self.assertAlmostEqual(latitude, 49.72842315886126, 4)
self.assertAlmostEqual(longitude, 5.400488376617026, 4)
4 changes: 2 additions & 2 deletions base_geoengine_demo/models/geo_npa.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ class NPA(geo_model.GeoModel):
city = fields.Char('City', size=64, index=True, required=True)
the_geom = geo_fields.GeoMultiPolygon('NPA Shape')
total_sales = fields.Float(
compute='_get_ZIP_total_sales',
compute='_compute_ZIP_total_sales',
string='Spatial! Total Sales',
)

@api.multi
def _get_ZIP_total_sales(self):
def _compute_ZIP_total_sales(self):
"""Return the total of the invoiced sales for this npa"""
mach_obj = self.env['geoengine.demo.automatic.retailing.machine']
for rec in self:
Expand Down
2 changes: 1 addition & 1 deletion base_geoengine_demo/models/retail_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from odoo.addons.base_geoengine import geo_model
from odoo.addons.base_geoengine import fields as geo_fields


logger = logging.getLogger(__name__)

try:
import geojson
except ImportError:
Expand Down
55 changes: 55 additions & 0 deletions base_geolocalize_openstreetmap/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3

==============================
Base Geolocalize Openstreetmap
==============================

Open street map API call to geolocalize an address.

Installation
============

Just install it!

Configuration
=============

No configuration needed.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues
<https://github.com/OCA/geospatial/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smash it by providing detailed and welcomed feedback.

Credits
=======

Images
------

* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.

Contributors
------------

* Benjamin Willig <[email protected]>

Maintainer
----------

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

This module is maintained by the OCA.

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

To contribute to this module, please visit https://odoo-community.org.
1 change: 1 addition & 0 deletions base_geolocalize_openstreetmap/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
21 changes: 21 additions & 0 deletions base_geolocalize_openstreetmap/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Copyright 2017 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

{
'name': 'Base Geolocalize Openstreetmap',
'summary': """
Open street map API call to geolocalize an address""",
'version': '10.0.1.0.0',
'license': 'AGPL-3',
'author': 'ACSONE SA/NV, Odoo Community Association (OCA)',
'website': 'https://github.com/OCA/geospatial',
'depends': [
'base_geolocalize',
],
'external_dependencies': {
'python': [
'requests'
],
},
}
1 change: 1 addition & 0 deletions base_geolocalize_openstreetmap/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import res_partner
Loading