[MERGE] forward port of branch 8.0 up to c7648a1

This commit is contained in:
Christophe Simonis
2015-02-12 13:20:54 +01:00
11 changed files with 183 additions and 127 deletions
+5 -2
View File
@@ -5,7 +5,10 @@ Contributing to Odoo
TL;DR
* Use this [template](https://github.com/odoo/odoo/wiki/Contributing#reporting-issues) when reporting issues, and please search for duplicates first!
* The issues not linked to pull requests will be handled with a low priority.
* If you [make a pull request](https://github.com/odoo/odoo/wiki/Contributing#making-pull-requests),
do not create an issue! Use the PR description for that
* Issues are handled with a much lower priority than pull requests
* Use this [template](https://github.com/odoo/odoo/wiki/Contributing#reporting-issues)
when reporting issues. Please search for duplicates first!
* Pull requests must be made against the [correct version](https://github.com/odoo/odoo/wiki/Contributing#against-which-version-should-i-submit-a-patch)
* There are restrictions on the kind of [changes allowed in stable series](https://github.com/odoo/odoo/wiki/Contributing#what-does-stable-mean)
+4 -3
View File
@@ -1155,9 +1155,10 @@ class account_move_line(osv.osv):
move_ids = set()
for line in self.browse(cr, uid, ids, context=context):
move_ids.add(line.move_id.id)
context['journal_id'] = line.journal_id.id
context['period_id'] = line.period_id.id
result = super(account_move_line, self).unlink(cr, uid, [line.id], context=context)
localcontext = dict(context)
localcontext['journal_id'] = line.journal_id.id
localcontext['period_id'] = line.period_id.id
result = super(account_move_line, self).unlink(cr, uid, [line.id], context=localcontext)
move_ids = list(move_ids)
if check and move_ids:
move_obj.validate(cr, uid, move_ids, context=context)
+56 -47
View File
@@ -125,9 +125,9 @@ class calendar_attendee(osv.Model):
def ics_datetime(idate, allday=False):
if idate:
if allday:
return datetime.strptime(idate.split(' ')[0], DEFAULT_SERVER_DATE_FORMAT).replace(tzinfo=pytz.timezone('UTC'))
return openerp.fields.Date.from_string(idate)
else:
return datetime.strptime(idate.split('.')[0], DEFAULT_SERVER_DATETIME_FORMAT).replace(tzinfo=pytz.timezone('UTC'))
return openerp.fields.Datetime.from_string(idate).replace(tzinfo=pytz.timezone('UTC'))
return False
try:
@@ -374,12 +374,12 @@ class calendar_alarm_manager(osv.AbstractModel):
tuple_params += (partner_id, )
#Add filter on hours
tuple_params += (seconds, seconds,)
tuple_params += (seconds,)
cr.execute("""SELECT *
FROM ( %s WHERE cal.active = True ) AS ALL_EVENTS
WHERE ALL_EVENTS.first_alarm < (now() at time zone 'utc' + interval '%%s' second )
AND ALL_EVENTS.last_alarm > (now() at time zone 'utc' - interval '%%s' second )
AND ALL_EVENTS.last_event_date > (now() at time zone 'utc')
""" % base_request, tuple_params)
for event_id, first_alarm, last_alarm, first_meeting, last_meeting, min_duration, max_duration, rule in cr.fetchall():
@@ -396,20 +396,30 @@ class calendar_alarm_manager(osv.AbstractModel):
return res
def do_check_alarm_for_one_date(self, cr, uid, one_date, event, event_maxdelta, in_the_next_X_seconds, after=False, notif=True, mail=True, context=None):
res = []
alarm_type = []
def do_check_alarm_for_one_date(self, cr, uid, one_date, event, event_maxdelta, in_the_next_X_seconds, after=False, notif=True, mail=True, missing=False, context=None):
# one_date: date of the event to check (not the same that in the event browse if recurrent)
# event: Event browse record
# event_maxdelta: biggest duration from alarms for this event
# in_the_next_X_seconds: looking in the future (in seconds)
# after: if not False: will return alert if after this date (date as string - todo: change in master)
# missing: if not False: will return alert even if we are too late
# notif: Looking for type notification
# mail: looking for type email
res = []
# TODO: replace notif and email in master by alarm_type + remove event_maxdelta and if using it
alarm_type = []
if notif:
alarm_type.append('notification')
if mail:
alarm_type.append('email')
if one_date - timedelta(minutes=event_maxdelta) < datetime.now() + timedelta(seconds=in_the_next_X_seconds): # if an alarm is possible for this date
if one_date - timedelta(minutes=(missing and 0 or event_maxdelta)) < datetime.now() + timedelta(seconds=in_the_next_X_seconds): # if an alarm is possible for this date
for alarm in event.alarm_ids:
if alarm.type in alarm_type and \
one_date - timedelta(minutes=alarm.duration_minutes) < datetime.now() + timedelta(seconds=in_the_next_X_seconds) and \
(not after or one_date - timedelta(minutes=alarm.duration_minutes) > datetime.strptime(after.split('.')[0], DEFAULT_SERVER_DATETIME_FORMAT)):
one_date - timedelta(minutes=(missing and 0 or alarm.duration_minutes)) < datetime.now() + timedelta(seconds=in_the_next_X_seconds) and \
(not after or one_date - timedelta(minutes=alarm.duration_minutes) > openerp.fields.Datetime.from_string(after)):
alert = {
'alarm_id': alarm.id,
'event_id': event.id,
@@ -419,55 +429,53 @@ class calendar_alarm_manager(osv.AbstractModel):
return res
def get_next_mail(self, cr, uid, context=None):
now = openerp.fields.Datetime.to_string(datetime.now())
icp = self.pool['ir.config_parameter']
last_notif_mail = icp.get_param(cr, SUPERUSER_ID, 'calendar.last_notif_mail', default=False) or now
try:
cron = self.pool['ir.model.data'].get_object(
cr, uid, 'calendar', 'ir_cron_scheduler_alarm', context=context)
cron = self.pool['ir.model.data'].get_object(cr, uid, 'calendar', 'ir_cron_scheduler_alarm', context=context)
except ValueError:
_logger.error("Cron for " + self._name + " can not be identified !")
return False
if cron.interval_type == "weeks":
cron_interval = cron.interval_number * 7 * 24 * 60 * 60
elif cron.interval_type == "days":
cron_interval = cron.interval_number * 24 * 60 * 60
elif cron.interval_type == "hours":
cron_interval = cron.interval_number * 60 * 60
elif cron.interval_type == "minutes":
cron_interval = cron.interval_number * 60
elif cron.interval_type == "seconds":
cron_interval = cron.interval_number
else:
cron_interval = False
interval_to_second = {
"weeks": 7 * 24 * 60 * 60,
"days": 24 * 60 * 60,
"hours": 60 * 60,
"minutes": 60,
"seconds": 1
}
if not cron_interval:
if cron.interval_type not in interval_to_second.keys():
_logger.error("Cron delay can not be computed !")
return False
cron_interval = cron.interval_number * interval_to_second[cron.interval_type]
all_events = self.get_next_potential_limit_alarm(cr, uid, cron_interval, notif=False, context=context)
for event in all_events: # .values()
max_delta = all_events[event]['max_duration']
curEvent = self.pool.get('calendar.event').browse(cr, uid, event, context=context)
for curEvent in self.pool.get('calendar.event').browse(cr, uid, all_events.keys(), context=context):
max_delta = all_events[curEvent.id]['max_duration']
if curEvent.recurrency:
bFound = False
LastFound = False
at_least_one = False
last_found = False
for one_date in self.pool.get('calendar.event').get_recurrent_date_by_event(cr, uid, curEvent, context=context):
in_date_format = one_date.replace(tzinfo=None)
LastFound = self.do_check_alarm_for_one_date(cr, uid, in_date_format, curEvent, max_delta, cron_interval, notif=False, context=context)
if LastFound:
for alert in LastFound:
self.do_mail_reminder(cr, uid, alert, context=context)
if not bFound: # if it's the first alarm for this recurrent event
bFound = True
if bFound and not LastFound: # if the precedent event had an alarm but not this one, we can stop the search for this event
last_found = self.do_check_alarm_for_one_date(cr, uid, in_date_format, curEvent, max_delta, 0, after=last_notif_mail, notif=False, missing=True, context=context)
for alert in last_found:
self.do_mail_reminder(cr, uid, alert, context=context)
at_least_one = True # if it's the first alarm for this recurrent event
if at_least_one and not last_found: # if the precedent event had an alarm but not this one, we can stop the search for this event
break
else:
in_date_format = datetime.strptime(curEvent.start, DEFAULT_SERVER_DATETIME_FORMAT)
LastFound = self.do_check_alarm_for_one_date(cr, uid, in_date_format, curEvent, max_delta, cron_interval, notif=False, context=context)
if LastFound:
for alert in LastFound:
self.do_mail_reminder(cr, uid, alert, context=context)
last_found = self.do_check_alarm_for_one_date(cr, uid, in_date_format, curEvent, max_delta, 0, after=last_notif_mail, notif=False, missing=True, context=context)
for alert in last_found:
self.do_mail_reminder(cr, uid, alert, context=context)
icp.set_param(cr, SUPERUSER_ID, 'calendar.last_notif_mail', now)
def get_next_notif(self, cr, uid, context=None):
ajax_check_every_seconds = 300
@@ -497,7 +505,7 @@ class calendar_alarm_manager(osv.AbstractModel):
break
else:
in_date_format = datetime.strptime(curEvent.start, DEFAULT_SERVER_DATETIME_FORMAT)
LastFound = self.do_check_alarm_for_one_date(cr, uid, in_date_format, curEvent, max_delta, ajax_check_every_seconds, partner.calendar_last_notif_ack, mail=False, context=context)
LastFound = self.do_check_alarm_for_one_date(cr, uid, in_date_format, curEvent, max_delta, ajax_check_every_seconds, after=partner.calendar_last_notif_ack, mail=False, context=context)
if LastFound:
for alert in LastFound:
all_notif.append(self.do_notif_reminder(cr, uid, alert, context=context))
@@ -516,6 +524,7 @@ class calendar_alarm_manager(osv.AbstractModel):
cr,
uid,
[att.id for att in event.attendee_ids],
email_from=event.user_id.partner_id.email,
template_xmlid='calendar_template_meeting_reminder',
force=True,
context=context
@@ -885,12 +894,12 @@ class calendar_event(osv.Model):
stop_date = values.get('stop_date') or event.stop_date
start_date = values.get('start_date') or event.start_date
if stop_date and start_date:
diff = datetime.strptime(stop_date.split(' ')[0], DEFAULT_SERVER_DATE_FORMAT) - datetime.strptime(start_date.split(' ')[0], DEFAULT_SERVER_DATE_FORMAT)
diff = openerp.fields.Date.from_string(stop_date) - openerp.fields.Date.from_string(start_date)
elif values.get('stop_datetime') or values.get('start_datetime'):
stop_datetime = values.get('stop_datetime') or event.stop_datetime
start_datetime = values.get('start_datetime') or event.start_datetime
if stop_datetime and start_datetime:
diff = datetime.strptime(stop_datetime.split('.')[0], DEFAULT_SERVER_DATETIME_FORMAT) - datetime.strptime(start_datetime.split('.')[0], DEFAULT_SERVER_DATETIME_FORMAT)
diff = openerp.fields.Datetime.from_string(stop_datetime) - openerp.fields.Datetime.from_string(start_datetime)
if diff:
duration = float(diff.days) * 24 + (float(diff.seconds) / 3600)
values['duration'] = round(duration, 2)
@@ -1012,7 +1021,7 @@ class calendar_event(osv.Model):
tz = pytz.timezone(user.tz) if user.tz else pytz.utc
if starttime:
start = datetime.strptime(starttime.split(' ')[0], DEFAULT_SERVER_DATE_FORMAT)
start = openerp.fields.Datetime.from_string(starttime)
startdate = tz.localize(start) # Add "+hh:mm" timezone
startdate = startdate.replace(hour=8) # Set 8 AM in localtime
startdate = startdate.astimezone(pytz.utc) # Convert to UTC
@@ -1433,7 +1442,7 @@ class calendar_event(osv.Model):
def get_interval(self, cr, uid, ids, date, interval, tz=None, context=None):
#Function used only in calendar_event_data.xml for email template
date = datetime.strptime(date.split('.')[0], DEFAULT_SERVER_DATETIME_FORMAT)
date = openerp.fields.Datetime.from_string(date)
if tz:
timezone = pytz.timezone(tz or 'UTC')
+6 -26
View File
@@ -38,39 +38,19 @@
<field name="duration" eval="1" />
<field name="interval">days</field>
<field name="type">notification</field>
</record>
</record>
<record model="calendar.alarm" id="alarm_mail_1">
<field name="name">15 min mail</field>
<field name="duration" eval="15" />
<field name="interval">minutes</field>
<field name="name">2~3 hours mail</field>
<field name="duration" eval="3" />
<field name="interval">hours</field>
<field name="type">email</field>
</record>
<record model="calendar.alarm" id="alarm_mail_2">
<field name="name">30 min mail</field>
<field name="duration" eval="30" />
<field name="interval">minutes</field>
<field name="type">email</field>
</record>
<record model="calendar.alarm" id="alarm_mail_3">
<field name="name">1 hour mail</field>
<field name="duration" eval="1" />
<field name="name">5~6 hours mail</field>
<field name="duration" eval="6" />
<field name="interval">hours</field>
<field name="type">email</field>
</record>
<record model="calendar.alarm" id="alarm_mail_4">
<field name="name">2 hours mail</field>
<field name="duration" eval="2" />
<field name="interval">hours</field>
<field name="type">email</field>
</record>
<record model="calendar.alarm" id="alarm_mail_5">
<field name="name">1 day mail</field>
<field name="duration" eval="1" />
<field name="interval">days</field>
<field name="type">email</field>
</record>
<record model="calendar.event.type" id="categ_meet1">
<field name="name">Customer Meeting</field>
+25 -2
View File
@@ -21,6 +21,27 @@
<field name="view_type">form</field>
<field name="view_id" ref="view_calendar_event_type_tree"/>
</record>
<!-- Calendar Alarm -->
<record id="view_calendar_alarm_tree" model="ir.ui.view">
<field name="name">Calendar Alarm Tree</field>
<field name="model">calendar.alarm</field>
<field name="arch" type="xml">
<tree string="Calendar Alarm" editable="bottom">
<field name="name"/>
<field name="type"/>
<field name="duration"/>
<field name="interval"/>
</tree>
</field>
</record>
<record id="action_calendar_alarm" model="ir.actions.act_window">
<field name="name">Calendar Alarm</field>
<field name="res_model">calendar.alarm</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_calendar_alarm_tree"/>
</record>
<!-- Calendar Events Form View -->
@@ -226,7 +247,6 @@
<calendar string="Meetings" date_start="start" date_stop="stop" date_delay="duration" all_day="allday"
display="[name]" color="color_partner_id" attendee="partner_ids" avatar_model="res.partner"
use_contacts="True" event_open_popup="%(calendar.view_calendar_event_form_popup)s">
<field name="name"/>
<field name="user_id"/>
<field name="color_partner_id"/>
@@ -311,10 +331,13 @@
<field name="view_id" ref="view_calendar_event_gantt"/>
</record>
<menuitem name="Calendar" id="mail_menu_calendar" parent="mail.mail_my_stuff" sequence="10" action="action_calendar_event"/>
<menuitem id="menu_calendar_configuration" name="Calendar" parent="base.menu_custom" groups="base.group_no_one"/>
<menuitem id="menu_calendar_event_type" parent="menu_calendar_configuration" action="action_calendar_event_type" groups="base.group_no_one"/>
<menuitem id="menu_calendar_alarm" parent="menu_calendar_configuration" action="action_calendar_alarm" groups="base.group_no_one"/>
<!-- called in js from '/js/base_calendar.js' -->
<record id="action_calendar_event_notify" model="ir.actions.act_window">
<field name="name">Meetings</field>
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<data noupdate="1">
<record id="event_type" model="event.type">
<field name="name">Generic Events</field>
+19 -2
View File
@@ -324,6 +324,11 @@ class stock_quant(osv.osv):
'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.quant', context=c),
}
def init(self, cr):
cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s', ('stock_quant_product_location_index',))
if not cr.fetchone():
cr.execute('CREATE INDEX stock_quant_product_location_index ON stock_quant (product_id, location_id, company_id, qty, in_date, reservation_id)')
def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False, lazy=True):
''' Overwrite the read_group in order to sum the function field 'inventory_value' in group by'''
res = super(stock_quant, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby, lazy=lazy)
@@ -415,7 +420,12 @@ class stock_quant(osv.osv):
self.move_quants_write(cr, uid, to_move_quants, move, location_to, dest_package_id, context=context)
self.pool.get('stock.move').recalculate_move_state(cr, uid, to_recompute_move_ids, context=context)
if location_to.usage == 'internal':
if self.search(cr, uid, [('product_id', '=', move.product_id.id), ('qty','<', 0)], limit=1, context=context):
# Do manual search for quant to avoid full table scan (order by id)
cr.execute("""
SELECT 0 FROM stock_quant, stock_location WHERE product_id = %s AND stock_location.id = stock_quant.location_id AND
((stock_location.parent_left >= %s AND stock_location.parent_left < %s) OR stock_location.id = %s) AND qty < 0.0 LIMIT 1
""", (move.product_id.id, location_to.parent_left, location_to.parent_right, location_to.id))
if cr.fetchone():
for quant in quants_reconcile:
self._quant_reconcile_negative(cr, uid, quant, move, context=context)
@@ -529,7 +539,10 @@ class stock_quant(osv.osv):
return False
qty_round = float_round(qty, precision_rounding=rounding)
new_qty_round = float_round(quant.qty - qty, precision_rounding=rounding)
new_quant = self.copy(cr, SUPERUSER_ID, quant.id, default={'qty': new_qty_round, 'history_ids': [(4, x.id) for x in quant.history_ids]}, context=context)
# Fetch the history_ids manually as it will not do a join with the stock moves then (=> a lot faster)
cr.execute("""SELECT move_id FROM stock_quant_move_rel WHERE quant_id = %s""", (quant.id,))
res = cr.fetchall()
new_quant = self.copy(cr, SUPERUSER_ID, quant.id, default={'qty': new_qty_round, 'history_ids': [(4, x[0]) for x in res]}, context=context)
self.write(cr, SUPERUSER_ID, quant.id, {'qty': qty_round}, context=context)
return self.browse(cr, uid, new_quant, context=context)
@@ -1858,6 +1871,10 @@ class stock_move(osv.osv):
'You try to move a product using a UoM that is not compatible with the UoM of the product moved. Please use an UoM in the same UoM category.',
['product_uom']),
]
def init(self, cr):
cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s', ('stock_move_product_location_index',))
if not cr.fetchone():
cr.execute('CREATE INDEX stock_move_product_location_index ON stock_move (product_id, location_id, location_dest_id, company_id, state)')
@api.cr_uid_ids_context
def do_unreserve(self, cr, uid, move_ids, context=None):
+1 -1
View File
@@ -1250,7 +1250,7 @@ instance.web.Client = instance.web.Widget.extend({
this.crashmanager = new instance.web.CrashManager();
instance.session.on('error', this.crashmanager, this.crashmanager.rpc_error);
self.notification = new instance.web.Notification(this);
self.notification.appendTo(self.$el);
self.notification.appendTo(self.$el.find('.openerp'));
self.loading = new instance.web.Loading(self);
self.loading.appendTo(self.$('.openerp_webclient_container'));
self.action_manager = new instance.web.ActionManager(self);
+7 -7
View File
@@ -1,15 +1,12 @@
# -*- coding: utf-8 -*-
import logging
import urlparse
import unittest2
import urllib2
import time
import werkzeug.urls
import lxml.html
import openerp
from openerp import tools
import re
_logger = logging.getLogger(__name__)
@@ -25,12 +22,15 @@ class Crawler(openerp.tests.HttpCase):
post_install = True
def crawl(self, url, seen=None, msg=''):
if seen == None:
if seen == None:
seen = set()
if url in seen:
url_slug = re.sub(r"[/](([^/=?&]+-)?[0-9]+)([/]|$)", '/<slug>/', url)
url_slug = re.sub(r"([^/=?&]+)=[^/=?&]+", '\g<1>=param', url_slug)
if url_slug in seen:
return seen
else:
seen.add(url)
seen.add(url_slug)
_logger.info("%s %s", msg, url)
r = self.url_open(url)
+36 -14
View File
@@ -14,18 +14,18 @@ class WebsiteMembership(http.Controller):
@http.route([
'/members',
'/members/page/<int:page>',
'/members/association/<int:membership_id>',
'/members/association/<int:membership_id>/page/<int:page>',
'/members/association/<membership_id>',
'/members/association/<membership_id>/page/<int:page>',
'/members/country/<int:country_id>',
'/members/country/<country_name>-<int:country_id>',
'/members/country/<int:country_id>/page/<int:page>',
'/members/country/<country_name>-<int:country_id>/page/<int:page>',
'/members/association/<int:membership_id>/country/<country_name>-<int:country_id>',
'/members/association/<int:membership_id>/country/<int:country_id>',
'/members/association/<int:membership_id>/country/<country_name>-<int:country_id>/page/<int:page>',
'/members/association/<int:membership_id>/country/<int:country_id>/page/<int:page>',
'/members/association/<membership_id>/country/<country_name>-<int:country_id>',
'/members/association/<membership_id>/country/<int:country_id>',
'/members/association/<membership_id>/country/<country_name>-<int:country_id>/page/<int:page>',
'/members/association/<membership_id>/country/<int:country_id>/page/<int:page>',
], type='http', auth="public", website=True)
def members(self, membership_id=None, country_name=None, country_id=0, page=0, **post):
cr, uid, context = request.cr, request.uid, request.context
@@ -38,7 +38,8 @@ class WebsiteMembership(http.Controller):
# base domain for groupby / searches
base_line_domain = [("partner.website_published", "=", True), ('state', 'in', ['free', 'paid'])]
if membership_id:
if membership_id and membership_id != 'free':
membership_id = int(membership_id)
base_line_domain.append(('membership_id', '=', membership_id))
membership = product_obj.browse(cr, uid, membership_id, context=context)
else:
@@ -48,9 +49,14 @@ class WebsiteMembership(http.Controller):
('partner.website_description', 'ilike', post_name)]
# group by country, based on all customers (base domain)
membership_line_ids = membership_line_obj.search(cr, SUPERUSER_ID, base_line_domain, context=context)
if membership_id != 'free':
membership_line_ids = membership_line_obj.search(cr, SUPERUSER_ID, base_line_domain, context=context)
country_domain = ('member_lines', 'in', membership_line_ids)
else:
membership_line_ids = []
country_domain = ('free_member', '=', True)
countries = partner_obj.read_group(
cr, uid, [('member_lines', 'in', membership_line_ids), ("website_published", "=", True)], ["id", "country_id"],
cr, uid, [country_domain, ("website_published", "=", True)], ["id", "country_id"],
groupby="country_id", orderby="country_id", context=request.context)
countries_total = sum(country_dict['country_id_count'] for country_dict in countries)
@@ -77,22 +83,38 @@ class WebsiteMembership(http.Controller):
line_domain.append(('membership_id', 'in', membership_ids))
# displayed membership lines
membership_line_ids = membership_line_obj.search(cr, SUPERUSER_ID, line_domain, context=context)
if membership_id != 'free':
membership_line_ids = membership_line_obj.search(cr, SUPERUSER_ID, line_domain, context=context)
membership_lines = membership_line_obj.browse(cr, uid, membership_line_ids, context=context)
# TODO: Following line can be deleted in master. Kept for retrocompatibility.
membership_lines = sorted(membership_lines, key=lambda x: x.membership_id.website_sequence)
partner_ids = [m.partner.id for m in membership_lines]
free_partner_ids = partner_obj.search(cr, uid, [('free_member', '=', True), ('website_published', '=', True)], context=context)
google_map_partner_ids = ",".join(map(str, partner_ids))
memberships_data = []
for membership_record in memberships:
memberships_data.append({'id': membership_record.id, 'name': membership_record.name})
memberships_partner_ids = {}
for line in membership_lines:
memberships_partner_ids.setdefault(line.membership_id.id, []).append(line.partner.id)
if free_partner_ids:
memberships_data.append({'id': 'free', 'name': _('Free Members')})
if not membership_id or membership_id == 'free':
memberships_partner_ids['free'] = free_partner_ids
partners = dict((p.id, p) for p in partner_obj.browse(request.cr, SUPERUSER_ID, partner_ids, request.context))
partners = dict((p.id, p) for p in partner_obj.browse(request.cr, SUPERUSER_ID, list(set(partner_ids + free_partner_ids)), request.context))
# request pager for lines
pager = request.website.pager(url="/members", total=len(membership_line_ids), page=page, step=self._references_per_page, scope=7, url_args=post)
values = {
'partners': partners,
'membership_lines': membership_lines,
'memberships': memberships,
'membership': membership,
'membership_lines': membership_lines, # TODO: This line can be deleted in master. Kept for retrocompatibility.
'memberships': memberships, # TODO: This line too.
'membership': membership, # TODO: This line too.
'memberships_data': memberships_data,
'memberships_partner_ids': memberships_partner_ids,
'membership_id': membership_id,
'countries': countries,
'current_country': current_country and [current_country['id'], current_country['name']] or None,
'current_country_id': current_country and current_country['id'] or 0,
@@ -31,10 +31,10 @@
<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>
<t t-foreach="memberships" t-as="membership_id">
<li t-att-class="membership and membership_id.id == membership.id and 'active' or ''">
<a t-attf-href="/members/association/#{ membership_id.id }#{current_country and '/country/%s' % slug(current_country) or ''}#{ search }"><t t-esc="membership_id.name"/></a>
<li t-att-class="'' if membership_id else 'active'"><a href="/members">All</a></li>
<t t-foreach="memberships_data" t-as="membership_data">
<li t-att-class="membership_id and membership_data['id'] == membership_id and 'active' or ''">
<a t-attf-href="/members/association/#{ membership_data['id'] }#{current_country and '/country/%s' % slug(current_country) or ''}#{ search }"><t t-esc="membership_data['name']"/></a>
</li>
</t>
</ul>
@@ -51,27 +51,28 @@
</form>
</div>
<div>
<t t-if="not membership_lines">
<t t-if="not memberships_partner_ids">
<p>No result found.</p>
</t>
<t t-foreach="membership_lines" t-as="membership_line_id">
<t t-if="current_membership_id != membership_line_id.membership_id.id">
<t t-set="current_membership_id" t-value="membership_line_id.membership_id.id"/>
<h3 class="text-center"><span t-field="membership_line_id.membership_id"/></h3>
<t t-foreach="memberships_data" t-as="membership_data">
<t t-if="memberships_partner_ids.get(membership_data['id'])">
<h3 class="text-center"><span t-esc="membership_data['name']"/></h3>
<t t-foreach="memberships_partner_ids[membership_data['id']]" t-as="partner_id">
<t t-set="partner" t-value="partners[partner_id]"/>
<div class="media">
<a class="pull-left" t-attf-href="/members/#{slug(partner)}"
t-field="partner.image_small"
t-field-options='{"widget": "image", "class": "media-object"}'
></a>
<div class="media-body" style="min-height: 64px;">
<a class="media-heading" t-attf-href="/members/#{slug(partner)}">
<span t-field="partner.display_name"/>
</a>
<div t-field="partner.website_short_description"/>
</div>
</div>
</t>
</t>
<t t-set="partner" t-value="partners[membership_line_id.partner.id]"/>
<div class="media">
<a class="pull-left" t-attf-href="/members/#{slug(partner)}"
t-field="partner.image_small"
t-field-options='{"widget": "image", "class": "media-object"}'
></a>
<div class="media-body" style="min-height: 64px;">
<a class="media-heading" t-attf-href="/members/#{slug(partner)}">
<span t-field="partner.display_name"/>
</a>
<div t-field="partner.website_short_description"/>
</div>
</div>
</t>
</div>
</div>