Начальное наполнение
3
__init__.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
from . import controllers
|
17
__manifest__.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
{
|
||||||
|
'name': 'Google Maps',
|
||||||
|
'category': 'Website/Website',
|
||||||
|
'summary': 'Show your company address on Google Maps',
|
||||||
|
'version': '1.0',
|
||||||
|
'description': """
|
||||||
|
Show your company address/partner address on Google Maps. Configure an API key in the Website settings.
|
||||||
|
""",
|
||||||
|
'depends': ['base_geolocalize', 'website_partner'],
|
||||||
|
'data': [
|
||||||
|
'views/google_map_templates.xml',
|
||||||
|
],
|
||||||
|
'installable': True,
|
||||||
|
'license': 'LGPL-3',
|
||||||
|
}
|
4
controllers/__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
from . import main
|
58
controllers/main.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
from odoo import http
|
||||||
|
from odoo.http import request
|
||||||
|
from odoo.tools.json import scriptsafe
|
||||||
|
|
||||||
|
|
||||||
|
class GoogleMap(http.Controller):
|
||||||
|
'''
|
||||||
|
This class generates on-the-fly partner maps that can be reused in every
|
||||||
|
website page. To do so, just use an ``<iframe ...>`` whose ``src``
|
||||||
|
attribute points to ``/google_map`` (this controller generates a complete
|
||||||
|
HTML5 page).
|
||||||
|
|
||||||
|
URL query parameters:
|
||||||
|
- ``partner_ids``: a comma-separated list of ids (partners to be shown)
|
||||||
|
- ``partner_url``: the base-url to display the partner
|
||||||
|
(eg: if ``partner_url`` is ``/partners/``, when the user will click on
|
||||||
|
a partner on the map, it will be redirected to <myodoo>.com/partners/<id>)
|
||||||
|
|
||||||
|
In order to resize the map, simply resize the ``iframe`` with CSS
|
||||||
|
directives ``width`` and ``height``.
|
||||||
|
'''
|
||||||
|
|
||||||
|
@http.route(['/google_map'], type='http', auth="public", website=True, sitemap=False)
|
||||||
|
def google_map(self, *arg, **post):
|
||||||
|
clean_ids = []
|
||||||
|
for partner_id in post.get('partner_ids', "").split(","):
|
||||||
|
try:
|
||||||
|
clean_ids.append(int(partner_id))
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
partners = request.env['res.partner'].sudo().search([("id", "in", clean_ids),
|
||||||
|
('website_published', '=', True), ('is_company', '=', True)])
|
||||||
|
partner_data = {
|
||||||
|
"counter": len(partners),
|
||||||
|
"partners": []
|
||||||
|
}
|
||||||
|
for partner in partners.with_context(show_address=True):
|
||||||
|
partner_data["partners"].append({
|
||||||
|
'id': partner.id,
|
||||||
|
'name': partner.name,
|
||||||
|
'address': '\n'.join(partner.display_name.split('\n')[1:]),
|
||||||
|
'latitude': str(partner.partner_latitude) if partner.partner_latitude else False,
|
||||||
|
'longitude': str(partner.partner_longitude) if partner.partner_longitude else False,
|
||||||
|
})
|
||||||
|
if 'customers' in post.get('partner_url', ''):
|
||||||
|
partner_url = '/customers/'
|
||||||
|
else:
|
||||||
|
partner_url = '/partners/'
|
||||||
|
|
||||||
|
google_maps_api_key = request.website.google_maps_api_key
|
||||||
|
values = {
|
||||||
|
'partner_url': partner_url,
|
||||||
|
'partner_data': scriptsafe.dumps(partner_data),
|
||||||
|
'google_maps_api_key': google_maps_api_key,
|
||||||
|
}
|
||||||
|
return request.render("website_google_map.google_map", values)
|
15
i18n/website_google_map.pot
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 17.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2023-10-26 21:56+0000\n"
|
||||||
|
"PO-Revision-Date: 2023-10-26 21:56+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"
|
BIN
static/description/icon.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
1
static/description/icon.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg width="50" height="50" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg"><path d="M30.439.813A18.546 18.546 0 0 0 25.001 0C19.47 0 14.52 2.423 11.22 6.23l8.504 6.934L30.439.813Z" fill="#1A73E8"/><path d="M11.217 6.23C8.587 9.262 7 13.175 7 17.443c0 3.282.675 5.94 1.783 8.321l10.938-12.6-8.504-6.934Z" fill="#EA4335"/><path d="M25.003 10.774c3.804 0 6.885 2.987 6.885 6.673 0 1.64-.612 3.145-1.626 4.306 0 0 5.437-6.268 10.715-12.347-2.18-4.064-5.96-7.19-10.532-8.593l-10.723 12.35a6.954 6.954 0 0 1 5.281-2.389Z" fill="#4285F4"/><path d="M25.003 24.115c-3.803 0-6.885-2.987-6.885-6.673a6.55 6.55 0 0 1 1.603-4.283L8.783 25.763c1.869 4.019 4.978 7.244 8.18 11.307l13.294-15.318a6.957 6.957 0 0 1-5.254 2.363Z" fill="#FBBC04"/><path d="M29.994 41.252C35.998 32.152 43 28.021 43 17.443c0-2.9-.733-5.633-2.025-8.037L16.965 37.07a62.11 62.11 0 0 1 3.047 4.185C23.663 46.722 22.65 50 25.005 50c2.349 0 1.338-3.281 4.99-8.748Z" fill="#34A853"/></svg>
|
After Width: | Height: | Size: 955 B |
28
static/src/css/website_google_map.css
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#odoo-google-map {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.marker {
|
||||||
|
font-size: 13px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.marker a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.marker pre {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
font-family: sans-serif !important;
|
||||||
|
}
|
BIN
static/src/img/partners.png
Normal file
After Width: | Height: | Size: 719 B |
89
static/src/js/website_google_map.js
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/* global MarkerClusterer, google */
|
||||||
|
function initialize_map() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// MAP CONFIG AND LOADING
|
||||||
|
var map = new google.maps.Map(document.getElementById('odoo-google-map'), {
|
||||||
|
zoom: 1,
|
||||||
|
center: {lat: 0.0, lng: 0.0},
|
||||||
|
mapTypeId: google.maps.MapTypeId.ROADMAP
|
||||||
|
});
|
||||||
|
|
||||||
|
// ENABLE ADDRESS GEOCODING
|
||||||
|
var Geocoder = new google.maps.Geocoder();
|
||||||
|
|
||||||
|
// INFO BUBBLES
|
||||||
|
var infoWindow = new google.maps.InfoWindow();
|
||||||
|
var partners = new google.maps.MarkerImage('/website_google_map/static/src/img/partners.png', new google.maps.Size(25, 25));
|
||||||
|
var partner_url = document.body.getAttribute('data-partner-url') || '';
|
||||||
|
var markers = [];
|
||||||
|
var options = {
|
||||||
|
imagePath: '/website_google_map/static/src/lib/images/m'
|
||||||
|
};
|
||||||
|
|
||||||
|
google.maps.event.addListener(map, 'click', function() {
|
||||||
|
infoWindow.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Display the bubble once clicked
|
||||||
|
var onMarkerClick = function() {
|
||||||
|
var marker = this;
|
||||||
|
var p = marker.partner;
|
||||||
|
infoWindow.setContent(
|
||||||
|
'<div class="marker">'+
|
||||||
|
(partner_url.length ? '<a target="_top" href="'+partner_url+p.id+'"><b>'+p.name +'</b></a>' : '<b>'+p.name+'</b>' )+
|
||||||
|
(p.type ? ' <b>' + p.type + '</b>' : '')+
|
||||||
|
' <pre>' + p.address + '</pre>'+
|
||||||
|
'</div>'
|
||||||
|
);
|
||||||
|
infoWindow.open(map, marker);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a bubble for a partner
|
||||||
|
var set_marker = function(partner) {
|
||||||
|
// If no lat & long, geocode address
|
||||||
|
// TODO: a server cronjob that will store these coordinates in database instead of resolving them on-the-fly
|
||||||
|
if (!partner.latitude && !partner.longitude) {
|
||||||
|
Geocoder.geocode({'address': partner.address}, function(results, status) {
|
||||||
|
if (status === google.maps.GeocoderStatus.OK) {
|
||||||
|
var location = results[0].geometry.location;
|
||||||
|
partner.latitude = location.ob;
|
||||||
|
partner.longitude = location.pb;
|
||||||
|
var marker = new google.maps.Marker({
|
||||||
|
partner: partner,
|
||||||
|
map: map,
|
||||||
|
icon: partners,
|
||||||
|
position: location
|
||||||
|
});
|
||||||
|
google.maps.event.addListener(marker, 'click', onMarkerClick);
|
||||||
|
markers.push(marker);
|
||||||
|
} else {
|
||||||
|
console.debug('Geocode was not successful for the following reason: ' + status);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
var latLng = new google.maps.LatLng(partner.latitude, partner.longitude);
|
||||||
|
var marker = new google.maps.Marker({
|
||||||
|
partner: partner,
|
||||||
|
icon: partners,
|
||||||
|
map: map,
|
||||||
|
position: latLng
|
||||||
|
});
|
||||||
|
google.maps.event.addListener(marker, 'click', onMarkerClick);
|
||||||
|
markers.push(marker);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* eslint-disable no-undef */
|
||||||
|
// Create the markers and cluster them on the map
|
||||||
|
if (odoo_partner_data){ /* odoo_partner_data special variable should have been defined in google_map.xml */
|
||||||
|
for (var i = 0; i < odoo_partner_data.counter; i++) {
|
||||||
|
set_marker(odoo_partner_data.partners[i]);
|
||||||
|
}
|
||||||
|
new MarkerClusterer(map, markers, options);
|
||||||
|
}
|
||||||
|
/* eslint-enable no-undef */
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize map once the DOM has been loaded
|
||||||
|
google.maps.event.addDomListener(window, 'load', initialize_map);
|
BIN
static/src/lib/images/conv30.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
static/src/lib/images/conv40.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
static/src/lib/images/conv50.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
static/src/lib/images/heart30.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
static/src/lib/images/heart40.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
static/src/lib/images/heart50.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
static/src/lib/images/m1.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
static/src/lib/images/m2.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
static/src/lib/images/m3.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
static/src/lib/images/m4.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
static/src/lib/images/m5.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
static/src/lib/images/people35.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
static/src/lib/images/people45.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
static/src/lib/images/people55.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
static/src/lib/images/pin.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
1315
static/src/lib/markerclusterer.js
Normal file
28
views/google_map_templates.xml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<template id="google_map">
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
|
||||||
|
<title>World Map</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/website_google_map/static/src/css/website_google_map.css"/>
|
||||||
|
</head>
|
||||||
|
<body t-att-data-partner-url="partner_url or None">
|
||||||
|
<script>
|
||||||
|
var odoo_partner_data = <t t-out="partner_data"/>;
|
||||||
|
</script>
|
||||||
|
<div id="odoo-google-map"></div>
|
||||||
|
<t t-if="google_maps_api_key">
|
||||||
|
<script t-attf-src="//maps.google.com/maps/api/js?key=#{google_maps_api_key}"></script>
|
||||||
|
</t>
|
||||||
|
<t t-else="1">
|
||||||
|
<script src="//maps.google.com/maps/api/js"></script>
|
||||||
|
</t>
|
||||||
|
<script type="text/javascript" src="/website_google_map/static/src/lib/markerclusterer.js"></script>
|
||||||
|
<script type="text/javascript" src="/website_google_map/static/src/js/website_google_map.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
</template>
|
||||||
|
</odoo>
|