# Do not use semantic controller due to SUPERUSER_ID
@http.route(['/partners/<partner_id>'], type='http', auth="public", website=True)
def partners_detail(self, partner_id, partner_name='', **post):
- mo = re.search('-([-0-9]+)$', str(partner_id))
+ mo = re.search('([-0-9]+)$', str(partner_id))
current_grade, current_country = None, None
grade_id = post.get('grade_id')
country_id = post.get('country_id')
<template id="ref_country" inherit_id="website_crm_partner_assign.index" optional="enabled" name="Left World Map">
<xpath expr="//ul[@id='reseller_countries']" position="after">
- <h3>World Map</h3>
+ <!-- modal for large map -->
+ <div class="modal fade partner_map_modal" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+ <h4 class="modal-title">World Map</h4>
+ </div>
+ <iframe t-attf-src="/google_map/?width=898&height=485&partner_ids=#{ google_map_partner_ids }&partner_url=/partners/"
+ style="width:898px; height:485px; border:0; padding:0; margin:0;"></iframe>
+ </div>
+ </div>
+ </div>
+ <!-- modal end -->
+ <h3>World Map<button class="btn btn-link" data-toggle="modal" data-target=".partner_map_modal"><span class="fa fa-external-link" /></button></h3>
<ul class="nav">
- <iframe t-attf-src="/google_map/?width=260&height=240&partner_ids=#{ google_map_partner_ids }&partner_url=/partners"
- style="width:260px; height:260px; border:0; padding:0; margin:0;"></iframe>
+ <iframe t-attf-src="/google_map/?width=260&height=240&partner_ids=#{ google_map_partner_ids }&partner_url=/partners/"
+ style="width:260px; height:240px; border:0; padding:0; margin:0;"></iframe>
</ul>
</xpath>
</template>
# Do not use semantic controller due to SUPERUSER_ID
@http.route(['/customers/<partner_id>'], type='http', auth="public", website=True)
def partners_detail(self, partner_id, **post):
- mo = re.search('-([-0-9]+)$', str(partner_id))
+ mo = re.search('([-0-9]+)$', str(partner_id))
if mo:
partner_id = int(mo.group(1))
partner = request.registry['res.partner'].browse(request.cr, SUPERUSER_ID, partner_id, context=request.context)
</template>
<!-- Option: left column: World Map -->
-<template id="opt_country" inherit_id="website_customer.index" optional="disabled" name="Show Map">
+<template id="opt_country" inherit_id="website_customer.index" optional="enabled" name="Show Map">
<xpath expr="//div[@id='ref_left_column']" position="inside">
-
- <iframe t-attf-src="/google_map/?partner_ids=#{ google_map_partner_ids }&partner_url=/customers/&output=embed"
- style="width:100%; border:0; padding:0; margin:0;"></iframe>
+ <!-- modal for large map -->
+ <div class="modal fade customer_map_modal" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+ <h4 class="modal-title">World Map</h4>
+ </div>
+ <iframe t-attf-src="/google_map/?width=898&height=485&partner_ids=#{ google_map_partner_ids }&partner_url=/customers/"
+ style="width:898px; height:485px; border:0; padding:0; margin:0;"></iframe>
+ </div>
+ </div>
+ </div>
+ <!-- modal end -->
+ <h3>World Map<button class="btn btn-link" data-toggle="modal" data-target=".customer_map_modal"><span class="fa fa-external-link" /></button></h3>
+ <ul class="nav">
+ <iframe t-attf-src="/google_map/?width=260&height=240&partner_ids=#{ google_map_partner_ids }&partner_url=/customers/"
+ style="width:260px; height:240px; border:0; padding:0; margin:0;"></iframe>
+ </ul>
</xpath>
</template>
import controllers
-import models
\ No newline at end of file
import main
-# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:
# -*- coding: utf-8 -*-
-import openerp
+import json
+from openerp import SUPERUSER_ID
from openerp.addons.web import http
from openerp.addons.web.http import request
-from datetime import datetime
+
class google_map(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)
def google_map(self, *arg, **post):
- values = {
- 'partner_ids': post.get('partner_ids', ""),
- 'width': post.get('width', 900),
- 'height': post.get('height', 460),
- 'partner_url': post.get('partner_url'),
- }
- return request.website.render("website_google_map.google_map", values)
-
- @http.route(['/google_map/partners.json'], type='http', auth="public", website=True)
- def google_map_data(self, *arg, **post):
+ cr, uid, context = request.cr, request.uid, request.context
partner_obj = request.registry['res.partner']
- domain = [("id", "in", [int(p) for p in post.get('partner_ids', "").split(",") if p])]
- domain_public = domain + [('website_published', '=', True)]
- partner_ids = partner_obj.search(request.cr, openerp.SUPERUSER_ID,
- domain_public, context=request.context)
- return partner_obj.google_map_json(request.cr, openerp.SUPERUSER_ID,
- partner_ids, request.context)
+ # filter real ints from query parameters and build a domain
+ clean_ids = []
+ for s in post.get('partner_ids', "").split(","):
+ try:
+ i = int(s)
+ clean_ids.append(i)
+ except ValueError:
+ pass
- @http.route(['/google_map/set_partner_position'], type='http', methods=['POST'], auth="public", website=True)
- def google_map_set_partner_position(self, *arg, **post):
- partner_obj = request.registry['res.partner']
+ # search for partners that can be displayed on a map
+ domain = [("id", "in", clean_ids), ('website_published', '=', True), ('is_company', '=', True)]
+ partners_ids = partner_obj.search(cr, SUPERUSER_ID, domain, context=context)
- partner_id = post.get('partner_id') and int(post['partner_id'])
- latitude = post.get('latitude') and float(post['latitude'])
- longitude = post.get('longitude') and float(post['longitude'])
+ # browse and format data
+ partner_data = {
+ "counter": len(partners_ids),
+ "partners": []
+ }
+ request.context.update({'show_address': True})
+ for partner in partner_obj.browse(cr, SUPERUSER_ID, partners_ids, context=context):
+ partner_data["partners"].append({
+ 'id': partner.id,
+ 'name': partner.name,
+ 'address': '\n'.join(partner.name_get()[0][1].split('\n')[1:]),
+ 'latitude': partner.partner_latitude,
+ 'longitude': partner.partner_longitude,
+ })
+ # generate the map
values = {
- 'partner_latitude': latitude,
- 'partner_longitude': longitude,
- 'date_localization': datetime.now().strftime('%Y-%m-%d'),
+ 'partner_url': post.get('partner_url'),
+ 'partner_data': json.dumps(partner_data)
}
- partner_obj.write(request.cr, openerp.SUPERUSER_ID, [partner_id], values,
- request.context)
-
-
-# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:
+ return request.website.render("website_google_map.google_map", values)
+++ /dev/null
-import res_partner
\ No newline at end of file
+++ /dev/null
-# -*- coding: utf-8 -*-
-
-from openerp.osv import osv
-
-import simplejson
-import werkzeug.wrappers
-
-
-class res_partner(osv.Model):
- _inherit = 'res.partner'
-
- def google_map_json(self, cr, uid, ids, context=None):
- data = {
- "counter": len(ids),
- "partners": []
- }
- for partner in self.pool.get('res.partner').browse(cr, uid, ids, context={'show_address': True}):
- data["partners"].append({
- 'id': partner.id,
- 'name': partner.name,
- 'address': '\n'.join(partner.name_get()[0][1].split('\n')[1:]),
- 'latitude': partner.partner_latitude,
- 'longitude': partner.partner_longitude,
- })
-
- mime = 'application/json'
- body = "var data = " + "}, \n{".join(simplejson.dumps(data).split("}, {"))
- return werkzeug.wrappers.Response(body, headers=[('Content-Type', mime), ('Content-Length', len(body))])
--- /dev/null
+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;
+}
-function initialize(pt) {
- var center = new google.maps.LatLng(10.91, 5.38);
- var Geocoder = new google.maps.Geocoder();
+function initialize_map() {
+ 'use strict';
- var map = new google.maps.Map(document.getElementById('map'), {
- zoom: 1,
- center: center,
- mapTypeId: google.maps.MapTypeId.ROADMAP
- });
+ // 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
+ });
- var infoWindow = new google.maps.InfoWindow();
+ // ENABLE ADRESS GEOCODING
+ var Geocoder = new google.maps.Geocoder();
- google.maps.event.addListener(map, 'click', function() {
- infoWindow.close();
- });
+ // 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 partners = new google.maps.MarkerImage("/website_google_map/static/src/img/partners.png",new google.maps.Size(25, 25));
+ google.maps.event.addListener(map, 'click', function() {
+ infoWindow.close();
+ });
- var markers = [];
+ // 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);
+ };
- 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>' )+ '<br/>'+
- (p.type ? ' <b>' + p.type + '</b>' : '')+
- ' <pre>' + p.address + '</pre>'+
- '</div>'
- );
- infoWindow.open(map, marker);
- };
-
- var set_marker = function(partner) {
- 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;
-
- $.post("/google_map/set_partner_position", {
- 'partner_id': partner.id,
- 'latitude': location.ob,
- 'longitude': location.pb
- });
- partner.latitude = location.ob;
- partner.longitude = location.pb;
-
- map.setCenter(results[0].geometry.location);
- var marker = new google.maps.Marker({
- partner: partner,
- map: map,
- icon: partners,
- position: location
- });
- google.maps.event.addListener(marker, 'click', onMarkerClick);
- markers.push(marker);
+ // Create a bubble for a partner
+ var set_marker = function(partner) {
+ // If no lat & long, geocode adress
+ // 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 {
- console.debug('Geocode was not successful for the following reason: ' + status);
+ 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);
}
- });
+ };
- } else {
-
- var latLng = new google.maps.LatLng(partner.latitude, partner.longitude);
- var marker = new google.maps.Marker({
- partner: partner,
- icon: partners,
- position: latLng
- });
- google.maps.event.addListener(marker, 'click', onMarkerClick);
- markers.push(marker);
+ // 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]);
+ }
+ var markerCluster = new MarkerClusterer(map, markers);
}
-
- };
-
- if (data)
- for (var i = 0; i < data.counter; i++) {
- set_marker(data.partners[i]);
- }
- var markerCluster = new MarkerClusterer(map, markers);
}
-google.maps.event.addDomListener(window, 'load', initialize);
+// Initialize map once the DOM has been loaded
+google.maps.event.addDomListener(window, 'load', initialize_map);
<?xml version="1.0" encoding="utf-8"?>
<openerp>
- <data>
- <template id="google_map">
-
+<data>
+<template id="google_map">
<!DOCTYPE html>
<html>
- <head>
- <meta http-equiv="content-type" content="text/html; charset=utf-8" />
- <title>World wide map</title>
-
- <style type="text/css">
- body {
- margin: 0;
- padding: 0;
- font-family: Helvetica, Arial, sans-serif !important;
- }
- .marker {
- font-size: 12px !important;
- }
- .marker b {
- font-weight: 500;
- }
- .marker pre {
- font-size: 10px !important;
- }
- </style>
- <script>var partner_url = '<t t-raw="partner_url or ''"/>';</script>
- <script src="//maps.google.com/maps/api/js?sensor=false"></script>
- <script type="text/javascript" t-attf-src="/google_map/partners.json?partner_ids=#{ partner_ids }"></script>
- <script type="text/javascript" src="/website_google_map/static/src/js/markerclusterer_compiled.js"></script>
- <script src="//code.jquery.com/jquery-1.6.1.min.js"></script>
- <script type="text/javascript" src="/website_google_map/static/src/js/google_map.js"></script>
- </head>
- <body>
- <div id="map" t-attf-style="width: #{ width }px; height: #{ height }px"></div>
- </body>
+ <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/google-map.css" />
+ </head>
+ <body t-att-data-partner-url="partner_url or ''">
+ <script>
+ var odoo_partner_data = <t t-raw="partner_data"/>;
+ </script>
+ <div id="odoo-google-map"></div>
+ <script src="//maps.google.com/maps/api/js?sensor=false"></script>
+ <script type="text/javascript" src="/website_google_map/static/src/js/markerclusterer_compiled.js"></script>
+ <script type="text/javascript" src="/website_google_map/static/src/js/google_map.js"></script>
+ </body>
</html>
-
- </template>
- </data>
+</template>
+</data>
</openerp>
# Do not use semantic controller due to SUPERUSER_ID
@http.route(['/members/<partner_id>'], type='http', auth="public", website=True)
def partners_detail(self, partner_id, **post):
- mo = re.search('-([-0-9]+)$', str(partner_id))
+ mo = re.search('([-0-9]+)$', str(partner_id))
if mo:
partner_id = int(mo.group(1))
partner = request.registry['res.partner'].browse(request.cr, SUPERUSER_ID, partner_id, context=request.context)
values = {}
values['main_object'] = values['partner'] = partner
return request.website.render("website_membership.partner", values)
- return self.customers(**post)
+ return self.members(**post)
<div class="container">
<div class="row">
- <div class="col-md-4 mb32" id="left_column">
+ <div class="col-md-3 mb32" id="left_column">
<ul class="nav nav-pills nav-stacked mt16">
<li class="nav-header"><h3>Associations</h3></li>
<li t-att-class="'' if membership else 'active'"><a href="/members">All</a></li>
<template id="opt_index_country" name="Location"
optional="enabled" inherit_id="website_membership.index">
- <xpath expr="//div[@id='left_column']/ul[last()]" position="after">
+ <xpath expr="//div[@id='left_column']/ul[1]" position="after">
<ul class="nav nav-pills nav-stacked mt16">
<li class="nav-header"><h3>Location</h3></li>
<t t-foreach="countries">
<!-- Option: index: Left Google Map -->
<template id="opt_index_google_map" name="Left World Map"
optional="enabled" inherit_id="website_membership.index">
- <xpath expr="//div[@id='left_column']/ul[1]" position="before">
- <ul class="nav nav-pills nav-stacked mt16">
- <li class="nav-header"><h3>World Map</h3></li>
- <ul class="nav">
- <iframe t-attf-src="/google_map/?width=320&height=240&partner_ids=#{ google_map_partner_ids }&partner_url=/members"
- style="width:320px; height:260px; border:0; padding:0; margin:0;"></iframe>
- </ul>
+ <xpath expr="//div[@id='left_column']/ul[last()]" position="after">
+ <!-- modal for large map -->
+ <div class="modal fade partner_map_modal" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+ <h4 class="modal-title">World Map</h4>
+ </div>
+ <iframe t-attf-src="/google_map/?width=898&height=485&partner_ids=#{ google_map_partner_ids }&partner_url=/members/"
+ style="width:898px; height:485px; border:0; padding:0; margin:0;"></iframe>
+ </div>
+ </div>
+ </div>
+ <!-- modal end -->
+ <h3>World Map<button class="btn btn-link" data-toggle="modal" data-target=".partner_map_modal"><span class="fa fa-external-link" /></button></h3>
+ <ul class="nav">
+ <iframe t-attf-src="/google_map/?width=260&height=240&partner_ids=#{ google_map_partner_ids }&partner_url=/members/"
+ style="width:260px; height:240px; border:0; padding:0; margin:0;"></iframe>
</ul>
</xpath>
</template>