new functionality for tzm.at
|
|
@ -0,0 +1,3 @@
|
||||||
|
.DS_Store
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
|
@ -0,0 +1,289 @@
|
||||||
|
Web Google Maps
|
||||||
|
===============
|
||||||
|
|
||||||
|
[](https://youtu.be/5hvAubXgUnc "Demo")
|
||||||
|
|
||||||
|
|
||||||
|
This module contains three new features:
|
||||||
|
- New view type and mode `map`
|
||||||
|
- New widget `gplaces_address_autocomplete`
|
||||||
|
- New widget `gplaces_autocomplete`
|
||||||
|
|
||||||
|
|
||||||
|
# Map view `"map"`
|
||||||
|
Basically, this new view `map` will integrate Google Maps into Odoo.
|
||||||
|
Enable you to display `res.partner` geolocation on map or any model contains geolocation.
|
||||||
|
This feature will work seamlessly with Odoo means you can search your partner location using Odoo search feature.
|
||||||
|
|
||||||
|
There are five available attributes that you can customize
|
||||||
|
- `lat` : an attritube to tell the map the latitude field on the object __[mandatory]__
|
||||||
|
- `lng` : an attritute to tell the map the longitude field on the object __[mandatory]__
|
||||||
|
- `color` : an attribute to modify marker color (optional) any given color will set all markers color __[optional]__.
|
||||||
|
- `colors` : work like attribute `color` but more configurable (you can set marker color depends on it's value) this attribute works similar to `colors` of tree view on Odoo 9.0 __[optional]__
|
||||||
|
- `library` : an attribute to tell map which map that will be loaded __[mandatory]__.
|
||||||
|
This options has two values:
|
||||||
|
1. `geometry`
|
||||||
|
2. `drawing`
|
||||||
|
|
||||||
|
How to create the view?
|
||||||
|
Example
|
||||||
|
>
|
||||||
|
<!-- View -->
|
||||||
|
<record id="view_res_partner_map" model="ir.ui.view">
|
||||||
|
<field name="name">view.res.partner.map</field>
|
||||||
|
<field name="model">res.partner</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<map class="o_res_partner_map" library='geometry' string="Map" lat="partner_latitude" lng="partner_longitude" colors="blue:company_type=='person';green:company_type=='company';">
|
||||||
|
<field name="id"/>
|
||||||
|
<field name="partner_latitude"/>
|
||||||
|
<field name="partner_longitude"/>
|
||||||
|
<field name="company_type"/>
|
||||||
|
<field name="color"/>
|
||||||
|
<field name="display_name"/>
|
||||||
|
<field name="title"/>
|
||||||
|
<field name="email"/>
|
||||||
|
<field name="parent_id"/>
|
||||||
|
<field name="is_company"/>
|
||||||
|
<field name="function"/>
|
||||||
|
<field name="phone"/>
|
||||||
|
<field name="street"/>
|
||||||
|
<field name="street2"/>
|
||||||
|
<field name="zip"/>
|
||||||
|
<field name="city"/>
|
||||||
|
<field name="country_id"/>
|
||||||
|
<field name="mobile"/>
|
||||||
|
<field name="state_id"/>
|
||||||
|
<field name="category_id"/>
|
||||||
|
<field name="image_small"/>
|
||||||
|
<field name="type"/>
|
||||||
|
<templates>
|
||||||
|
<t t-name="kanban-box">
|
||||||
|
<div class="oe_kanban_global_click o_res_partner_kanban">
|
||||||
|
<div class="o_kanban_image">
|
||||||
|
<t t-if="record.image_small.raw_value">
|
||||||
|
<img t-att-src="kanban_image('res.partner', 'image_small', record.id.raw_value)"/>
|
||||||
|
</t>
|
||||||
|
<t t-if="!record.image_small.raw_value">
|
||||||
|
<t t-if="record.type.raw_value === 'delivery'">
|
||||||
|
<img t-att-src='_s + "/base/static/src/img/truck.png"' class="o_kanban_image oe_kanban_avatar_smallbox"/>
|
||||||
|
</t>
|
||||||
|
<t t-if="record.type.raw_value === 'invoice'">
|
||||||
|
<img t-att-src='_s + "/base/static/src/img/money.png"' class="o_kanban_image oe_kanban_avatar_smallbox"/>
|
||||||
|
</t>
|
||||||
|
<t t-if="record.type.raw_value != 'invoice' && record.type.raw_value != 'delivery'">
|
||||||
|
<t t-if="record.is_company.raw_value === true">
|
||||||
|
<img t-att-src='_s + "/base/static/src/img/company_image.png"'/>
|
||||||
|
</t>
|
||||||
|
<t t-if="record.is_company.raw_value === false">
|
||||||
|
<img t-att-src='_s + "/base/static/src/img/avatar.png"'/>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
<div class="oe_kanban_details">
|
||||||
|
<strong class="o_kanban_record_title oe_partner_heading">
|
||||||
|
<field name="display_name"/>
|
||||||
|
</strong>
|
||||||
|
<div class="o_kanban_tags_section oe_kanban_partner_categories">
|
||||||
|
<span class="oe_kanban_list_many2many">
|
||||||
|
<field name="category_id" widget="many2many_tags" options="{'color_field': 'color'}"/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
<li t-if="record.parent_id.raw_value and !record.function.raw_value">
|
||||||
|
<field name="parent_id"/>
|
||||||
|
</li>
|
||||||
|
<li t-if="!record.parent_id.raw_value and record.function.raw_value">
|
||||||
|
<field name="function"/>
|
||||||
|
</li>
|
||||||
|
<li t-if="record.parent_id.raw_value and record.function.raw_value">
|
||||||
|
<field name="function"/> at <field name="parent_id"/>
|
||||||
|
</li>
|
||||||
|
<li t-if="record.city.raw_value and !record.country_id.raw_value">
|
||||||
|
<field name="city"/>
|
||||||
|
</li>
|
||||||
|
<li t-if="!record.city.raw_value and record.country_id.raw_value">
|
||||||
|
<field name="country_id"/>
|
||||||
|
</li>
|
||||||
|
<li t-if="record.city.raw_value and record.country_id.raw_value">
|
||||||
|
<field name="city"/>
|
||||||
|
, <field name="country_id"/>
|
||||||
|
</li>
|
||||||
|
<li t-if="record.email.raw_value" class="o_text_overflow">
|
||||||
|
<field name="email"/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="oe_kanban_partner_links"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</templates>
|
||||||
|
</map>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Action -->
|
||||||
|
<record id="action_partner_map" model="ir.actions.act_window">
|
||||||
|
...
|
||||||
|
<field name="view_type">form</field>
|
||||||
|
<field name="view_mode">tree,form,map</field>
|
||||||
|
...
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
The view looks familiar?
|
||||||
|
Yes, you're right.
|
||||||
|
The marker infowindow will use `kanban-box` kanban card style.
|
||||||
|
|
||||||
|
|
||||||
|
### How to setup color for marker on map?
|
||||||
|
There are two attributes:
|
||||||
|
- `colors`
|
||||||
|
- `color`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
>
|
||||||
|
<!-- colors -->
|
||||||
|
<map string="Map" lat="partner_latitude" lng="partner_longitude" colors="green:company_type=='person';blue:company_type=='company';">
|
||||||
|
...
|
||||||
|
</map>
|
||||||
|
|
||||||
|
<!-- color -->
|
||||||
|
<map string="Map" lat="partner_latitude" lng="partner_longitude" color="orange">
|
||||||
|
...
|
||||||
|
</map>
|
||||||
|
|
||||||
|
|
||||||
|
# New widget `"gplaces_address_autocomplete"`
|
||||||
|
|
||||||
|
New widget to integrate [Place Autocomplete Address Form](https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete-addressform) in Odoo.
|
||||||
|
The widget has four options that can be modify:
|
||||||
|
- `component_form`
|
||||||
|
- `fillfields`
|
||||||
|
- `lat`
|
||||||
|
- `lng`
|
||||||
|
|
||||||
|
### Component form `component_form`
|
||||||
|
Is an option used to modify which value you want to take from an objects returned by the geocoder.
|
||||||
|
Full documentation about Google component types can be found [here](https://developers.google.com/maps/documentation/geocoding/intro#Types)
|
||||||
|
By default this option are configured like the following value
|
||||||
|
>
|
||||||
|
{
|
||||||
|
'street_number': 'long_name',
|
||||||
|
'route': 'long_name',
|
||||||
|
'intersection': 'short_name',
|
||||||
|
'political': 'short_name',
|
||||||
|
'country': 'short_name',
|
||||||
|
'administrative_area_level_1': 'short_name',
|
||||||
|
'administrative_area_level_2': 'short_name',
|
||||||
|
'administrative_area_level_3': 'short_name',
|
||||||
|
'administrative_area_level_4': 'short_name',
|
||||||
|
'administrative_area_level_5': 'short_name',
|
||||||
|
'colloquial_area': 'short_name',
|
||||||
|
'locality': 'short_name',
|
||||||
|
'ward': 'short_name',
|
||||||
|
'sublocality_level_1': 'short_name',
|
||||||
|
'sublocality_level_2': 'short_name',
|
||||||
|
'sublocality_level_3': 'short_name',
|
||||||
|
'sublocality_level_5': 'short_name',
|
||||||
|
'neighborhood': 'short_name',
|
||||||
|
'premise': 'short_name',
|
||||||
|
'postal_code': 'short_name',
|
||||||
|
'natural_feature': 'short_name',
|
||||||
|
'airport': 'short_name',
|
||||||
|
'park': 'short_name',
|
||||||
|
'point_of_interest': 'long_name'
|
||||||
|
}
|
||||||
|
|
||||||
|
This configuration can be modify into view field definition.
|
||||||
|
Example:
|
||||||
|
>
|
||||||
|
<record id="view_res_partner_form" model="ir.ui.view">
|
||||||
|
...
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
...
|
||||||
|
<field name="street" widget="gplaces_address_form" options="{'component_form': {'street_number': 'short_name'}}"/>
|
||||||
|
...
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
### Fill fields `fillfields`
|
||||||
|
Is an option that will be influenced by `gplaces_address_autocomplete` widget.
|
||||||
|
This options should contains known `fields` that you want the widget to fulfill a value for each given field automatically.
|
||||||
|
A field can contains one or multiple elements of component form
|
||||||
|
By default this options are configured like the following
|
||||||
|
>
|
||||||
|
{
|
||||||
|
'street': ['street_number', 'route'],
|
||||||
|
'street2': ['administrative_area_level_3', 'administrative_area_level_4', 'administrative_area_level_5'],
|
||||||
|
'city': ['locality', 'administrative_area_level_2'],
|
||||||
|
'zip': 'postal_code',
|
||||||
|
'state_id': 'administrative_area_level_1',
|
||||||
|
'country_id': 'country',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
This configuration can be modify into view field definition as well
|
||||||
|
Example:
|
||||||
|
>
|
||||||
|
<record id="view_res_partner_form" model="ir.ui.view">
|
||||||
|
...
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
...
|
||||||
|
<field name="street" widget="google_places" options="{'fillfields': {'street2': ['route', 'street_number']}}"/>
|
||||||
|
...
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
### Latitude `lat` and Longitude `lng`
|
||||||
|
This options tell the widget the fields geolocation, in order to have this fields filled automatically.
|
||||||
|
|
||||||
|
|
||||||
|
# New widget `"gplaces_autocomplete"`
|
||||||
|
|
||||||
|
New widget to integrate [Place Autocomplete](https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete) in Odoo.
|
||||||
|
This widget have similar configuration to `gplaces_address_autocomplete`.
|
||||||
|
|
||||||
|
### Component form `component_form` ###
|
||||||
|
Same configuration of `gplaces_address_autocomplete` component form
|
||||||
|
|
||||||
|
### Fill fields `fillfields`
|
||||||
|
This configuration works similar to `gplaces_address_autocomplete`.
|
||||||
|
By default this options are configured like following value:
|
||||||
|
>
|
||||||
|
{
|
||||||
|
general: {
|
||||||
|
name: 'name',
|
||||||
|
website: 'website',
|
||||||
|
phone: ['international_phone_number', 'formatted_phone_number']
|
||||||
|
},
|
||||||
|
geolocation: {
|
||||||
|
partner_latitude: 'latitude',
|
||||||
|
partner_longitude: 'longitude'
|
||||||
|
},
|
||||||
|
address: {
|
||||||
|
street: ['street_number', 'route'],
|
||||||
|
street2: ['administrative_area_level_3', 'administrative_area_level_4', 'administrative_area_level_5'],
|
||||||
|
city: ['locality', 'administrative_area_level_2'],
|
||||||
|
zip: 'postal_code',
|
||||||
|
state_id: 'administrative_area_level_1',
|
||||||
|
country_id: 'country'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
# Technical
|
||||||
|
This module will install `base_setup` and `base_geolocalize`.
|
||||||
|
*I recommend you to setup __Google Maps Key API__ and add it into Odoo `Settings > General` Settings when you installed this module*
|
||||||
|
|
||||||
|
*__List of Google APIs & services required in order to make all features works__*
|
||||||
|
- Geocoding API
|
||||||
|
- Maps JavaScript API
|
||||||
|
- Places API for Web
|
||||||
|
|
||||||
|
|
||||||
|
The goal of this module is to bring the power of Google Maps into Odoo
|
||||||
|
This module has tested on Odoo Version 11.0c
|
||||||
|
|
||||||
|
[](https://ko-fi.com/P5P4FOM0)
|
||||||
|
*if you want to support me to keep this project maintained. Thanks :)*
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# License AGPL-3
|
||||||
|
from . import models
|
||||||
|
from . import controllers
|
||||||
|
from .hooks import uninstall_hook
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
{
|
||||||
|
'name': 'Web Google Maps',
|
||||||
|
'version': '11.0.1.0.5',
|
||||||
|
'author': 'Yopi Angi',
|
||||||
|
'license': 'AGPL-3',
|
||||||
|
'maintainer': 'Yopi Angi<yopiangi@gmail.com>',
|
||||||
|
'support': 'yopiangi@gmail.com',
|
||||||
|
'category': 'Extra Tools',
|
||||||
|
'description': """
|
||||||
|
Web Google Map and google places autocomplete address form
|
||||||
|
==========================================================
|
||||||
|
|
||||||
|
This module brings three features:
|
||||||
|
1. Allows user to view all partners addresses on google maps.
|
||||||
|
2. Enabled google places autocomplete address form into partner
|
||||||
|
form view, it provide autocomplete feature when typing address of partner
|
||||||
|
""",
|
||||||
|
'depends': [
|
||||||
|
'base_setup',
|
||||||
|
'base_geolocalize',
|
||||||
|
],
|
||||||
|
'website': '',
|
||||||
|
'data': [
|
||||||
|
'data/google_maps_libraries.xml',
|
||||||
|
'views/google_places_template.xml',
|
||||||
|
'views/res_partner.xml',
|
||||||
|
'views/res_config.xml'
|
||||||
|
],
|
||||||
|
'demo': [],
|
||||||
|
'images': ['static/description/thumbnails.png'],
|
||||||
|
'qweb': ['static/src/xml/widget_places.xml'],
|
||||||
|
'installable': True,
|
||||||
|
'uninstall_hook': 'uninstall_hook',
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from . import main
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from odoo import http
|
||||||
|
|
||||||
|
|
||||||
|
class Main(http.Controller):
|
||||||
|
|
||||||
|
@http.route('/web/map_theme', type='json', auth='user')
|
||||||
|
def map_theme(self):
|
||||||
|
ICP = http.request.env['ir.config_parameter'].sudo()
|
||||||
|
theme = ICP.get_param('google.maps_theme', default='default')
|
||||||
|
res = {'theme': theme}
|
||||||
|
return res
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<data noupdate="1">
|
||||||
|
<function model="ir.config_parameter" name="set_param" eval="('google.maps_libraries', 'geometry,places')"/>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# License AGPL-3
|
||||||
|
|
||||||
|
def uninstall_hook(cr, registry):
|
||||||
|
cr.execute("UPDATE ir_act_window "
|
||||||
|
"SET view_mode=replace(view_mode, ',map', '')"
|
||||||
|
"WHERE view_mode LIKE '%,map%';")
|
||||||
|
cr.execute("UPDATE ir_act_window "
|
||||||
|
"SET view_mode=replace(view_mode, 'map,', '')"
|
||||||
|
"WHERE view_mode LIKE '%map,%';")
|
||||||
|
cr.execute("DELETE FROM ir_act_window "
|
||||||
|
"WHERE view_mode = 'map';")
|
||||||
|
|
@ -0,0 +1,466 @@
|
||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * web_google_maps
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 11.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2018-10-09 16:04+0000\n"
|
||||||
|
"PO-Revision-Date: 2018-10-09 16:04+0000\n"
|
||||||
|
"Last-Translator: <>\n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: \n"
|
||||||
|
"Plural-Forms: \n"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_web_google_maps_config_settings
|
||||||
|
msgid "Api key"
|
||||||
|
msgstr "Api key"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Arabic"
|
||||||
|
msgstr "Arabic"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_theme:0
|
||||||
|
msgid "Aubergine"
|
||||||
|
msgstr "Aubergine"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Basque"
|
||||||
|
msgstr "Basque"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Bengali"
|
||||||
|
msgstr "Bengali"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Bulgarian"
|
||||||
|
msgstr "Bulgarian"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Catalan"
|
||||||
|
msgstr "Catalan"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Chinese (Simplified)"
|
||||||
|
msgstr "Chinese (Simplified)"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Chinese (Traditional)"
|
||||||
|
msgstr "Chinese (Traditional)"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_web_google_maps_config_settings
|
||||||
|
msgid "Configure your Google Maps View"
|
||||||
|
msgstr "Configure your Google Maps View"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Croatian"
|
||||||
|
msgstr "Croatian"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Czech"
|
||||||
|
msgstr "Czech"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Danish"
|
||||||
|
msgstr "Danish"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_theme:0
|
||||||
|
msgid "Dark"
|
||||||
|
msgstr "Dark"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_theme:0
|
||||||
|
msgid "Default"
|
||||||
|
msgstr "Default"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Dutch"
|
||||||
|
msgstr "Dutch"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "English"
|
||||||
|
msgstr "English"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "English (Australian)"
|
||||||
|
msgstr "English (Australian)"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "English (Great Britain)"
|
||||||
|
msgstr "English (Great Britain)"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Farsi"
|
||||||
|
msgstr "Farsi"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Filipino"
|
||||||
|
msgstr "Filipino"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Finnish"
|
||||||
|
msgstr "Finnish"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "French"
|
||||||
|
msgstr "French"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Galician"
|
||||||
|
msgstr "Galician"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.model.fields,field_description:web_google_maps.field_res_config_settings_google_maps_geometry
|
||||||
|
msgid "Geometry"
|
||||||
|
msgstr "Geometry"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_web_google_maps_config_settings
|
||||||
|
msgid "Geometry includes utility functions for calculating scalar geometric values (such as distance and area) on the surface of the earth. \n"
|
||||||
|
" Consult the"
|
||||||
|
msgstr "Geometry includes utility functions for calculating scalar geometric values (such as distance and area) on the surface of the earth. \n"
|
||||||
|
" Consult the"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_web_google_maps_config_settings
|
||||||
|
msgid "Geometry library documentation"
|
||||||
|
msgstr "Geometry library documentation"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "German"
|
||||||
|
msgstr "German"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.model.fields,field_description:web_google_maps.field_res_config_settings_google_maps_lang_localization
|
||||||
|
msgid "Google Maps Language Localization"
|
||||||
|
msgstr "Google Maps Language Localization"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_web_google_maps_config_settings
|
||||||
|
msgid "Google Maps Libraries"
|
||||||
|
msgstr "Google Maps Libraries"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.model.fields,field_description:web_google_maps.field_res_config_settings_google_maps_region_localization
|
||||||
|
msgid "Google Maps Region Localization"
|
||||||
|
msgstr "Google Maps Region Localization"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_web_google_maps_config_settings
|
||||||
|
msgid "Google Maps View"
|
||||||
|
msgstr "Google Maps View"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.model.fields,field_description:web_google_maps.field_res_config_settings_google_maps_view_api_key
|
||||||
|
msgid "Google Maps View Api Key"
|
||||||
|
msgstr "Google Maps View Api Key"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Greek"
|
||||||
|
msgstr "Greek"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Gujarati"
|
||||||
|
msgstr "Gujarati"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Hebrew"
|
||||||
|
msgstr "Hebrew"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Hindi"
|
||||||
|
msgstr "Hindi"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Hungarian"
|
||||||
|
msgstr "Hungarian"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_web_google_maps_config_settings
|
||||||
|
msgid "If you set the language of the map, it's important to consider setting the region too. This helps ensure that your application complies with local laws."
|
||||||
|
msgstr "If you set the language of the map, it's important to consider setting the region too. This helps ensure that your application complies with local laws."
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Indonesian"
|
||||||
|
msgstr "Indonesian"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Italian"
|
||||||
|
msgstr "Italian"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Japanese"
|
||||||
|
msgstr "Japanese"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Kannada"
|
||||||
|
msgstr "Kannada"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Korean"
|
||||||
|
msgstr "Korean"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_web_google_maps_config_settings
|
||||||
|
msgid "Language"
|
||||||
|
msgstr "Language"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Latvian"
|
||||||
|
msgstr "Latvian"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Lithuanian"
|
||||||
|
msgstr "Lithuanian"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Malayalam"
|
||||||
|
msgstr "Malayalam"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#. openerp-web
|
||||||
|
#: code:addons/web_google_maps/static/src/js/view/map/map_view.js:15
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_res_partner_map
|
||||||
|
#, python-format
|
||||||
|
msgid "Map"
|
||||||
|
msgstr "Map"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.model.fields,field_description:web_google_maps.field_res_config_settings_google_maps_theme
|
||||||
|
msgid "Map theme"
|
||||||
|
msgstr "Map theme"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Marathi"
|
||||||
|
msgstr "Marathi"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_theme:0
|
||||||
|
msgid "Night"
|
||||||
|
msgstr "Night"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Norwegian"
|
||||||
|
msgstr "Norwegian"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.model.fields,field_description:web_google_maps.field_res_config_settings_google_maps_places
|
||||||
|
msgid "Places"
|
||||||
|
msgstr "Places"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_web_google_maps_config_settings
|
||||||
|
msgid "Places enables your application to search for places such as establishments, geographic locations, or prominent points of interest, within a defined area. \n"
|
||||||
|
" Consult the"
|
||||||
|
msgstr "Places enables your application to search for places such as establishments, geographic locations, or prominent points of interest, within a defined area. \n"
|
||||||
|
" Consult the"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_web_google_maps_config_settings
|
||||||
|
msgid "Places library documentation"
|
||||||
|
msgstr "Places library documentation"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Polish"
|
||||||
|
msgstr "Polish"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Portuguese"
|
||||||
|
msgstr "Portuguese"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Portuguese (Brazil)"
|
||||||
|
msgstr "Portuguese (Brazil)"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Portuguese (Portugal)"
|
||||||
|
msgstr "Portuguese (Portugal)"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_web_google_maps_config_settings
|
||||||
|
msgid "Region"
|
||||||
|
msgstr "Region"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_theme:0
|
||||||
|
msgid "Retro"
|
||||||
|
msgstr "Retro"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Romanian"
|
||||||
|
msgstr "Romanian"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Russian"
|
||||||
|
msgstr "Russian"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Serbian"
|
||||||
|
msgstr "Serbian"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_web_google_maps_config_settings
|
||||||
|
msgid "Set API keys and map localization"
|
||||||
|
msgstr "Set API keys and map localization"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_theme:0
|
||||||
|
msgid "Silver"
|
||||||
|
msgstr "Silver"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Slovak"
|
||||||
|
msgstr "Slovak"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Slovenian"
|
||||||
|
msgstr "Slovenian"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Spanish"
|
||||||
|
msgstr "Spanish"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Swedish"
|
||||||
|
msgstr "Swedish"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Tagalog"
|
||||||
|
msgstr "Tagalog"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Tamil"
|
||||||
|
msgstr "Tamil"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Telugu"
|
||||||
|
msgstr "Telugu"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Thai"
|
||||||
|
msgstr "Thai"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#. openerp-web
|
||||||
|
#: code:addons/web_google_maps/static/src/js/widgets/gplaces_autocomplete.js:244
|
||||||
|
#: code:addons/web_google_maps/static/src/js/widgets/gplaces_autocomplete.js:352
|
||||||
|
#, python-format
|
||||||
|
msgid "The following fields are invalid:"
|
||||||
|
msgstr "The following fields are invalid:"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_web_google_maps_config_settings
|
||||||
|
msgid "Theme"
|
||||||
|
msgstr "Theme"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Turkish"
|
||||||
|
msgstr "Turkish"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Ukrainian"
|
||||||
|
msgstr "Ukrainian"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: selection:res.config.settings,google_maps_lang_localization:0
|
||||||
|
msgid "Vietnamese"
|
||||||
|
msgstr "Vietnamese"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_web_google_maps_config_settings
|
||||||
|
msgid "Visit the"
|
||||||
|
msgstr "Visit the"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_web_google_maps_config_settings
|
||||||
|
msgid "about Localizing the Map"
|
||||||
|
msgstr "about Localizing the Map"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_res_partner_map
|
||||||
|
msgid "at"
|
||||||
|
msgstr "at"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_web_google_maps_config_settings
|
||||||
|
msgid "for more information."
|
||||||
|
msgstr "for more information."
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.model,name:web_google_maps.model_ir_actions_act_window_view
|
||||||
|
msgid "ir.actions.act_window.view"
|
||||||
|
msgstr "ir.actions.act_window.view"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.model,name:web_google_maps.model_ir_ui_view
|
||||||
|
msgid "ir.ui.view"
|
||||||
|
msgstr "ir.ui.view"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.ui.view,arch_db:web_google_maps.view_web_google_maps_config_settings
|
||||||
|
msgid "page"
|
||||||
|
msgstr "page"
|
||||||
|
|
||||||
|
#. module: web_google_maps
|
||||||
|
#: model:ir.model,name:web_google_maps.model_res_config_settings
|
||||||
|
msgid "res.config.settings"
|
||||||
|
msgstr "res.config.settings"
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# License AGPL-3
|
||||||
|
from . import ir_act_window_view
|
||||||
|
from . import ir_ui_view
|
||||||
|
from . import res_config
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# License AGPL-3
|
||||||
|
from odoo import fields, models
|
||||||
|
|
||||||
|
|
||||||
|
class IrActionsActWindowView(models.Model):
|
||||||
|
_inherit = 'ir.actions.act_window.view'
|
||||||
|
|
||||||
|
view_mode = fields.Selection(selection_add=[('map', 'Map')])
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# License AGPL-3
|
||||||
|
from odoo import api, fields, models
|
||||||
|
|
||||||
|
|
||||||
|
class IrUiView(models.Model):
|
||||||
|
_inherit = 'ir.ui.view'
|
||||||
|
|
||||||
|
type = fields.Selection(selection_add=[('map', 'Map')])
|
||||||
|
|
@ -0,0 +1,199 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# License AGPL-3
|
||||||
|
from odoo import api, fields, models
|
||||||
|
|
||||||
|
GMAPS_LANG_LOCALIZATION = [
|
||||||
|
('ar', 'Arabic'),
|
||||||
|
('bg', 'Bulgarian'),
|
||||||
|
('bn', 'Bengali'),
|
||||||
|
('ca', 'Catalan'),
|
||||||
|
('cs', 'Czech'),
|
||||||
|
('da', 'Danish'),
|
||||||
|
('de', 'German'),
|
||||||
|
('el', 'Greek'),
|
||||||
|
('en', 'English'),
|
||||||
|
('en-AU', 'English (Australian)'),
|
||||||
|
('en-GB', 'English (Great Britain)'),
|
||||||
|
('es', 'Spanish'),
|
||||||
|
('eu', 'Basque'),
|
||||||
|
('eu', 'Basque'),
|
||||||
|
('fa', 'Farsi'),
|
||||||
|
('fi', 'Finnish'),
|
||||||
|
('fil', 'Filipino'),
|
||||||
|
('fr', 'French'),
|
||||||
|
('gl', 'Galician'),
|
||||||
|
('gu', 'Gujarati'),
|
||||||
|
('hi', 'Hindi'),
|
||||||
|
('hr', 'Croatian'),
|
||||||
|
('hu', 'Hungarian'),
|
||||||
|
('id', 'Indonesian'),
|
||||||
|
('it', 'Italian'),
|
||||||
|
('iw', 'Hebrew'),
|
||||||
|
('ja', 'Japanese'),
|
||||||
|
('kn', 'Kannada'),
|
||||||
|
('ko', 'Korean'),
|
||||||
|
('lt', 'Lithuanian'),
|
||||||
|
('lv', 'Latvian'),
|
||||||
|
('ml', 'Malayalam'),
|
||||||
|
('mr', 'Marathi'),
|
||||||
|
('nl', 'Dutch'),
|
||||||
|
('no', 'Norwegian'),
|
||||||
|
('pl', 'Polish'),
|
||||||
|
('pt', 'Portuguese'),
|
||||||
|
('pt-BR', 'Portuguese (Brazil)'),
|
||||||
|
('pt-PT', 'Portuguese (Portugal)'),
|
||||||
|
('ro', 'Romanian'),
|
||||||
|
('ru', 'Russian'),
|
||||||
|
('sk', 'Slovak'),
|
||||||
|
('sl', 'Slovenian'),
|
||||||
|
('sr', 'Serbian'),
|
||||||
|
('sv', 'Swedish'),
|
||||||
|
('ta', 'Tamil'),
|
||||||
|
('te', 'Telugu'),
|
||||||
|
('th', 'Thai'),
|
||||||
|
('tl', 'Tagalog'),
|
||||||
|
('tr', 'Turkish'),
|
||||||
|
('uk', 'Ukrainian'),
|
||||||
|
('vi', 'Vietnamese'),
|
||||||
|
('zh-CN', 'Chinese (Simplified)'),
|
||||||
|
('zh-TW', 'Chinese (Traditional)'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class ResConfigSettings(models.TransientModel):
|
||||||
|
_inherit = 'res.config.settings'
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def get_region_selection(self):
|
||||||
|
country_ids = self.env['res.country'].search([])
|
||||||
|
values = [(country.code, country.name) for country in country_ids]
|
||||||
|
return values
|
||||||
|
|
||||||
|
google_maps_view_api_key = fields.Char(string='Google Maps View Api Key')
|
||||||
|
google_maps_lang_localization = fields.Selection(
|
||||||
|
selection=GMAPS_LANG_LOCALIZATION,
|
||||||
|
string='Google Maps Language Localization')
|
||||||
|
google_maps_region_localization = fields.Selection(
|
||||||
|
selection=get_region_selection,
|
||||||
|
string='Google Maps Region Localization')
|
||||||
|
google_maps_theme = fields.Selection(
|
||||||
|
selection=[('default', 'Default'),
|
||||||
|
('aubergine', 'Aubergine'),
|
||||||
|
('night', 'Night'),
|
||||||
|
('dark', 'Dark'),
|
||||||
|
('retro', 'Retro'),
|
||||||
|
('silver', 'Silver')],
|
||||||
|
string='Map theme')
|
||||||
|
google_maps_places = fields.Boolean(string='Places', default=True)
|
||||||
|
google_maps_geometry = fields.Boolean(string='Geometry', default=True)
|
||||||
|
|
||||||
|
@api.onchange('google_maps_lang_localization')
|
||||||
|
def onchange_lang_localization(self):
|
||||||
|
if not self.google_maps_lang_localization:
|
||||||
|
self.google_maps_region_localization = ''
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def set_values(self):
|
||||||
|
super(ResConfigSettings, self).set_values()
|
||||||
|
ICPSudo = self.env['ir.config_parameter'].sudo()
|
||||||
|
lang_localization = self._set_google_maps_lang_localization()
|
||||||
|
region_localization = self._set_google_maps_region_localization()
|
||||||
|
|
||||||
|
lib_places = self._set_google_maps_places()
|
||||||
|
lib_geometry = self._set_google_maps_geometry()
|
||||||
|
|
||||||
|
active_libraries = '%s,%s' % (lib_geometry, lib_places)
|
||||||
|
|
||||||
|
ICPSudo.set_param('google.api_key_geocode',
|
||||||
|
self.google_maps_view_api_key)
|
||||||
|
ICPSudo.set_param('google.lang_localization',
|
||||||
|
lang_localization)
|
||||||
|
ICPSudo.set_param('google.region_localization',
|
||||||
|
region_localization)
|
||||||
|
ICPSudo.set_param('google.maps_theme', self.google_maps_theme)
|
||||||
|
ICPSudo.set_param('google.maps_libraries', active_libraries)
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def get_values(self):
|
||||||
|
res = super(ResConfigSettings, self).get_values()
|
||||||
|
ICPSudo = self.env['ir.config_parameter'].sudo()
|
||||||
|
|
||||||
|
lang_localization = self._get_google_maps_lang_localization()
|
||||||
|
region_localization = self._get_google_maps_region_localization()
|
||||||
|
|
||||||
|
lib_places = self._get_google_maps_places()
|
||||||
|
lib_geometry = self._get_google_maps_geometry()
|
||||||
|
|
||||||
|
res.update({
|
||||||
|
'google_maps_view_api_key': ICPSudo.get_param(
|
||||||
|
'google.api_key_geocode', default=''),
|
||||||
|
'google_maps_lang_localization': lang_localization,
|
||||||
|
'google_maps_region_localization': region_localization,
|
||||||
|
'google_maps_theme': ICPSudo.get_param(
|
||||||
|
'google.maps_theme', default='default'),
|
||||||
|
'google_maps_places': lib_places,
|
||||||
|
'google_maps_geometry': lib_geometry
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def _set_google_maps_lang_localization(self):
|
||||||
|
if self.google_maps_lang_localization:
|
||||||
|
lang_localization = '&language=%s' % \
|
||||||
|
self.google_maps_lang_localization
|
||||||
|
else:
|
||||||
|
lang_localization = ''
|
||||||
|
|
||||||
|
return lang_localization
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _get_google_maps_lang_localization(self):
|
||||||
|
ICPSudo = self.env['ir.config_parameter'].sudo()
|
||||||
|
google_maps_lang = ICPSudo.get_param(
|
||||||
|
'google.lang_localization', default='')
|
||||||
|
val = google_maps_lang.split('=')
|
||||||
|
lang = val and val[-1] or ''
|
||||||
|
return lang
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def _set_google_maps_region_localization(self):
|
||||||
|
if self.google_maps_region_localization:
|
||||||
|
region_localization = '®ion=%s' % \
|
||||||
|
self.google_maps_region_localization
|
||||||
|
else:
|
||||||
|
region_localization = ''
|
||||||
|
|
||||||
|
return region_localization
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _get_google_maps_region_localization(self):
|
||||||
|
ICPSudo = self.env['ir.config_parameter'].sudo()
|
||||||
|
google_maps_region = ICPSudo.get_param(
|
||||||
|
'google.region_localization', default='')
|
||||||
|
val = google_maps_region.split('=')
|
||||||
|
region = val and val[-1] or ''
|
||||||
|
return region
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _get_google_maps_geometry(self):
|
||||||
|
ICPSudo = self.env['ir.config_parameter'].sudo()
|
||||||
|
google_maps_libraries = ICPSudo.get_param(
|
||||||
|
'google.maps_libraries', default='')
|
||||||
|
libraries = google_maps_libraries.split(',')
|
||||||
|
return 'geometry' in libraries
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def _set_google_maps_geometry(self):
|
||||||
|
return 'geometry' if self.google_maps_geometry else ''
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _get_google_maps_places(self):
|
||||||
|
ICPSudo = self.env['ir.config_parameter'].sudo()
|
||||||
|
google_maps_libraries = ICPSudo.get_param(
|
||||||
|
'google.maps_libraries', default='')
|
||||||
|
libraries = google_maps_libraries.split(',')
|
||||||
|
return 'places' in libraries
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def _set_google_maps_places(self):
|
||||||
|
return 'places' if self.google_maps_places else ''
|
||||||
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
|
@ -0,0 +1,77 @@
|
||||||
|
<section class="oe_container">
|
||||||
|
<div class="oe_row">
|
||||||
|
<h2 class="oe_slogan" style="color:#875A7B;">Integrate Google Maps into Odoo</h2>
|
||||||
|
<h4 class="oe_slogan">Show all your partners location on Google Maps</h4>
|
||||||
|
<div class="oe_span12">
|
||||||
|
<img class="oe_picture oe_screenshot" src="maps.png">
|
||||||
|
<div class="text-center">
|
||||||
|
<a href="https://youtu.be/5hvAubXgUnc" class="btn btn-primary" target="_blank">Demo Video</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="oe_span12">
|
||||||
|
<p>This module brings four new features:</p>
|
||||||
|
<ul>
|
||||||
|
<li>New view <em>map</em> allows user to view all partners addresses on google maps.</li>
|
||||||
|
<li>
|
||||||
|
New widget <em>gplaces_address_autocomplete</em>, enabled <a target="_blank" href="https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete-addressform">Google places autocomplete address form</a> into partner form view,<br/>
|
||||||
|
provide autocomplete feature when you typing an address of partner (or any field using this widget)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
New widget <em>gplaces_autocomplete</em>, enabled <a target="_blank" href="https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete">Google places autocomplete</a> into partner form view,<br/>
|
||||||
|
provide autocomplete feature when typing partner name (or any field using this widget)
|
||||||
|
</li>
|
||||||
|
<li>Map Localization</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="oe_container">
|
||||||
|
<div class="oe_row oe_spaced">
|
||||||
|
<h4 class="oe_slogan">New Widget Google Place Autocomplete Address Form</h4>
|
||||||
|
<div class="oe_span12">
|
||||||
|
<img class="oe_picture oe_screenshot" src="widget_gplaces_address_form.gif">
|
||||||
|
</div>
|
||||||
|
<div class="oe_span12 oe_mb32">
|
||||||
|
<p>Provide autocomplete feature when typing an address</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="oe_container">
|
||||||
|
<div class="oe_row oe_spaced">
|
||||||
|
<h4 class="oe_slogan">New Widget Google Place Autocomplete</h4>
|
||||||
|
<div class="oe_span12">
|
||||||
|
<img class="oe_picture oe_screenshot" src="widget_gplaces_autocomplete.gif">
|
||||||
|
</div>
|
||||||
|
<div class="oe_span12 oe_mb32">
|
||||||
|
<p>Provide autocomplete feature when typing partner's name</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="oe_container">
|
||||||
|
<div class="oe_row oe_spaced">
|
||||||
|
<div class="oe_span12">
|
||||||
|
<h2>Bug Tracker</h2>
|
||||||
|
<p>Bugs are tracked on
|
||||||
|
<a class="reference external" target="_blank" href="https://github.com/gityopie/odoo-addons/issues">GitHub Issues</a>. In case of trouble, please check there if your issue has already been reported. If you spotted
|
||||||
|
it first, help us smashing it by providing a detailed and welcomed feedback.</p>
|
||||||
|
</div>
|
||||||
|
<div class="oe_span12">
|
||||||
|
<h3>Contributors</h3>
|
||||||
|
<ul class="simple">
|
||||||
|
<li>Yopi Angi <
|
||||||
|
<a class="reference external" href="mailto:yopiangi@gmail.com">yopiangi@gmail.com</a>></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="oe_span12">
|
||||||
|
<h3>Maintainer</h3>
|
||||||
|
<p>This module is maintained by myself, if you are interested to contribute please let me know</p>
|
||||||
|
<a href="https://ko-fi.com/P5P4FOM0" target="_blank">
|
||||||
|
<img src="https://www.ko-fi.com/img/donate_sm.png" alt="ko-fi"/>
|
||||||
|
</a>
|
||||||
|
<p>Thank you</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
After Width: | Height: | Size: 334 KiB |
|
After Width: | Height: | Size: 255 KiB |
|
After Width: | Height: | Size: 246 KiB |
|
After Width: | Height: | Size: 457 KiB |
|
After Width: | Height: | Size: 303 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
|
@ -0,0 +1,155 @@
|
||||||
|
/* https://github.com/twbs/bootstrap/issues/4160 */
|
||||||
|
/* put google places autocomplete dropdown results above the bootstrap modal 1050 zindex. */
|
||||||
|
.pac-container {
|
||||||
|
z-index: 1051 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map .o_map_view {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map .o_map_sidenav {
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
max-width: 400px;
|
||||||
|
width: 400px;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
overflow-x: hidden;
|
||||||
|
transition: 0.5s;
|
||||||
|
transform: translate3d(0, 0, 0);
|
||||||
|
-webkit-transform: translate3d(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map .o_map_sidenav.whiteframe {
|
||||||
|
box-shadow: 0 2px 4px -1px rgba(0, 0, 0, .2), 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map .o_map_sidenav.closed {
|
||||||
|
transform: translate3d(-100%, 0, 0);
|
||||||
|
-webkit-transform: translate3d(-100%, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map .o_map_sidenav .sidenav-body .panel {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_act_window .o_map .o_map_view,
|
||||||
|
.o_act_window .o_map .o_map_sidenav {
|
||||||
|
min-height: 400px;
|
||||||
|
height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map .o_map_sidenav .controls,
|
||||||
|
.o_map .o_map_sidenav .layers {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map .o_map_sidenav .controls span.active,
|
||||||
|
.o_map .o_map_sidenav .layers span.active {
|
||||||
|
color: #7c7bad;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map .o_map_sidenav .controls span img,
|
||||||
|
.o_map .o_map_sidenav .layers span img {
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map_control .btn_map_control {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-left: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: margin-left .5s;
|
||||||
|
line-height: 20px;
|
||||||
|
padding: 4.5px 10px;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 2px;
|
||||||
|
box-shadow: rgba(0, 0, 0, 0.3) 0px 1px 4px -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map_control .btn_map_control.opened {
|
||||||
|
margin-left: 410px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map_routes_window {
|
||||||
|
min-width: 100px;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-left: 15px;
|
||||||
|
opacity: 0.8;
|
||||||
|
background: #ffffff;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map_redirect_google {
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
width: 25px;
|
||||||
|
height: 25px;
|
||||||
|
margin-right: 15px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 2px;
|
||||||
|
line-height: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map_places_control .pac-card #pac-container #pac-button {
|
||||||
|
padding-top: 5px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map_places_control .pac-card #pac-container #pac-result {
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map_places_control .pac-card .pac-controls {
|
||||||
|
padding: 0 0 10px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map_places_control .pac-card .pac-controls label {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map_places_control .pac-card #pac-input {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 300;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map_places_control .pac-card #pac-input:focus {
|
||||||
|
border-color: #7c7bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map_place_result input#place-input-name {
|
||||||
|
background-color: #efefef;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 300;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map_place_result ul {
|
||||||
|
list-style-type: none;
|
||||||
|
margin-left: -30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map_place_result ul li i {
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_control_panel .o_map_buttons_view>button:first-child {
|
||||||
|
float: left;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 313 B |
|
After Width: | Height: | Size: 185 B |
|
After Width: | Height: | Size: 217 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 313 B |
|
After Width: | Height: | Size: 198 B |
|
After Width: | Height: | Size: 217 B |
|
After Width: | Height: | Size: 231 B |
|
|
@ -0,0 +1,61 @@
|
||||||
|
odoo.define('web_google_maps.relational_fields', function (require) {
|
||||||
|
|
||||||
|
var core = require('web.core');
|
||||||
|
var relational_fields = require('web.relational_fields');
|
||||||
|
var MapRenderer = require('web_google_maps.MapRenderer');
|
||||||
|
|
||||||
|
var qweb = core.qweb;
|
||||||
|
|
||||||
|
relational_fields.FieldOne2Many.include({
|
||||||
|
_render: function () {
|
||||||
|
if (!this.view || this.renderer) {
|
||||||
|
return this._super();
|
||||||
|
}
|
||||||
|
var arch = this.view.arch;
|
||||||
|
var viewType;
|
||||||
|
if (arch.tag == 'map') {
|
||||||
|
viewType = 'map';
|
||||||
|
var record_options = {
|
||||||
|
editable: true,
|
||||||
|
deletable: true,
|
||||||
|
read_only_mode: this.isReadonly
|
||||||
|
}
|
||||||
|
this.renderer = new MapRenderer(this, this.value, {
|
||||||
|
arch: arch,
|
||||||
|
record_options: record_options,
|
||||||
|
viewType: viewType,
|
||||||
|
fieldLat: arch.attrs.lat,
|
||||||
|
fieldLng: arch.attrs.lng,
|
||||||
|
markerColor: arch.attrs.color,
|
||||||
|
mapLibrary: arch.attrs.library,
|
||||||
|
drawingMode: arch.attrs.drawing_mode,
|
||||||
|
drawingPath: arch.attrs.drawing_path
|
||||||
|
});
|
||||||
|
this.$el.addClass('o_field_x2many o_field_x2many_' + viewType);
|
||||||
|
return this.renderer.appendTo(this.$el);
|
||||||
|
}
|
||||||
|
return this._super();
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Override
|
||||||
|
*/
|
||||||
|
_renderButtons: function () {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
if (this.view.arch.tag === 'map') {
|
||||||
|
var options = {create_text: this.nodeOptions.create_text, widget: this};
|
||||||
|
this.$buttons = $(qweb.render('MapView.buttons', options));
|
||||||
|
this.$buttons.on('click', 'button.o-map-button-new', this._onAddRecord.bind(this));
|
||||||
|
this.$buttons.on('click', 'button.o-map-button-center-map', this._onMapCenter.bind(this));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_onMapCenter: function (event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
if (this.renderer.mapLibrary === 'geometry') {
|
||||||
|
this.renderer.mapGeometryCentered();
|
||||||
|
} else if (this.renderer.mapLibrary === 'drawing') {
|
||||||
|
this.renderer.mapShapesCentered();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,181 @@
|
||||||
|
odoo.define('web_google_maps.MapController', function (require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var Context = require('web.Context');
|
||||||
|
var core = require('web.core');
|
||||||
|
var BasicController = require('web.BasicController');
|
||||||
|
var Domain = require('web.Domain');
|
||||||
|
|
||||||
|
var _t = core._t;
|
||||||
|
var qweb = core.qweb;
|
||||||
|
|
||||||
|
var MapController = BasicController.extend({
|
||||||
|
custom_events: _.extend({}, BasicController.prototype.custom_events, {
|
||||||
|
button_clicked: '_onButtonClicked',
|
||||||
|
kanban_record_delete: '_onRecordDelete',
|
||||||
|
kanban_record_update: '_onUpdateRecord',
|
||||||
|
kanban_column_archive_records: '_onArchiveRecords',
|
||||||
|
}),
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* @param {Object} params
|
||||||
|
*/
|
||||||
|
init: function (parent, model, renderer, params) {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
|
||||||
|
this.on_create = params.on_create;
|
||||||
|
this.hasButtons = params.hasButtons;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {OdooEvent} event
|
||||||
|
*/
|
||||||
|
_onButtonClicked: function (event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
var self = this;
|
||||||
|
var attrs = event.data.attrs;
|
||||||
|
var record = event.data.record;
|
||||||
|
if (attrs.context) {
|
||||||
|
attrs.context = new Context(attrs.context)
|
||||||
|
.set_eval_context({
|
||||||
|
active_id: record.res_id,
|
||||||
|
active_ids: [record.res_id],
|
||||||
|
active_model: record.model,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.trigger_up('execute_action', {
|
||||||
|
action_data: attrs,
|
||||||
|
env: {
|
||||||
|
context: record.getContext(),
|
||||||
|
currentID: record.res_id,
|
||||||
|
model: record.model,
|
||||||
|
resIDs: record.res_ids,
|
||||||
|
},
|
||||||
|
on_closed: function () {
|
||||||
|
var recordModel = self.model.localData[record.id];
|
||||||
|
var group = self.model.localData[recordModel.parentID];
|
||||||
|
var parent = self.model.localData[group.parentID];
|
||||||
|
|
||||||
|
self.model.reload(record.id).then(function (db_id) {
|
||||||
|
var data = self.model.get(db_id);
|
||||||
|
var kanban_record = event.target;
|
||||||
|
kanban_record.update(data);
|
||||||
|
|
||||||
|
// Check if we still need to display the record. Some fields of the domain are
|
||||||
|
// not guaranteed to be in data. This is for example the case if the action
|
||||||
|
// contains a domain on a field which is not in the Kanban view. Therefore,
|
||||||
|
// we need to handle multiple cases based on 3 variables:
|
||||||
|
// domInData: all domain fields are in the data
|
||||||
|
// activeInDomain: 'active' is already in the domain
|
||||||
|
// activeInData: 'active' is available in the data
|
||||||
|
|
||||||
|
var domain = (parent ? parent.domain : group.domain) || [];
|
||||||
|
var domInData = _.every(domain, function (d) {
|
||||||
|
return d[0] in data.data;
|
||||||
|
});
|
||||||
|
var activeInDomain = _.pluck(domain, 0).indexOf('active') !== -1;
|
||||||
|
var activeInData = 'active' in data.data;
|
||||||
|
|
||||||
|
// Case # | domInData | activeInDomain | activeInData
|
||||||
|
// 1 | true | true | true => no domain change
|
||||||
|
// 2 | true | true | false => not possible
|
||||||
|
// 3 | true | false | true => add active in domain
|
||||||
|
// 4 | true | false | false => no domain change
|
||||||
|
// 5 | false | true | true => no evaluation
|
||||||
|
// 6 | false | true | false => no evaluation
|
||||||
|
// 7 | false | false | true => replace domain
|
||||||
|
// 8 | false | false | false => no evaluation
|
||||||
|
|
||||||
|
// There are 3 cases which cannot be evaluated since we don't have all the
|
||||||
|
// necessary information. The complete solution would be to perform a RPC in
|
||||||
|
// these cases, but this is out of scope. A simpler one is to do a try / catch.
|
||||||
|
|
||||||
|
if (domInData && !activeInDomain && activeInData) {
|
||||||
|
domain = domain.concat([
|
||||||
|
['active', '=', true]
|
||||||
|
]);
|
||||||
|
} else if (!domInData && !activeInDomain && activeInData) {
|
||||||
|
domain = [
|
||||||
|
['active', '=', true]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var visible = new Domain(domain).compute(data.evalContext);
|
||||||
|
} catch (e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!visible) {
|
||||||
|
kanban_record.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {OdooEvent} event
|
||||||
|
*/
|
||||||
|
_onRecordDelete: function (event) {
|
||||||
|
this._deleteRecords([event.data.id]);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @todo should simply use field_changed event...
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {OdooEvent} ev
|
||||||
|
*/
|
||||||
|
_onUpdateRecord: function (ev) {
|
||||||
|
var changes = _.clone(ev.data);
|
||||||
|
ev.data.force_save = true;
|
||||||
|
this._applyChanges(ev.target.db_id, changes, ev);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* The interface allows in some case the user to archive a column. This is
|
||||||
|
* what this handler is for.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {OdooEvent} event
|
||||||
|
*/
|
||||||
|
_onArchiveRecords: function (event) {
|
||||||
|
var self = this;
|
||||||
|
var active_value = !event.data.archive;
|
||||||
|
var column = event.target;
|
||||||
|
var record_ids = _.pluck(column.records, 'db_id');
|
||||||
|
if (record_ids.length) {
|
||||||
|
this.model
|
||||||
|
.toggleActive(record_ids, active_value, column.db_id)
|
||||||
|
.then(function (db_id) {
|
||||||
|
var data = self.model.get(db_id);
|
||||||
|
self._updateEnv();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
renderButtons: function ($node) {
|
||||||
|
if (this.hasButtons) {
|
||||||
|
this.$buttons = $(qweb.render('MapView.buttons', {
|
||||||
|
widget: this
|
||||||
|
}));
|
||||||
|
this.$buttons.on('click', 'button.o-map-button-new', this._onButtonNew.bind(this));
|
||||||
|
this.$buttons.on('click', 'button.o-map-button-center-map', this._onButtonMapCenter.bind(this));
|
||||||
|
this.$buttons.appendTo($node);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_onButtonMapCenter: function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (this.renderer.mapLibrary === 'geometry') {
|
||||||
|
this.renderer.mapGeometryCentered();
|
||||||
|
} else if (this.renderer.mapLibrary === 'drawing') {
|
||||||
|
this.renderer.mapShapesCentered();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_onButtonNew: function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.trigger_up('switch_view', {
|
||||||
|
view_type: 'form',
|
||||||
|
res_id: undefined
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return MapController;
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
odoo.define('web_google_maps.MapModel', function(require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var BasicModel = require('web.BasicModel');
|
||||||
|
|
||||||
|
var MapModel = BasicModel.extend({
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
reload: function (id, options) {
|
||||||
|
if (options && options.groupBy && !options.groupBy.length) {
|
||||||
|
options.groupBy = this.defaultGroupedBy;
|
||||||
|
}
|
||||||
|
return this._super.apply(this, arguments);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
load: function (params) {
|
||||||
|
this.defaultGroupedBy = params.groupBy;
|
||||||
|
params.groupedBy = (params.groupedBy && params.groupedBy.length) ? params.groupedBy : this.defaultGroupedBy;
|
||||||
|
return this._super(params);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Ensures that there is no nested groups in Map (only the first grouping
|
||||||
|
* level is taken into account).
|
||||||
|
*
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
_readGroup: function (list) {
|
||||||
|
var self = this;
|
||||||
|
if (list.groupedBy.length > 1) {
|
||||||
|
list.groupedBy = [list.groupedBy[0]];
|
||||||
|
}
|
||||||
|
return this._super.apply(this, arguments);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return MapModel;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
odoo.define('web_google_maps.MapView', function (require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var BasicView = require('web.BasicView');
|
||||||
|
var core = require('web.core');
|
||||||
|
|
||||||
|
var MapModel = require('web_google_maps.MapModel');
|
||||||
|
var MapRenderer = require('web_google_maps.MapRenderer');
|
||||||
|
var MapController = require('web_google_maps.MapController');
|
||||||
|
|
||||||
|
var _lt = core._lt;
|
||||||
|
|
||||||
|
var MapView = BasicView.extend({
|
||||||
|
accesskey: 'm',
|
||||||
|
display_name: _lt('Map'),
|
||||||
|
icon: 'fa-map-o',
|
||||||
|
jsLibs: [],
|
||||||
|
config: _.extend({}, BasicView.prototype.config, {
|
||||||
|
Model: MapModel,
|
||||||
|
Renderer: MapRenderer,
|
||||||
|
Controller: MapController
|
||||||
|
}),
|
||||||
|
viewType: 'map',
|
||||||
|
init: function (viewInfo, params) {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
|
||||||
|
var arch = viewInfo.arch;
|
||||||
|
var attrs = arch.attrs;
|
||||||
|
|
||||||
|
var activeActions = this.controllerParams.activeActions;
|
||||||
|
var mode = arch.attrs.editable && !params.readonly ? "edit" : "readonly";
|
||||||
|
|
||||||
|
this.loadParams.limit = this.loadParams.limit || 40;
|
||||||
|
this.loadParams.openGroupByDefault = true;
|
||||||
|
this.loadParams.type = 'list';
|
||||||
|
|
||||||
|
this.loadParams.groupBy = arch.attrs.default_group_by ? [arch.attrs.default_group_by] : (params.groupBy || []);
|
||||||
|
|
||||||
|
this.rendererParams.arch = arch;
|
||||||
|
this.rendererParams.mapLibrary = attrs.library;
|
||||||
|
|
||||||
|
if (attrs.library === 'drawing') {
|
||||||
|
this.rendererParams.drawingMode = attrs.drawing_mode;
|
||||||
|
this.rendererParams.drawingPath = attrs.drawing_path;
|
||||||
|
} else if (attrs.library === 'geometry') {
|
||||||
|
var colors = this._setMarkersColor(attrs.colors);
|
||||||
|
this.rendererParams.markerColor = attrs.color;
|
||||||
|
this.rendererParams.markerColors = colors;
|
||||||
|
this.rendererParams.fieldLat = attrs.lat;
|
||||||
|
this.rendererParams.fieldLng = attrs.lng;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.rendererParams.record_options = {
|
||||||
|
editable: activeActions.edit,
|
||||||
|
deletable: activeActions.delete,
|
||||||
|
read_only_mode: params.readOnlyMode || true,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.controllerParams.mode = mode;
|
||||||
|
this.controllerParams.hasButtons = true;
|
||||||
|
},
|
||||||
|
_setMarkersColor: function (colors) {
|
||||||
|
var pair, color, expr;
|
||||||
|
if (!colors) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return _(colors.split(';'))
|
||||||
|
.chain()
|
||||||
|
.compact()
|
||||||
|
.map(function (color_pair) {
|
||||||
|
pair = color_pair.split(':');
|
||||||
|
color = pair[0];
|
||||||
|
expr = pair[1];
|
||||||
|
return [color, py.parse(py.tokenize(expr)), expr];
|
||||||
|
}).value();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return MapView;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
odoo.define('web_google_maps.view_registry', function (require) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var MapView = require('web_google_maps.MapView');
|
||||||
|
var view_registry = require('web.view_registry');
|
||||||
|
|
||||||
|
view_registry.add('map', MapView);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
odoo.define('web_google_maps.FieldsRegistry', function(require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var registry = require('web.field_registry');
|
||||||
|
var GplacesAutocomplete = require('web_google_maps.GplaceAutocompleteFields');
|
||||||
|
|
||||||
|
registry.add('gplaces_address_autocomplete', GplacesAutocomplete.GplacesAddressAutocompleteField);
|
||||||
|
registry.add('gplaces_autocomplete', GplacesAutocomplete.GplacesAutocompleteField);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,496 @@
|
||||||
|
odoo.define('web_google_maps.GplaceAutocompleteFields', function (require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var BasicFields = require('web.basic_fields');
|
||||||
|
var core = require('web.core');
|
||||||
|
var Utils = require('web_google_maps.Utils');
|
||||||
|
var _t = core._t;
|
||||||
|
|
||||||
|
var GplaceAutocomplete = BasicFields.InputField.extend({
|
||||||
|
className: 'o_field_char o_field_google_autocomplete',
|
||||||
|
tagName: 'span',
|
||||||
|
supportedFieldTypes: ['char'],
|
||||||
|
events: _.extend({}, BasicFields.InputField.prototype.events, {
|
||||||
|
'focus': '_geolocate'
|
||||||
|
}),
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
init: function () {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
|
||||||
|
this._type_relations = ['one2many', 'many2one', 'many2many'];
|
||||||
|
this.places_autocomplete = false;
|
||||||
|
this.component_form = Utils.GOOGLE_PLACES_COMPONENT_FORM;
|
||||||
|
this.address_form = Utils.ADDRESS_FORM;
|
||||||
|
this.fillfields_delimiter = {
|
||||||
|
street: " ",
|
||||||
|
street2: ", ",
|
||||||
|
};
|
||||||
|
this.fillfields = {};
|
||||||
|
this.lng = false;
|
||||||
|
this.lat = false;
|
||||||
|
this.setDefault();
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
start: function () {
|
||||||
|
return this._super.apply(this, arguments).then(this.prepareWidgetOptions.bind(this));
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Set widget default value
|
||||||
|
*/
|
||||||
|
setDefault: function () {},
|
||||||
|
/**
|
||||||
|
* Prepare widget options
|
||||||
|
*/
|
||||||
|
prepareWidgetOptions: function () {
|
||||||
|
if (this.mode === 'edit') {
|
||||||
|
// update 'component_form', 'delimiter' if exists
|
||||||
|
if (this.attrs.options) {
|
||||||
|
if (this.attrs.options.hasOwnProperty('component_form')) {
|
||||||
|
this.component_form = _.defaults({}, this.attrs.options.component_form, this.component_form);
|
||||||
|
}
|
||||||
|
if (this.attrs.options.hasOwnProperty('delimiter')) {
|
||||||
|
this.fillfields_delimiter = _.defaults({}, this.attrs.options.delimiter, this.fillfields_delimiter);
|
||||||
|
}
|
||||||
|
if (this.attrs.options.hasOwnProperty('lat')) {
|
||||||
|
this.lat = this.attrs.options.lat;
|
||||||
|
}
|
||||||
|
if (this.attrs.options.hasOwnProperty('lng')) {
|
||||||
|
this.lng = this.attrs.options.lng;
|
||||||
|
}
|
||||||
|
if (this.attrs.options.hasOwnProperty('address_form')) {
|
||||||
|
this.address_form = _.defaults({}, this.attrs.options.address_form, this.address_form);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.target_fields = this.getFillFieldsType();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* To be overriden
|
||||||
|
*/
|
||||||
|
getFillFieldsType: function () {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Geolocate
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_geolocate: function () {
|
||||||
|
var self = this;
|
||||||
|
if (navigator.geolocation) {
|
||||||
|
navigator.geolocation.getCurrentPosition(function (position) {
|
||||||
|
var geolocation = {
|
||||||
|
lat: position.coords.latitude,
|
||||||
|
lng: position.coords.longitude
|
||||||
|
};
|
||||||
|
|
||||||
|
var circle = new google.maps.Circle({
|
||||||
|
center: geolocation,
|
||||||
|
radius: position.coords.accuracy
|
||||||
|
});
|
||||||
|
|
||||||
|
self.places_autocomplete.setBounds(circle.getBounds());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_prepareValue: function (model, field_name, value) {
|
||||||
|
var model = model || false;
|
||||||
|
var field_name = field_name || false;
|
||||||
|
var value = value || false;
|
||||||
|
return Utils.fetchValues(model, field_name, value);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_populateAddress: function (place, fillfields, delimiter) {
|
||||||
|
var place = place || false;
|
||||||
|
var fillfields = fillfields || this.fillfields;
|
||||||
|
var delimiter = delimiter || this.fillfields_delimiter;
|
||||||
|
return Utils.gmaps_populate_address(place, fillfields, delimiter);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_populatePlaces: function (place, fillfields) {
|
||||||
|
var place = place || false;
|
||||||
|
var fillfields = fillfields || this.fillfields;
|
||||||
|
return Utils.gmaps_populate_places(place, fillfields);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_getCountryState: function (model, country, state) {
|
||||||
|
var model = model || false;
|
||||||
|
var country = country || false;
|
||||||
|
var state = state || false;
|
||||||
|
return Utils.fetchCountryState(model, country, state);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_setGeolocation: function (latitude, longitude) {
|
||||||
|
var res = {};
|
||||||
|
if (_.intersection(_.keys(this.record.fields), [this.lat, this.lng]).length == 2) {
|
||||||
|
res[this.lat] = latitude;
|
||||||
|
res[this.lng] = longitude;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_onUpdateWidgetFields: function (changes) {
|
||||||
|
var changes = changes || {};
|
||||||
|
this.trigger_up('field_changed', {
|
||||||
|
dataPointID: this.dataPointID,
|
||||||
|
changes: changes,
|
||||||
|
viewType: this.viewType,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
_renderEdit: function () {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
if (this.isValid()) {
|
||||||
|
this._initGplacesAutocomplete();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
destroy: function () {
|
||||||
|
if (this.places_autocomplete) {
|
||||||
|
this.places_autocomplete.unbindAll();
|
||||||
|
}
|
||||||
|
// Remove all PAC container in DOM if any
|
||||||
|
$('.pac-container').remove();
|
||||||
|
return this._super();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
var GplaceAddressAutocompleteField = GplaceAutocomplete.extend({
|
||||||
|
setDefault: function () {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
this.fillfields = {
|
||||||
|
[this.address_form.street]: ['street_number', 'route'],
|
||||||
|
[this.address_form.street2]: ['administrative_area_level_3', 'administrative_area_level_4', 'administrative_area_level_5'],
|
||||||
|
[this.address_form.city]: ['locality', 'administrative_area_level_2'],
|
||||||
|
[this.address_form.zip]: 'postal_code',
|
||||||
|
[this.address_form.state_id]: 'administrative_area_level_1',
|
||||||
|
[this.address_form.country_id]: 'country'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
prepareWidgetOptions: function () {
|
||||||
|
if (this.mode === 'edit' && this.attrs.options) {
|
||||||
|
if (this.attrs.options.hasOwnProperty('fillfields')) {
|
||||||
|
this.fillfields = _.defaults({}, this.attrs.options.fillfields, this.fillfields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._super();
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Get fields attributes
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
getFillFieldsType: function () {
|
||||||
|
var self = this;
|
||||||
|
var field;
|
||||||
|
var res = this._super();
|
||||||
|
if (this._isValid) {
|
||||||
|
_.each(this.fillfields, function (val, name) {
|
||||||
|
if (_.contains(self._type_relations, self.record.fields[name].type)) {
|
||||||
|
field = {
|
||||||
|
name: name,
|
||||||
|
type: self.record.fields[name].type,
|
||||||
|
relation: self.record.fields[name].relation
|
||||||
|
};
|
||||||
|
res.push(field);
|
||||||
|
} else {
|
||||||
|
field = {
|
||||||
|
name: name,
|
||||||
|
type: self.record.fields[name].type,
|
||||||
|
relation: false
|
||||||
|
};
|
||||||
|
res.push(field);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
_initGplacesAutocomplete: function () {
|
||||||
|
var self = this;
|
||||||
|
if (!this.places_autocomplete) {
|
||||||
|
this.places_autocomplete = new google.maps.places.Autocomplete(this.$input.get(0), {
|
||||||
|
types: ['address']
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// When the user selects an address from the dropdown, populate the address fields in the form.
|
||||||
|
this.place_listener = this.places_autocomplete.addListener('place_changed', function () {
|
||||||
|
var requests = [];
|
||||||
|
var place = this.getPlace();
|
||||||
|
if (place.hasOwnProperty('address_components')) {
|
||||||
|
var google_address = self._populateAddress(place);
|
||||||
|
_.each(self.target_fields, function (field) {
|
||||||
|
requests.push(self._prepareValue(field.relation, field.name, google_address[field.name]));
|
||||||
|
});
|
||||||
|
|
||||||
|
var partner_geometry = self._setGeolocation(place.geometry.location.lat(), place.geometry.location.lng());
|
||||||
|
_.each(partner_geometry, function (val, field) {
|
||||||
|
requests.push(self._prepareValue(false, field, val));
|
||||||
|
});
|
||||||
|
|
||||||
|
$.when.apply($, requests).done(function () {
|
||||||
|
var changes = {};
|
||||||
|
_.each(arguments, function (data, idx) {
|
||||||
|
_.each(data, function (val, key) {
|
||||||
|
if (typeof val === 'object') {
|
||||||
|
changes[key] = val;
|
||||||
|
} else {
|
||||||
|
changes[key] = self._parseValue(val);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (!changes[self.address_form.state_id] &&
|
||||||
|
changes[self.address_form.country_id].hasOwnProperty('id') &&
|
||||||
|
google_address[self.address_form.state_id]) {
|
||||||
|
var state_id = _.find(self.target_fields, function(field) {
|
||||||
|
return field.name === self.address_form.state_id;
|
||||||
|
})
|
||||||
|
if (!state_id) return;
|
||||||
|
self._getCountryState(
|
||||||
|
state_id.relation,
|
||||||
|
changes[self.address_form.country_id].id,
|
||||||
|
google_address[self.address_form.state_id]
|
||||||
|
).then(function (result) {
|
||||||
|
var state = {
|
||||||
|
[self.address_form.state_id]: result.length == 1 ? result[0] : false,
|
||||||
|
}
|
||||||
|
_.extend(changes, state);
|
||||||
|
self._onUpdateWidgetFields(changes);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self._onUpdateWidgetFields(changes);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.$input.val(google_address[self.name]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
isValid: function () {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
var self = this,
|
||||||
|
unknown_fields;
|
||||||
|
|
||||||
|
unknown_fields = _.filter(_.keys(self.fillfields), function (field) {
|
||||||
|
return !self.record.fields.hasOwnProperty(field);
|
||||||
|
});
|
||||||
|
if (unknown_fields.length > 0) {
|
||||||
|
self.do_warn(_t('The following fields are invalid:'), _t('<ul><li>' + unknown_fields.join('</li><li>') + '</li></ul>'));
|
||||||
|
this._isValid = false;
|
||||||
|
}
|
||||||
|
return this._isValid;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
destroy: function () {
|
||||||
|
if (this.places_autocomplete) {
|
||||||
|
google.maps.event.removeListener(this.place_listener);
|
||||||
|
google.maps.event.clearInstanceListeners(this.places_autocomplete);
|
||||||
|
}
|
||||||
|
return this._super();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var GplacesAutocompleteField = GplaceAutocomplete.extend({
|
||||||
|
setDefault: function () {
|
||||||
|
this._super.apply(this);
|
||||||
|
this.fillfields = {
|
||||||
|
general: {
|
||||||
|
name: 'name',
|
||||||
|
website: 'website',
|
||||||
|
phone: ['international_phone_number', 'formatted_phone_number']
|
||||||
|
},
|
||||||
|
address: {
|
||||||
|
[this.address_form.street]: ['street_number', 'route'],
|
||||||
|
[this.address_form.street2]: ['administrative_area_level_3', 'administrative_area_level_4', 'administrative_area_level_5'],
|
||||||
|
[this.address_form.city]: ['locality', 'administrative_area_level_2'],
|
||||||
|
[this.address_form.zip]: 'postal_code',
|
||||||
|
[this.address_form.state_id]: 'administrative_area_level_1',
|
||||||
|
[this.address_form.country_id]: 'country'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
prepareWidgetOptions: function () {
|
||||||
|
if (this.mode === 'edit' && this.attrs.options) {
|
||||||
|
if (this.attrs.options.hasOwnProperty('fillfields')) {
|
||||||
|
if (this.attrs.options.fillfields.hasOwnProperty('address')) {
|
||||||
|
this.fillfields['address'] = _.defaults({}, this.attrs.options.fillfields.address, this.fillfields.address);
|
||||||
|
}
|
||||||
|
if (this.attrs.options.fillfields.hasOwnProperty('general')) {
|
||||||
|
this.fillfields['general'] = _.defaults({}, this.attrs.options.fillfields.general, this.fillfields.general);
|
||||||
|
}
|
||||||
|
if (this.attrs.options.fillfields.hasOwnProperty('geolocation')) {
|
||||||
|
this.fillfields['geolocation'] = this.attrs.options.fillfields.geolocation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._super();
|
||||||
|
},
|
||||||
|
getFillFieldsType: function () {
|
||||||
|
var self = this;
|
||||||
|
var field;
|
||||||
|
var res = this._super();
|
||||||
|
if (this._isValid) {
|
||||||
|
for (var option in this.fillfields) {
|
||||||
|
_.each(this.fillfields[option], function (val, name) {
|
||||||
|
if (_.contains(self._type_relations, self.record.fields[name].type)) {
|
||||||
|
field = {
|
||||||
|
name: name,
|
||||||
|
type: self.record.fields[name].type,
|
||||||
|
relation: self.record.fields[name].relation
|
||||||
|
};
|
||||||
|
res.push(field);
|
||||||
|
} else {
|
||||||
|
field = {
|
||||||
|
name: name,
|
||||||
|
type: self.record.fields[name].type,
|
||||||
|
relation: false
|
||||||
|
};
|
||||||
|
res.push(field);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
_setGeolocation: function (lat, lng) {
|
||||||
|
var res = {};
|
||||||
|
if (this.lat && this.lng) {
|
||||||
|
var _res = this._super(lat, lng);
|
||||||
|
return _res;
|
||||||
|
} else if (this.fillfields.geolocation) {
|
||||||
|
_.each(this.fillfields.geolocation, function (alias, field) {
|
||||||
|
if (alias === 'latitude') {
|
||||||
|
res[field] = lat;
|
||||||
|
}
|
||||||
|
if (alias === 'longitude') {
|
||||||
|
res[field] = lng;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
_initGplacesAutocomplete: function () {
|
||||||
|
var self = this;
|
||||||
|
this.places_autocomplete = new google.maps.places.Autocomplete(this.$input.get(0), {
|
||||||
|
types: ['establishment']
|
||||||
|
});
|
||||||
|
// When the user selects an address from the dropdown, populate the address fields in the form.
|
||||||
|
this.place_listener = this.places_autocomplete.addListener('place_changed', function () {
|
||||||
|
var values = {},
|
||||||
|
requests = [],
|
||||||
|
place;
|
||||||
|
place = this.getPlace();
|
||||||
|
if (place.hasOwnProperty('address_components')) {
|
||||||
|
// Get address
|
||||||
|
var google_address = self._populateAddress(place, self.fillfields.address, self.fillfields_delimiter);
|
||||||
|
_.extend(values, google_address);
|
||||||
|
// Get place (name, website, phone)
|
||||||
|
var google_place = self._populatePlaces(place, self.fillfields.general);
|
||||||
|
_.extend(values, google_place);
|
||||||
|
// Get place geolocation
|
||||||
|
var google_geolocation = self._setGeolocation(place.geometry.location.lat(), place.geometry.location.lng());
|
||||||
|
_.extend(values, google_geolocation);
|
||||||
|
|
||||||
|
_.each(self.target_fields, function (field) {
|
||||||
|
requests.push(self._prepareValue(field.relation, field.name, values[field.name]));
|
||||||
|
});
|
||||||
|
|
||||||
|
$.when.apply($, requests).done(function () {
|
||||||
|
var changes = {}
|
||||||
|
_.each(arguments, function (data, idx) {
|
||||||
|
_.each(data, function (val, key) {
|
||||||
|
if (typeof val === 'object') {
|
||||||
|
changes[key] = val;
|
||||||
|
} else {
|
||||||
|
changes[key] = self._parseValue(val);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (!changes[self.address_form.state_id] &&
|
||||||
|
changes[self.address_form.country_id].hasOwnProperty('id') &&
|
||||||
|
google_address[self.address_form.state_id]) {
|
||||||
|
var state_id = _.find(self.target_fields, function(field) {
|
||||||
|
return field.name === self.address_form.state_id;
|
||||||
|
})
|
||||||
|
if (!state_id) return;
|
||||||
|
self._getCountryState(
|
||||||
|
state_id.relation,
|
||||||
|
changes[self.address_form.country_id].id,
|
||||||
|
google_address[self.address_form.state_id]
|
||||||
|
).then(function (result) {
|
||||||
|
var state = {
|
||||||
|
[self.address_form.state_id]: result.length == 1 ? result[0] : false,
|
||||||
|
}
|
||||||
|
_.extend(changes, state);
|
||||||
|
self._onUpdateWidgetFields(changes);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self._onUpdateWidgetFields(changes);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.$input.val(place.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
isValid: function () {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
var self = this,
|
||||||
|
unknown_fields;
|
||||||
|
for (var option in this.fillfields) {
|
||||||
|
unknown_fields = _.filter(_.keys(this.fillfields[option]), function (field) {
|
||||||
|
return !self.record.fields.hasOwnProperty(field);
|
||||||
|
});
|
||||||
|
if (unknown_fields.length > 0) {
|
||||||
|
self.do_warn(_t('The following fields are invalid:'), _t('<ul><li>' + unknown_fields.join('</li><li>') + '</li></ul>'));
|
||||||
|
this._isValid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this._isValid;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
destroy: function () {
|
||||||
|
if (this.places_autocomplete) {
|
||||||
|
google.maps.event.removeListener(this.place_listener);
|
||||||
|
google.maps.event.clearInstanceListeners(this.$input.get(0));
|
||||||
|
}
|
||||||
|
return this._super();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
GplacesAddressAutocompleteField: GplaceAddressAutocompleteField,
|
||||||
|
GplacesAutocompleteField: GplacesAutocompleteField
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
odoo.define('web_google_maps.Utils', function (require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var rpc = require("web.rpc");
|
||||||
|
|
||||||
|
var GOOGLE_PLACES_COMPONENT_FORM = {
|
||||||
|
street_number: 'long_name',
|
||||||
|
route: 'long_name',
|
||||||
|
intersection: 'short_name',
|
||||||
|
political: 'short_name',
|
||||||
|
country: 'short_name',
|
||||||
|
administrative_area_level_1: 'short_name',
|
||||||
|
administrative_area_level_2: 'short_name',
|
||||||
|
administrative_area_level_3: 'short_name',
|
||||||
|
administrative_area_level_4: 'short_name',
|
||||||
|
administrative_area_level_5: 'short_name',
|
||||||
|
colloquial_area: 'short_name',
|
||||||
|
locality: 'short_name',
|
||||||
|
ward: 'short_name',
|
||||||
|
sublocality_level_1: 'short_name',
|
||||||
|
sublocality_level_2: 'short_name',
|
||||||
|
sublocality_level_3: 'short_name',
|
||||||
|
sublocality_level_5: 'short_name',
|
||||||
|
neighborhood: 'short_name',
|
||||||
|
premise: 'short_name',
|
||||||
|
postal_code: 'short_name',
|
||||||
|
natural_feature: 'short_name',
|
||||||
|
airport: 'short_name',
|
||||||
|
park: 'short_name',
|
||||||
|
point_of_interest: 'long_name'
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Mapping field with an alias
|
||||||
|
* key: alias
|
||||||
|
* value: field
|
||||||
|
*/
|
||||||
|
var ADDRESS_FORM = {
|
||||||
|
street: 'street',
|
||||||
|
street2: 'street2',
|
||||||
|
city: 'city',
|
||||||
|
zip: 'zip',
|
||||||
|
state_id: 'state_id',
|
||||||
|
country_id: 'country_id'
|
||||||
|
};
|
||||||
|
|
||||||
|
function fetchValues(model, field_name, value) {
|
||||||
|
var def = $.Deferred(),
|
||||||
|
res = {};
|
||||||
|
|
||||||
|
if (model && value) {
|
||||||
|
rpc.query({
|
||||||
|
'model': model,
|
||||||
|
'method': 'search_read',
|
||||||
|
'args': [['|', ['name', '=', value], ['code', '=', value]], ['display_name', ]]
|
||||||
|
}).then(function (record) {
|
||||||
|
res[field_name] = record.length == 1 ? record[0] : false;
|
||||||
|
def.resolve(res);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res[field_name] = value;
|
||||||
|
def.resolve(res);
|
||||||
|
}
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchCountryState(model, country, state) {
|
||||||
|
var def = $.Deferred();
|
||||||
|
|
||||||
|
if (country && state) {
|
||||||
|
rpc.query({
|
||||||
|
model: model,
|
||||||
|
method: 'search_read',
|
||||||
|
args: [[['country_id', '=', country], ['code', '=', state]], ['display_name']]
|
||||||
|
}).then(function(record) {
|
||||||
|
def.resolve(record);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
def.resolve([]);
|
||||||
|
}
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gmaps_get_geolocation(place, options) {
|
||||||
|
if (!place) return {};
|
||||||
|
|
||||||
|
var vals = {};
|
||||||
|
_.each(options, function (alias, field) {
|
||||||
|
if (alias === 'latitude') {
|
||||||
|
vals[field] = place.geometry.location.lat();
|
||||||
|
} else if (alias === 'longitude') {
|
||||||
|
vals[field] = place.geometry.location.lng();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return vals;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gmaps_populate_places(place, place_options) {
|
||||||
|
if (!place) return {};
|
||||||
|
|
||||||
|
var values = {},
|
||||||
|
vals;
|
||||||
|
_.each(place_options, function (option, field) {
|
||||||
|
if (option instanceof Array && !_.has(values, field)) {
|
||||||
|
vals = _.filter(_.map(option, function (opt) {
|
||||||
|
return place[opt] || false;
|
||||||
|
}));
|
||||||
|
values[field] = _.first(vals) || "";
|
||||||
|
} else {
|
||||||
|
values[field] = place[option] || "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gmaps_populate_address(place, address_options, delimiter) {
|
||||||
|
if (!place) return {};
|
||||||
|
|
||||||
|
var address_options = address_options || {},
|
||||||
|
fields_delimiter = delimiter || {
|
||||||
|
street: " ",
|
||||||
|
street2: ", "
|
||||||
|
},
|
||||||
|
fields_to_fill = {},
|
||||||
|
options, temp, dlmter, result = {};
|
||||||
|
|
||||||
|
// initialize object key and value
|
||||||
|
_.each(address_options, function (value, key) {
|
||||||
|
fields_to_fill[key] = [];
|
||||||
|
});
|
||||||
|
|
||||||
|
_.each(address_options, function (options, field) {
|
||||||
|
// turn all fields options into an Array
|
||||||
|
options = _.flatten([options]);
|
||||||
|
temp = {};
|
||||||
|
_.each(place.address_components, function (component) {
|
||||||
|
_.each(_.intersection(options, component.types), function (match) {
|
||||||
|
temp[match] = component[GOOGLE_PLACES_COMPONENT_FORM[match]] || false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
fields_to_fill[field] = _.map(options, function (item) {
|
||||||
|
return temp[item];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
_.each(fields_to_fill, function (value, key) {
|
||||||
|
dlmter = fields_delimiter[key] || ' ';
|
||||||
|
if (key == 'city') {
|
||||||
|
result[key] = _.first(_.filter(value)) || '';
|
||||||
|
} else {
|
||||||
|
result[key] = _.filter(value).join(dlmter);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
'GOOGLE_PLACES_COMPONENT_FORM': GOOGLE_PLACES_COMPONENT_FORM,
|
||||||
|
'ADDRESS_FORM': ADDRESS_FORM,
|
||||||
|
'gmaps_populate_address': gmaps_populate_address,
|
||||||
|
'gmaps_populate_places': gmaps_populate_places,
|
||||||
|
'gmaps_get_geolocation': gmaps_get_geolocation,
|
||||||
|
'fetchValues': fetchValues,
|
||||||
|
'fetchCountryState': fetchCountryState
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
/* https://github.com/twbs/bootstrap/issues/4160 */
|
||||||
|
/* put google places autocomplete dropdown results above the bootstrap modal 1050 zindex. */
|
||||||
|
.pac-container {
|
||||||
|
z-index: 1051 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_field_x2many_map {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map_container {
|
||||||
|
min-height: 400px;
|
||||||
|
min-width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
.o-flex-display();
|
||||||
|
|
||||||
|
.o_map_view {
|
||||||
|
.o-flex(1, 1, auto);
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map_left_sidenav {
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
max-width: 400px;
|
||||||
|
width: 400px;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
overflow-x: hidden;
|
||||||
|
transition: 0.5s;
|
||||||
|
transform: translate3d(0, 0, 0);
|
||||||
|
-webkit-transform: translate3d(0, 0, 0);
|
||||||
|
|
||||||
|
&.closed {
|
||||||
|
transform: translate3d(-100%, 0, 0);
|
||||||
|
-webkit-transform: translate3d(-100%, 0, 0);
|
||||||
|
|
||||||
|
.sidenav-body .panel {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map_right_sidebar {
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
|
||||||
|
&.closed {
|
||||||
|
width: 0;
|
||||||
|
transition: 0.5s;
|
||||||
|
transform: translateX(-100%);
|
||||||
|
-webkit-transform: translateX(-100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.open {
|
||||||
|
width: 250px;
|
||||||
|
transition: 0.5s;
|
||||||
|
transform: translateX(0);
|
||||||
|
-webkit-transform: translateX(0);
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding-left: 3px;
|
||||||
|
list-style: none;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
li {
|
||||||
|
padding-bottom: 8px;
|
||||||
|
|
||||||
|
span {
|
||||||
|
padding: 3px 6px;
|
||||||
|
|
||||||
|
&.total {
|
||||||
|
font-size: 10px;
|
||||||
|
background: #ddd;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_map_button {
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
width: auto;
|
||||||
|
padding: 0px 6px;
|
||||||
|
margin: 0px 15px 5px 0px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 2px;
|
||||||
|
line-height: 25px;
|
||||||
|
font-family: 'Roboto,Arial,sans-serif';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<template>
|
||||||
|
<div t-name="MapView.MapView" class="o_map_container">
|
||||||
|
<div class="o_map_view"></div>
|
||||||
|
<div class="o_map_right_sidebar closed"></div>
|
||||||
|
</div>
|
||||||
|
<t t-name="MapView.MapViewGroupInfo">
|
||||||
|
<ul t-if="widget.groups">
|
||||||
|
<t t-foreach="widget.groups" t-as="group">
|
||||||
|
<li>
|
||||||
|
<img t-att-src="group.marker"/>
|
||||||
|
<span class="title"><t t-esc="group.title"/></span>
|
||||||
|
<span class="total"><t t-esc="group.count"/></span>
|
||||||
|
</li>
|
||||||
|
</t>
|
||||||
|
</ul>
|
||||||
|
</t>
|
||||||
|
<t t-name="MapView.buttons">
|
||||||
|
<div class="o_list_buttons">
|
||||||
|
<t t-if="(widget.is_action_enabled !== undefined ? widget.is_action_enabled('create') : false) || !widget.isReadonly">
|
||||||
|
<button type="button" class="btn btn-primary btn-sm o-map-button-new" accesskey="c">
|
||||||
|
<t t-esc="create_text || _t('Create')"/>
|
||||||
|
</button>
|
||||||
|
</t>
|
||||||
|
<button type="button" class="btn btn-default btn-sm o-map-button-center-map">
|
||||||
|
<t t-esc="_t('Center Map')"/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<template id="web_google_maps.assets_gmaps">
|
||||||
|
<t t-set="google_maps_api_key" t-value="request.env['ir.config_parameter'].sudo().get_param('google.api_key_geocode')"/>
|
||||||
|
<t t-set="google_maps_lang_localization" t-value="request.env['ir.config_parameter'].sudo().get_param('google.lang_localization')"/>
|
||||||
|
<t t-set="google_maps_region_localization" t-value="request.env['ir.config_parameter'].sudo().get_param('google.region_localization')"/>
|
||||||
|
<t t-set="google_maps_libraries" t-value="request.env['ir.config_parameter'].sudo().get_param('google.maps_libraries')"/>
|
||||||
|
<t t-if="google_maps_api_key">
|
||||||
|
<script t-att-async="'async'" t-att-defer="'defer'" t-attf-src="https://maps.googleapis.com/maps/api/js?v=quarterly&key=#{google_maps_api_key}&libraries=#{google_maps_libraries}#{google_maps_lang_localization}#{google_maps_region_localization}"></script>
|
||||||
|
</t>
|
||||||
|
<t t-if="not google_maps_api_key">
|
||||||
|
<script t-att-async="'async'" t-att-defer="'defer'" t-attf-src="https://maps.googleapis.com/maps/api/js?v=quarterly&libraries=#{google_maps_libraries}#{google_maps_lang_localization}#{google_maps_region_localization}"></script>
|
||||||
|
</t>
|
||||||
|
<script src="/web_google_maps/static/lib/markercluster/markerclusterer.js"></script>
|
||||||
|
</template>
|
||||||
|
<template id="webclient_bootstrap" name="webclient_bootstrap gmaps" inherit_id="web.webclient_bootstrap">
|
||||||
|
<xpath expr="//t[@t-call-assets='web.assets_common']" position="before">
|
||||||
|
<t t-call="web_google_maps.assets_gmaps"/>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
<template id="assets_backend" name="web_google_maps assets backend" inherit_id="web.assets_backend">
|
||||||
|
<xpath expr="." position="inside">
|
||||||
|
<link rel="stylesheet" type="text/less" href="/web_google_maps/static/src/less/web_maps.less"/>
|
||||||
|
<script type="text/javascript" src="/web_google_maps/static/src/js/view/map/map_model.js"></script>
|
||||||
|
<script type="text/javascript" src="/web_google_maps/static/src/js/view/map/map_controller.js"></script>
|
||||||
|
<script type="text/javascript" src="/web_google_maps/static/src/js/view/map/map_renderer.js"></script>
|
||||||
|
<script type="text/javascript" src="/web_google_maps/static/src/js/view/map/map_view.js"></script>
|
||||||
|
<script type="text/javascript" src="/web_google_maps/static/src/js/view/view_registry.js"></script>
|
||||||
|
<script type="text/javascript" src="/web_google_maps/static/src/js/fields/relational_fields.js"></script>
|
||||||
|
<script type="text/javascript" src="/web_google_maps/static/src/js/widgets/utils.js"></script>
|
||||||
|
<script type="text/javascript" src="/web_google_maps/static/src/js/widgets/gplaces_autocomplete.js"></script>
|
||||||
|
<script type="text/javascript" src="/web_google_maps/static/src/js/widgets/fields_registry.js"></script>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<odoo>
|
||||||
|
<record id="view_web_google_maps_config_settings" model="ir.ui.view">
|
||||||
|
<field name="name">view.web.google.config.settings</field>
|
||||||
|
<field name="model">res.config.settings</field>
|
||||||
|
<field name="inherit_id" ref="base_setup.res_config_settings_view_form" />
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//div[@name='integration']" position="after">
|
||||||
|
<div name="web_google_maps">
|
||||||
|
<h2>Google Maps View</h2>
|
||||||
|
<div class="row mt16 o_settings_container">
|
||||||
|
<div class="col-xs-12 col-md-6 o_setting_box">
|
||||||
|
<div class="o_setting_right_pane">
|
||||||
|
<label string="Configure your Google Maps View"/>
|
||||||
|
<div class="text-muted">
|
||||||
|
<p>Set API keys and map localization</p>
|
||||||
|
<span>Visit the <a href="https://developers.google.com/maps/documentation/javascript/localization" target="_blank">page</a> about Localizing the Map</span>
|
||||||
|
</div>
|
||||||
|
<div class="content-group">
|
||||||
|
<div class="mt16">
|
||||||
|
<label for="google_maps_view_api_key" string="Api key"/>
|
||||||
|
<field name="google_maps_view_api_key"/>
|
||||||
|
</div>
|
||||||
|
<div class="mt16">
|
||||||
|
<label for="google_maps_theme" string="Theme"/>
|
||||||
|
<field name="google_maps_theme"/>
|
||||||
|
</div>
|
||||||
|
<div class="mt16">
|
||||||
|
<label for="google_maps_lang_localization" string="Language"/>
|
||||||
|
<field name="google_maps_lang_localization"/>
|
||||||
|
</div>
|
||||||
|
<div class="mt16" attrs="{'invisible': [('google_maps_lang_localization', 'in', [False, ''])]}">
|
||||||
|
<div class="text-muted">
|
||||||
|
If you set the language of the map, it's important to consider setting the region too. This helps ensure that your application complies with local laws.
|
||||||
|
</div>
|
||||||
|
<label for="google_maps_region_localization" string="Region"/>
|
||||||
|
<field name="google_maps_region_localization"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h2> Google Maps Libraries </h2>
|
||||||
|
<div class="row mt16 o_settings_container">
|
||||||
|
<div class="col-xs-12 col-md-6 o_setting_box">
|
||||||
|
<div class="o_setting_left_pane">
|
||||||
|
<field name="google_maps_geometry"/>
|
||||||
|
</div>
|
||||||
|
<div class="o_setting_right_pane">
|
||||||
|
<label for="google_maps_geometry"/>
|
||||||
|
<div class="text-muted">
|
||||||
|
Geometry includes utility functions for calculating scalar geometric values (such as distance and area) on the surface of the earth.
|
||||||
|
Consult the <a href="https://developers.google.com/maps/documentation/javascript/geometry">Geometry library documentation</a> for more information.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-12 col-md-6 o_setting_box">
|
||||||
|
<div class="o_setting_left_pane">
|
||||||
|
<field name="google_maps_places"/>
|
||||||
|
</div>
|
||||||
|
<div class="o_setting_right_pane">
|
||||||
|
<label for="google_maps_places"/>
|
||||||
|
<div class="text-muted">
|
||||||
|
Places enables your application to search for places such as establishments, geographic locations, or prominent points of interest, within a defined area.
|
||||||
|
Consult the <a href="https://developers.google.com/maps/documentation/javascript/places">Places library documentation</a> for more information.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<record id="view_res_partner_map" model="ir.ui.view">
|
||||||
|
<field name="name">view.res.partner.map</field>
|
||||||
|
<field name="model">res.partner</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<map class="o_res_partner_map" library="geometry" string="Map" lat="partner_latitude" lng="partner_longitude" colors="blue:company_type=='person';green:company_type=='company';">
|
||||||
|
<field name="id"/>
|
||||||
|
<field name="partner_latitude"/>
|
||||||
|
<field name="partner_longitude"/>
|
||||||
|
<field name="company_type"/>
|
||||||
|
<field name="color"/>
|
||||||
|
<field name="display_name"/>
|
||||||
|
<field name="title"/>
|
||||||
|
<field name="email"/>
|
||||||
|
<field name="parent_id"/>
|
||||||
|
<field name="is_company"/>
|
||||||
|
<field name="function"/>
|
||||||
|
<field name="phone"/>
|
||||||
|
<field name="street"/>
|
||||||
|
<field name="street2"/>
|
||||||
|
<field name="zip"/>
|
||||||
|
<field name="city"/>
|
||||||
|
<field name="country_id"/>
|
||||||
|
<field name="mobile"/>
|
||||||
|
<field name="state_id"/>
|
||||||
|
<field name="category_id"/>
|
||||||
|
<field name="image_small"/>
|
||||||
|
<field name="type"/>
|
||||||
|
<templates>
|
||||||
|
<t t-name="kanban-box">
|
||||||
|
<div class="oe_kanban_global_click o_res_partner_kanban">
|
||||||
|
<div class="o_kanban_image">
|
||||||
|
<t t-if="record.image_small.raw_value">
|
||||||
|
<img t-att-src="kanban_image('res.partner', 'image_small', record.id.raw_value)"/>
|
||||||
|
</t>
|
||||||
|
<t t-if="!record.image_small.raw_value">
|
||||||
|
<t t-if="record.type.raw_value === 'delivery'">
|
||||||
|
<img t-att-src='_s + "/base/static/src/img/truck.png"' class="o_kanban_image oe_kanban_avatar_smallbox"/>
|
||||||
|
</t>
|
||||||
|
<t t-if="record.type.raw_value === 'invoice'">
|
||||||
|
<img t-att-src='_s + "/base/static/src/img/money.png"' class="o_kanban_image oe_kanban_avatar_smallbox"/>
|
||||||
|
</t>
|
||||||
|
<t t-if="record.type.raw_value != 'invoice' && record.type.raw_value != 'delivery'">
|
||||||
|
<t t-if="record.is_company.raw_value === true">
|
||||||
|
<img t-att-src='_s + "/base/static/src/img/company_image.png"'/>
|
||||||
|
</t>
|
||||||
|
<t t-if="record.is_company.raw_value === false">
|
||||||
|
<img t-att-src='_s + "/base/static/src/img/avatar.png"'/>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
<div class="oe_kanban_details">
|
||||||
|
<strong class="o_kanban_record_title oe_partner_heading">
|
||||||
|
<field name="display_name"/>
|
||||||
|
</strong>
|
||||||
|
<div class="o_kanban_tags_section oe_kanban_partner_categories">
|
||||||
|
<span class="oe_kanban_list_many2many">
|
||||||
|
<field name="category_id" widget="many2many_tags" options="{'color_field': 'color'}"/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
<li t-if="record.parent_id.raw_value and !record.function.raw_value">
|
||||||
|
<field name="parent_id"/>
|
||||||
|
</li>
|
||||||
|
<li t-if="!record.parent_id.raw_value and record.function.raw_value">
|
||||||
|
<field name="function"/>
|
||||||
|
</li>
|
||||||
|
<li t-if="record.parent_id.raw_value and record.function.raw_value">
|
||||||
|
<field name="function"/> at <field name="parent_id"/>
|
||||||
|
</li>
|
||||||
|
<li t-if="record.city.raw_value and !record.country_id.raw_value">
|
||||||
|
<field name="city"/>
|
||||||
|
</li>
|
||||||
|
<li t-if="!record.city.raw_value and record.country_id.raw_value">
|
||||||
|
<field name="country_id"/>
|
||||||
|
</li>
|
||||||
|
<li t-if="record.city.raw_value and record.country_id.raw_value">
|
||||||
|
<field name="city"/>
|
||||||
|
, <field name="country_id"/>
|
||||||
|
</li>
|
||||||
|
<li t-if="record.email.raw_value" class="o_text_overflow">
|
||||||
|
<field name="email"/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="oe_kanban_partner_links"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</templates>
|
||||||
|
</map>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
<record id="base.action_partner_form" model="ir.actions.act_window">
|
||||||
|
<field name="view_mode">kanban,tree,form,map</field>
|
||||||
|
</record>
|
||||||
|
<record id="action_partner_form_view3" model="ir.actions.act_window.view">
|
||||||
|
<field eval="3" name="sequence"/>
|
||||||
|
<field name="view_mode">map</field>
|
||||||
|
<field name="view_id" ref="view_res_partner_map"/>
|
||||||
|
<field name="act_window_id" ref="base.action_partner_form"/>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||