-
-
Notifications
You must be signed in to change notification settings - Fork 602
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ADD] pos_partner_location_google_map: Module added.
- Loading branch information
Showing
19 changed files
with
563 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"name": "POS Partner Location Google Map", | ||
"version": "16.0.1.0.0", | ||
"category": "Point Of Sale", | ||
"summary": "POS Partner Location Google Map", | ||
"author": "Cetmix, Odoo Community Association (OCA)", | ||
"maintainers": ["geomer198", "CetmixGitDrone"], | ||
"website": "https://github.com/OCA/pos", | ||
"license": "AGPL-3", | ||
"depends": ["pos_partner_location_abstract"], | ||
"data": [], | ||
"assets": { | ||
"point_of_sale.assets": [ | ||
"pos_partner_location_google_map/static/src/js/*.js", | ||
], | ||
}, | ||
"installable": True, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from . import address_google_struct | ||
from . import base_geocoder | ||
from . import pos_config |
137 changes: 137 additions & 0 deletions
137
pos_partner_location_google_map/models/address_google_struct.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
from odoo.osv.expression import AND, OR | ||
|
||
from odoo.addons.pos_partner_location_abstract.models.address_struct import ( | ||
AddressStruct, | ||
) | ||
|
||
|
||
class AddressGoogleStruct(AddressStruct): | ||
ADDR_FIELDS = { | ||
"number": ["street_number"], | ||
"street": ["street_address", "route", "plus_code"], | ||
"city": [ | ||
"locality", | ||
"sublocality", | ||
"sublocality_level_1", | ||
"sublocality_level_2", | ||
"sublocality_level_3", | ||
"sublocality_level_4", | ||
], | ||
"state_id": [ | ||
"administrative_area_level_1", | ||
"administrative_area_level_2", | ||
"administrative_area_level_3", | ||
"administrative_area_level_4", | ||
"administrative_area_level_5", | ||
], | ||
"country_id": ["country"], | ||
"zip": ["postal_code"], | ||
} | ||
SERVICE_URL = "https://maps.googleapis.com/maps/api/place/details/json" | ||
|
||
def __init__(self, odoo_env): | ||
super(AddressGoogleStruct, self).__init__(odoo_env) | ||
self.api_key = ( | ||
self.env["ir.config_parameter"] | ||
.sudo() | ||
.get_param("base_geolocalize.google_map_api_key", False) | ||
) | ||
|
||
def has_token(self): | ||
"""Checking exists Google API key in settings""" | ||
return bool(self.api_key) | ||
|
||
def _get_fields_value(self, addr_key): | ||
""" | ||
Get fields value for preparing values address | ||
:param str addr_key: field name | ||
:return list: list of fields values | ||
""" | ||
return [self._result.get(key, False) for key in self.ADDR_FIELDS[addr_key]] | ||
|
||
@property | ||
def street(self): | ||
street_number = self._result.get("street_number") | ||
result = [] | ||
if street_number: | ||
result.append(street_number) | ||
for address in self._get_fields_value("street"): | ||
if address: | ||
result.append(address) | ||
return " ".join(result) | ||
return "" | ||
|
||
@property | ||
def city(self): | ||
for city in self._get_fields_value("city"): | ||
if city: | ||
return city | ||
return False | ||
|
||
@property | ||
def state_id(self): | ||
domain = [] | ||
codes = [] | ||
for state in self._get_fields_value("state_id"): | ||
if state: | ||
domain = OR([domain, [("name", "like", state.get("name"))]]) | ||
codes.append(state.get("code")) | ||
if codes: | ||
domain = OR([domain, [("code", "in", codes)]]) | ||
if len(domain) == 0: | ||
return False | ||
country_id = self.country_id | ||
if country_id: | ||
domain = AND([domain, [("country_id", "=", country_id[0])]]) | ||
state = self.env["res.country.state"].search(domain, limit=1) | ||
return state.name_get()[0] if state else False | ||
|
||
@property | ||
def country_id(self): | ||
country_item = self._result.get("country") | ||
if not country_item: | ||
return False | ||
country = self.env["res.country"].search( | ||
[ | ||
"|", | ||
("name", "like", country_item.get("name")), | ||
("code", "=", country_item.get("code")), | ||
] | ||
) | ||
return country.name_get()[0] if country else False | ||
|
||
@property | ||
def zip(self): | ||
return self._result.get("postal_code") | ||
|
||
def query_addr(self, params, timeout=5): | ||
params.update(key=self.api_key) | ||
response = super(AddressGoogleStruct, self).query_addr(params, timeout=timeout) | ||
if response: | ||
if response.get("status") == "OK": | ||
self._prepare_components_data(response["result"]["address_components"]) | ||
return True | ||
return False | ||
|
||
def _prepare_components_data(self, components): | ||
""" | ||
Preparing component values for class result | ||
:param dict components: list of components | ||
:return: None | ||
:rtype: NoneType | ||
""" | ||
state_country_fields = [ | ||
*self.ADDR_FIELDS.get("state_id", []), | ||
*self.ADDR_FIELDS.get("country_id", []), | ||
] | ||
for component in components: | ||
for type_ in component["types"]: | ||
if type_ in state_country_fields: | ||
self._result[type_] = { | ||
"code": component["short_name"], | ||
"name": component["long_name"], | ||
} | ||
elif type_ in self.ADDR_FIELDS.get("street", []): | ||
self._result[type_] = component["short_name"] | ||
else: | ||
self._result[type_] = component["long_name"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
from odoo import _, api, models | ||
|
||
from .address_google_struct import AddressGoogleStruct | ||
|
||
|
||
class GeoProvider(models.AbstractModel): | ||
_inherit = "base.geocoder" | ||
|
||
@api.model | ||
def prepare_geo_address_googlemap(self, place_id): | ||
""" | ||
Prepare Address values by place id | ||
:param str place_id: Google map place id | ||
:return dict: address fields values | ||
""" | ||
google = AddressGoogleStruct(self.env) | ||
if not google.has_token(): | ||
raise models.UserError( | ||
_( | ||
"API key for GeoCoding (Places) required.\n" | ||
"Visit https://developers.google.com/maps/documentation/geocoding/get-api-key " # noqa | ||
"for more information." | ||
) | ||
) | ||
status = google.query_addr({"place_id": place_id}) | ||
return google.get_result() if status else {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from odoo import api, fields, models | ||
|
||
|
||
class PosConfig(models.Model): | ||
_inherit = "pos.config" | ||
|
||
googlemap_api_key = fields.Char(compute="_compute_geolocalize") | ||
|
||
@api.model | ||
def _set_extended_data(self): | ||
data = super(PosConfig, self)._set_extended_data() | ||
ICPSudo = self.env["ir.config_parameter"].sudo() | ||
data.update( | ||
api_key=ICPSudo.get_param("base_geolocalize.google_map_api_key", False) | ||
) | ||
return data | ||
|
||
def _set_pos_config_parameter(self, tech_name, ext_vals=None): | ||
super(PosConfig, self)._set_pos_config_parameter(tech_name, ext_vals) | ||
key = ext_vals.get("api_key", "") if tech_name == "googlemap" else "" | ||
for config in self: | ||
config.googlemap_api_key = key | ||
return |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
In General Settings -> Integrations enable the Geo Localisation checkbox. | ||
Select provided and add API key. NB: only google maps are currently supported. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* Cetmix <https://cetmix.com/> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
This module allows to select partner address directly on map. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
In POS open customer list, select a customer and click "Details". | ||
On the customer form click on the "globe" icon and select a location on map. | ||
Click "Save" to save the location. |
22 changes: 22 additions & 0 deletions
22
pos_partner_location_google_map/static/src/js/PartnerDetailsMapGoogleEdit.esm.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/** @odoo-module **/ | ||
|
||
import PartnerDetailsEdit from "point_of_sale.PartnerDetailsEdit"; | ||
import Registries from "point_of_sale.Registries"; | ||
|
||
const PartnerDetailsMapGoogleEdit = (PartnerDetailsEdit) => | ||
class PartnerDetailsMapGoogleEdit extends PartnerDetailsEdit { | ||
get accessToMap() { | ||
this.config = this.env.pos.config; | ||
if ( | ||
this.config.geolocalize_tech_name === "googlemap" && | ||
this.config.googlemap_api_key | ||
) { | ||
return true; | ||
} | ||
return super.accessToMap; | ||
} | ||
}; | ||
|
||
Registries.Component.extend(PartnerDetailsEdit, PartnerDetailsMapGoogleEdit); | ||
|
||
export default PartnerDetailsMapGoogleEdit; |
113 changes: 113 additions & 0 deletions
113
pos_partner_location_google_map/static/src/js/PartnerMapGoogleEdit.esm.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
/** @odoo-module **/ | ||
|
||
import PartnerMapEdit from "pos_partner_location_abstract.PartnerMapEdit"; | ||
import Registries from "point_of_sale.Registries"; | ||
import {loadJS} from "@web/core/assets"; | ||
import {onMounted, onWillStart} from "@odoo/owl"; | ||
|
||
/* eslint no-undef: "warn"*/ | ||
const PartnerMapGoogleEdit = (PartnerMapEdit) => | ||
class PartnerMapGoogleEdit extends PartnerMapEdit { | ||
onHandleMap() { | ||
if ( | ||
this.config.geolocalize_tech_name === "googlemap" && | ||
this.config.googlemap_api_key | ||
) { | ||
this.provider = "googlemap"; | ||
onWillStart(async () => | ||
loadJS( | ||
`https://maps.googleapis.com/maps/api/js?key=${this.config.googlemap_api_key}&libraries=places` | ||
) | ||
); | ||
onMounted(() => this.googleMapConfigure()); | ||
} else { | ||
super.onHandleMap(); | ||
} | ||
} | ||
|
||
googleMapConfigure() { | ||
// Default latLng | ||
// Config | ||
this.geocoder = new google.maps.Geocoder(); | ||
const latLng = new google.maps.LatLng(this.lat, this.lng); | ||
const mapOptions = { | ||
zoom: 12, | ||
center: latLng, | ||
}; | ||
// Show Map | ||
this.map = new google.maps.Map(this.mapContainerRef.el, mapOptions); | ||
|
||
if (this.lat && this.lng) { | ||
this.setAddressByLatLng(this.lat, this.lng); | ||
} else { | ||
this.setAddressByLocation(this.partner.contact_address); | ||
} | ||
|
||
this.marker = new google.maps.Marker({ | ||
position: latLng, | ||
map: this.map, | ||
draggable: true, | ||
}); | ||
|
||
this.addrInput.el.value = this.partner.contact_address; | ||
|
||
this.map.addListener("click", (event) => { | ||
const lat = event.latLng.lat(); | ||
const lng = event.latLng.lng(); | ||
this.update_marker(lat, lng); | ||
this.setAddressByLatLng(lat, lng); | ||
}); | ||
} | ||
|
||
setAddressByLatLng(lat, lng) { | ||
if (lat && lng) { | ||
const latLng = new google.maps.LatLng(lat, lng); | ||
this.geocoder.geocode({location: latLng}, (results, status) => { | ||
if (status === google.maps.GeocoderStatus.OK) { | ||
this.getFormattedAddress(results[0].place_id); | ||
this.addrInput.el.value = results[0].formatted_address; | ||
} | ||
}); | ||
} | ||
} | ||
|
||
update_marker(lat, lng) { | ||
super.update_marker(lat, lng); | ||
if (this.provider === "googlemap") { | ||
const latLng = new google.maps.LatLng(lat, lng); | ||
this.map.setCenter(latLng); | ||
this.marker.setPosition(latLng); | ||
google.maps.event.trigger(this.map, "resize"); | ||
} | ||
} | ||
|
||
setAddressByLocation(address) { | ||
if (address && this.provider === "googlemap") { | ||
this.geocoder.geocode({address: address}, (results, status) => { | ||
if (status === google.maps.GeocoderStatus.OK) { | ||
this.lat = results[0].geometry.location.lat(); | ||
this.lng = results[0].geometry.location.lng(); | ||
this.getFormattedAddress(results[0].place_id); | ||
this.addrInput.el.value = results[0].formatted_address; | ||
this.update_marker(this.lat, this.lng); | ||
} | ||
}); | ||
} else { | ||
super.setAddressByLocation(address); | ||
} | ||
} | ||
|
||
getFormattedAddress(place_id) { | ||
this.rpc({ | ||
model: "base.geocoder", | ||
method: "prepare_geo_address_googlemap", | ||
args: [place_id], | ||
}).then((resp) => { | ||
this.address = resp; | ||
}); | ||
} | ||
}; | ||
|
||
Registries.Component.extend(PartnerMapEdit, PartnerMapGoogleEdit); | ||
|
||
export default PartnerMapGoogleEdit; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from . import common | ||
from . import test_address_google_struct | ||
from . import test_base_geocoder |
Oops, something went wrong.