diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py
index 1092ec33aeaa7c37259bb7ebc518860410388350..5b45f8dd02abe53b266875317cf539b6fd911b93 100644
--- a/addons/account/account_invoice.py
+++ b/addons/account/account_invoice.py
@@ -572,8 +572,8 @@ class account_invoice(models.Model):
             if 'journal_id' in journal_defaults:
                 values['journal_id'] = journal_defaults['journal_id']
             if not values.get('journal_id'):
-                field_desc = journals.fields_get(['journal_id'])
-                type_label = next(t for t, label in field_desc['journal_id']['selection'] if t == journal_type)
+                field_desc = journals.fields_get(['type'])
+                type_label = next(t for t, label in field_desc['type']['selection'] if t == journal_type)
                 action = self.env.ref('account.action_account_journal_form')
                 msg = _('Cannot find any account journal of type "%s" for this company, You should create one.\n Please go to Journal Configuration') % type_label
                 raise RedirectWarning(msg, action.id, _('Go to the configuration panel'))
diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py
index c4fd782bea2349a8e49cc4dde1d7c1ba74324045..d994237e094ec44ad1cff8424d1071684bc40a05 100644
--- a/addons/crm/crm_lead.py
+++ b/addons/crm/crm_lead.py
@@ -229,10 +229,12 @@ class crm_lead(format_address, osv.osv):
         'user_id': fields.many2one('res.users', 'Salesperson', select=True, track_visibility='onchange'),
         'referred': fields.char('Referred By'),
         'date_open': fields.datetime('Assigned', readonly=True),
-        'day_open': fields.function(_compute_day, string='Days to Open', \
-                                multi='day_open', type="float", store=True),
-        'day_close': fields.function(_compute_day, string='Days to Close', \
-                                multi='day_open', type="float", store=True),
+        'day_open': fields.function(_compute_day, string='Days to Assign',
+                                    multi='day_open', type="float",
+                                    store={'crm.lead': (lambda self, cr, uid, ids, c={}: ids, ['date_open'], 10)}),
+        'day_close': fields.function(_compute_day, string='Days to Close',
+                                     multi='day_open', type="float",
+                                     store={'crm.lead': (lambda self, cr, uid, ids, c={}: ids, ['date_closed'], 10)}),
         'date_last_stage_update': fields.datetime('Last Stage Update', select=True),
 
         # Messaging and marketing
@@ -887,6 +889,8 @@ class crm_lead(format_address, osv.osv):
             context['default_type'] = vals.get('type')
         if vals.get('section_id') and not context.get('default_section_id'):
             context['default_section_id'] = vals.get('section_id')
+        if vals.get('user_id'):
+            vals['date_open'] = fields.datetime.now()
 
         # context: no_log, because subtype already handle this
         create_context = dict(context, mail_create_nolog=True)
@@ -896,7 +900,9 @@ class crm_lead(format_address, osv.osv):
         # stage change: update date_last_stage_update
         if 'stage_id' in vals:
             vals['date_last_stage_update'] = fields.datetime.now()
-        # stage change with new stage: update probability
+        if vals.get('user_id'):
+            vals['date_open'] = fields.datetime.now()
+        # stage change with new stage: update probability and date_closed
         if vals.get('stage_id') and not vals.get('probability'):
             onchange_stage_values = self.onchange_stage_id(cr, uid, ids, vals.get('stage_id'), context=context)['value']
             vals.update(onchange_stage_values)
diff --git a/addons/email_template/wizard/mail_compose_message.py b/addons/email_template/wizard/mail_compose_message.py
index ebe66757b096c51a554893475b08e614c6b3bb9d..f79aa77ddc9a358d28f1d23a4436cdc28bed7249 100644
--- a/addons/email_template/wizard/mail_compose_message.py
+++ b/addons/email_template/wizard/mail_compose_message.py
@@ -19,7 +19,7 @@
 #
 ##############################################################################
 
-from openerp import tools, SUPERUSER_ID
+from openerp import tools
 from openerp.osv import osv, fields
 
 
@@ -54,6 +54,8 @@ class mail_compose_message(osv.TransientModel):
                     res.get('model'), res.get('res_id'), context=context
                 )['value']
             )
+        if fields is not None:
+            [res.pop(field, None) for field in res.keys() if field not in fields]
         return res
 
     _columns = {
@@ -113,7 +115,9 @@ class mail_compose_message(osv.TransientModel):
                 }
                 values.setdefault('attachment_ids', list()).append(ir_attach_obj.create(cr, uid, data_attach, context=context))
         else:
-            values = self.default_get(cr, uid, ['subject', 'body', 'email_from', 'reply_to', 'attachment_ids', 'mail_server_id'], context=context)
+            default_context = dict(context, default_composition_mode=composition_mode, default_model=model, default_res_id=res_id)
+            default_values = self.default_get(cr, uid, ['composition_mode', 'model', 'res_id', 'subject', 'body', 'email_from', 'reply_to', 'attachment_ids', 'mail_server_id'], context=default_context)
+            values = dict((key, default_values[key]) for key in ['subject', 'body', 'email_from', 'reply_to', 'attachment_ids', 'mail_server_id'] if key in default_values)
 
         if values.get('body_html'):
             values['body'] = values.pop('body_html')
diff --git a/addons/hr_contract/hr_contract.py b/addons/hr_contract/hr_contract.py
index 8b58c3efd6107b769f6bc0c9090aa393c0380800..b80b93bc3a5fa53d5aac056f6a6c4217a92deaeb 100644
--- a/addons/hr_contract/hr_contract.py
+++ b/addons/hr_contract/hr_contract.py
@@ -20,6 +20,7 @@
 ##############################################################################
 import time
 
+from openerp import SUPERUSER_ID
 from openerp.osv import fields, osv
 
 class hr_employee(osv.osv):
@@ -41,7 +42,7 @@ class hr_employee(osv.osv):
     def _contracts_count(self, cr, uid, ids, field_name, arg, context=None):
         Contract = self.pool['hr.contract']
         return {
-            employee_id: Contract.search_count(cr,uid, [('employee_id', '=', employee_id)], context=context)
+            employee_id: Contract.search_count(cr, SUPERUSER_ID, [('employee_id', '=', employee_id)], context=context)
             for employee_id in ids
         }
 
@@ -53,7 +54,7 @@ class hr_employee(osv.osv):
         'vehicle': fields.char('Company Vehicle'),
         'vehicle_distance': fields.integer('Home-Work Dist.', help="In kilometers"),
         'contract_ids': fields.one2many('hr.contract', 'employee_id', 'Contracts'),
-        'contract_id':fields.function(_get_latest_contract, string='Contract', type='many2one', relation="hr.contract", help='Latest contract of the employee'),
+        'contract_id': fields.function(_get_latest_contract, string='Contract', type='many2one', relation="hr.contract", help='Latest contract of the employee'),
         'contracts_count': fields.function(_contracts_count, type='integer', string='Contracts'),
     }
 
diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py
index 66f843cd03a7b14e5713f70891b0571e1f363370..a33982b38600f7206c69a217ce1df2a293702126 100644
--- a/addons/mail/wizard/mail_compose_message.py
+++ b/addons/mail/wizard/mail_compose_message.py
@@ -68,7 +68,7 @@ class mail_compose_message(osv.TransientModel):
         result = super(mail_compose_message, self).default_get(cr, uid, fields, context=context)
 
         # v6.1 compatibility mode
-        result['composition_mode'] = result.get('composition_mode', context.get('mail.compose.message.mode'))
+        result['composition_mode'] = result.get('composition_mode', context.get('mail.compose.message.mode', 'comment'))
         result['model'] = result.get('model', context.get('active_model'))
         result['res_id'] = result.get('res_id', context.get('active_id'))
         result['parent_id'] = result.get('parent_id', context.get('message_id'))
@@ -97,6 +97,9 @@ class mail_compose_message(osv.TransientModel):
         if result['model'] == 'res.users' and result['res_id'] == uid:
             result['model'] = 'res.partner'
             result['res_id'] = self.pool.get('res.users').browse(cr, uid, uid).partner_id.id
+
+        if fields is not None:
+            [result.pop(field, None) for field in result.keys() if field not in fields]
         return result
 
     def _get_composition_mode_selection(self, cr, uid, context=None):
diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py
index e2e94233861dcabc56c052022da256c7b1dcdebe..2ede7b27b9d818be2b9aac5b022869804e78920b 100644
--- a/addons/mrp/mrp.py
+++ b/addons/mrp/mrp.py
@@ -239,16 +239,27 @@ class mrp_bom(osv.osv):
         """
         if properties is None:
             properties = []
-        domain = None
         if product_id:
-            domain = ['|',('product_id', '=', product_id),('product_tmpl_id.product_variant_ids', '=', product_id)]
-        else:
+            if not product_tmpl_id:
+                product_tmpl_id = self.pool['product.product'].browse(cr, uid, product_id).product_tmpl_id.id
+            domain = [
+                '|',
+                    ('product_id', '=', product_id),
+                    '&',
+                        ('product_id', '=', False),
+                        ('product_tmpl_id', '=', product_tmpl_id)
+            ]
+        elif product_tmpl_id:
             domain = [('product_id', '=', False), ('product_tmpl_id', '=', product_tmpl_id)]
+        else:
+            # neither product nor template, makes no sense to search
+            return False
         if product_uom:
             domain +=  [('product_uom','=',product_uom)]
         domain = domain + [ '|', ('date_start', '=', False), ('date_start', '<=', time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)),
                             '|', ('date_stop', '=', False), ('date_stop', '>=', time.strftime(DEFAULT_SERVER_DATETIME_FORMAT))]
-        ids = self.search(cr, uid, domain)
+        # order to prioritize bom with product_id over the one without
+        ids = self.search(cr, uid, domain, order='product_id')
         for bom in self.pool.get('mrp.bom').browse(cr, uid, ids):
             if not set(map(int,bom.property_ids or [])) - set(properties or []):
                 return bom.id
diff --git a/addons/project_issue/project_issue.py b/addons/project_issue/project_issue.py
index 016313b5e44cfc40cd327e368ba9823a19b6b17a..a2fbed7492e5856dbd761b5583713b84380ced35 100644
--- a/addons/project_issue/project_issue.py
+++ b/addons/project_issue/project_issue.py
@@ -25,9 +25,11 @@ from openerp import api
 from openerp import SUPERUSER_ID
 from openerp import tools
 from openerp.osv import fields, osv, orm
+from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
 from openerp.tools import html2plaintext
 from openerp.tools.translate import _
 
+
 class project_issue_version(osv.Model):
     _name = "project.issue.version"
     _order = "name desc"
@@ -129,73 +131,51 @@ class project_issue(osv.Model):
         @return: difference between current date and log date
         @param context: A standard dictionary for contextual values
         """
-        cal_obj = self.pool.get('resource.calendar')
-        res_obj = self.pool.get('resource.resource')
+        Calendar = self.pool['resource.calendar']
 
-        res = {}
+        res = dict.fromkeys(ids, dict())
         for issue in self.browse(cr, uid, ids, context=context):
-
+            values = {
+                'day_open': 0.0, 'day_close': 0.0,
+                'working_hours_open': 0.0, 'working_hours_close': 0.0,
+                'days_since_creation': 0.0, 'inactivity_days': 0.0,
+            }
             # if the working hours on the project are not defined, use default ones (8 -> 12 and 13 -> 17 * 5), represented by None
-            if not issue.project_id or not issue.project_id.resource_calendar_id:
-                working_hours = None
+            calendar_id = None
+            if issue.project_id and issue.project_id.resource_calendar_id:
+                calendar_id = issue.project_id.resource_calendar_id.id
+
+            dt_create_date = datetime.strptime(issue.create_date, DEFAULT_SERVER_DATETIME_FORMAT)
+
+            if issue.date_open:
+                dt_date_open = datetime.strptime(issue.date_open, DEFAULT_SERVER_DATETIME_FORMAT)
+                values['day_open'] = (dt_date_open - dt_create_date).total_seconds() / (24.0 * 3600)
+                values['working_hours_open'] = Calendar._interval_hours_get(
+                    cr, uid, calendar_id, dt_create_date, dt_date_open,
+                    timezone_from_uid=issue.user_id.id or uid,
+                    exclude_leaves=False, context=context)
+
+            if issue.date_closed:
+                dt_date_closed = datetime.strptime(issue.date_closed, DEFAULT_SERVER_DATETIME_FORMAT)
+                values['day_close'] = (dt_date_closed - dt_create_date).total_seconds() / (24.0 * 3600)
+                values['working_hours_close'] = Calendar._interval_hours_get(
+                    cr, uid, calendar_id, dt_create_date, dt_date_closed,
+                    timezone_from_uid=issue.user_id.id or uid,
+                    exclude_leaves=False, context=context)
+
+            days_since_creation = datetime.today() - dt_create_date
+            values['days_since_creation'] = days_since_creation.days
+            if issue.date_action_last:
+                inactive_days = datetime.today() - datetime.strptime(issue.date_action_last, DEFAULT_SERVER_DATETIME_FORMAT)
+            elif issue.date_last_stage_update:
+                inactive_days = datetime.today() - datetime.strptime(issue.date_last_stage_update, DEFAULT_SERVER_DATETIME_FORMAT)
             else:
-                working_hours = issue.project_id.resource_calendar_id.id
+                inactive_days = datetime.today() - datetime.strptime(issue.create_date, DEFAULT_SERVER_DATETIME_FORMAT)
+            values['inactivity_days'] = inactive_days.days
 
-            res[issue.id] = {}
+            # filter only required values
             for field in fields:
-                duration = 0
-                ans = False
-                hours = 0
-
-                date_create = datetime.strptime(issue.create_date, "%Y-%m-%d %H:%M:%S")
-                if field in ['working_hours_open','day_open']:
-                    if issue.date_open:
-                        date_open = datetime.strptime(issue.date_open, "%Y-%m-%d %H:%M:%S")
-                        ans = date_open - date_create
-                        date_until = issue.date_open
-                        #Calculating no. of working hours to open the issue
-                        hours = cal_obj._interval_hours_get(cr, uid, working_hours,
-                                                           date_create,
-                                                           date_open,
-                                                           timezone_from_uid=issue.user_id.id or uid,
-                                                           exclude_leaves=False,
-                                                           context=context)
-                elif field in ['working_hours_close','day_close']:
-                    if issue.date_closed:
-                        date_close = datetime.strptime(issue.date_closed, "%Y-%m-%d %H:%M:%S")
-                        date_until = issue.date_closed
-                        ans = date_close - date_create
-                        #Calculating no. of working hours to close the issue
-                        hours = cal_obj._interval_hours_get(cr, uid, working_hours,
-                                                           date_create,
-                                                           date_close,
-                                                           timezone_from_uid=issue.user_id.id or uid,
-                                                           exclude_leaves=False,
-                                                           context=context)
-                elif field in ['days_since_creation']:
-                    if issue.create_date:
-                        days_since_creation = datetime.today() - datetime.strptime(issue.create_date, "%Y-%m-%d %H:%M:%S")
-                        res[issue.id][field] = days_since_creation.days
-                    continue
-
-                elif field in ['inactivity_days']:
-                    res[issue.id][field] = 0
-                    if issue.date_action_last:
-                        inactive_days = datetime.today() - datetime.strptime(issue.date_action_last, '%Y-%m-%d %H:%M:%S')
-                        res[issue.id][field] = inactive_days.days
-                    continue
-                if ans:
-                    resource_id = False
-                    if issue.user_id:
-                        resource_ids = res_obj.search(cr, uid, [('user_id','=',issue.user_id.id)])
-                        if resource_ids and len(resource_ids):
-                            resource_id = resource_ids[0]
-                    duration = float(ans.days) + float(ans.seconds)/(24*3600)
-
-                if field in ['working_hours_open','working_hours_close']:
-                    res[issue.id][field] = hours
-                elif field in ['day_open','day_close']:
-                    res[issue.id][field] = duration
+                res[issue.id][field] = values[field]
 
         return res
 
@@ -230,11 +210,12 @@ class project_issue(osv.Model):
             if work.task_id:
                 issues += issue_pool.search(cr, uid, [('task_id','=',work.task_id.id)])
         return issues
+
     _columns = {
         'id': fields.integer('ID', readonly=True),
         'name': fields.char('Issue', required=True),
         'active': fields.boolean('Active', required=False),
-        'create_date': fields.datetime('Creation Date', readonly=True,select=True),
+        'create_date': fields.datetime('Creation Date', readonly=True, select=True),
         'write_date': fields.datetime('Update Date', readonly=True),
         'days_since_creation': fields.function(_compute_day, string='Days since creation date', \
                                                multi='compute_day', type="integer", help="Difference in days between creation date and current date"),
@@ -254,9 +235,9 @@ class project_issue(osv.Model):
                                          required=False),
         'email_from': fields.char('Email', size=128, help="These people will receive email.", select=1),
         'email_cc': fields.char('Watchers Emails', size=256, help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"),
-        'date_open': fields.datetime('Opened', readonly=True,select=True),
+        'date_open': fields.datetime('Assigned', readonly=True, select=True),
         # Project Issue fields
-        'date_closed': fields.datetime('Closed', readonly=True,select=True),
+        'date_closed': fields.datetime('Closed', readonly=True, select=True),
         'date': fields.datetime('Date'),
         'date_last_stage_update': fields.datetime('Last Stage Update', select=True),
         'channel': fields.char('Channel', help="Communication channel."),
@@ -269,17 +250,21 @@ class project_issue(osv.Model):
         'project_id': fields.many2one('project.project', 'Project', track_visibility='onchange', select=True),
         'duration': fields.float('Duration'),
         'task_id': fields.many2one('project.task', 'Task', domain="[('project_id','=',project_id)]"),
-        'day_open': fields.function(_compute_day, string='Days to Open', \
-                                multi='compute_day', type="float", store=True),
-        'day_close': fields.function(_compute_day, string='Days to Close', \
-                                multi='compute_day', type="float", store=True),
+        'day_open': fields.function(_compute_day, string='Days to Assign',
+                                    multi='compute_day', type="float",
+                                    store={'project.issue': (lambda self, cr, uid, ids, c={}: ids, ['date_open'], 10)}),
+        'day_close': fields.function(_compute_day, string='Days to Close',
+                                     multi='compute_day', type="float",
+                                     store={'project.issue': (lambda self, cr, uid, ids, c={}: ids, ['date_closed'], 10)}),
         'user_id': fields.many2one('res.users', 'Assigned to', required=False, select=1, track_visibility='onchange'),
-        'working_hours_open': fields.function(_compute_day, string='Working Hours to Open the Issue', \
-                                multi='compute_day', type="float", store=True),
-        'working_hours_close': fields.function(_compute_day, string='Working Hours to Close the Issue', \
-                                multi='compute_day', type="float", store=True),
-        'inactivity_days': fields.function(_compute_day, string='Days since last action', \
-                                multi='compute_day', type="integer", help="Difference in days between last action and current date"),
+        'working_hours_open': fields.function(_compute_day, string='Working Hours to assign the Issue',
+                                              multi='compute_day', type="float",
+                                              store={'project.issue': (lambda self, cr, uid, ids, c={}: ids, ['date_open'], 10)}),
+        'working_hours_close': fields.function(_compute_day, string='Working Hours to close the Issue',
+                                               multi='compute_day', type="float",
+                                               store={'project.issue': (lambda self, cr, uid, ids, c={}: ids, ['date_closed'], 10)}),
+        'inactivity_days': fields.function(_compute_day, string='Days since last action',
+                                           multi='compute_day', type="integer", help="Difference in days between last action and current date"),
         'color': fields.integer('Color Index'),
         'user_email': fields.related('user_id', 'email', type='char', string='User Email', readonly=True),
         'date_action_last': fields.datetime('Last Action', readonly=1),
@@ -312,13 +297,16 @@ class project_issue(osv.Model):
             default = {}
         default = default.copy()
         default.update(name=_('%s (copy)') % (issue['name']))
-        return super(project_issue, self).copy(cr, uid, id, default=default,
-                context=context)
+        return super(project_issue, self).copy(cr, uid, id, default=default, context=context)
 
     def create(self, cr, uid, vals, context=None):
         context = dict(context or {})
         if vals.get('project_id') and not context.get('default_project_id'):
             context['default_project_id'] = vals.get('project_id')
+        if vals.get('user_id'):
+            vals['date_open'] = fields.datetime.now()
+        if 'stage_id' in vals:
+            vals.update(self.onchange_stage_id(cr, uid, None, vals.get('stage_id'), context=context)['value'])
 
         # context: no_log, because subtype already handle this
         create_context = dict(context, mail_create_nolog=True)
@@ -327,12 +315,13 @@ class project_issue(osv.Model):
     def write(self, cr, uid, ids, vals, context=None):
         # stage change: update date_last_stage_update
         if 'stage_id' in vals:
+            vals.update(self.onchange_stage_id(cr, uid, ids, vals.get('stage_id'), context=context)['value'])
             vals['date_last_stage_update'] = fields.datetime.now()
             if 'kanban_state' not in vals:
                 vals['kanban_state'] = 'normal'
         # user_id change: update date_start
         if vals.get('user_id'):
-            vals['date_start'] = fields.datetime.now()
+            vals['date_open'] = fields.datetime.now()
 
         return super(project_issue, self).write(cr, uid, ids, vals, context)
 
@@ -363,6 +352,14 @@ class project_issue(osv.Model):
     # Stage management
     # -------------------------------------------------------
 
+    def onchange_stage_id(self, cr, uid, ids, stage_id, context=None):
+        if not stage_id:
+            return {'value': {}}
+        stage = self.pool['project.task.type'].browse(cr, uid, stage_id, context=context)
+        if stage.fold:
+            return {'value': {'date_closed': fields.datetime.now()}}
+        return {'value': {'date_closed': False}}
+
     def stage_find(self, cr, uid, cases, section_id, domain=[], order='sequence', context=None):
         """ Override of the base.stage method
             Parameter of the stage search taken from the issue:
diff --git a/addons/project_issue/project_issue_view.xml b/addons/project_issue/project_issue_view.xml
index 502598193a637e7b3c2b745115b32d28e211f59c..620c612ecf15bbc699c0e7d1aae8bc39bfd802d7 100644
--- a/addons/project_issue/project_issue_view.xml
+++ b/addons/project_issue/project_issue_view.xml
@@ -90,16 +90,18 @@
                             <field name="description" placeholder="Add an internal note..." groups="base.group_user"/>
                         </page>
                         <page string="Extra Info" groups="project.group_project_manager,project.group_project_user">
-                            <group string="Statistics">
-                                <field name="day_open"/>
-                                <field name="day_close"/>
-                                <field name="working_hours_open" widget="float_time"/>
-                                <field name="working_hours_close" widget="float_time"/>
-                                <field name="inactivity_days"/>
-                                <field name="days_since_creation"/>
-                            </group>
-                            <group string="Status" groups="base.group_no_one">
-                                <field name="active"/>
+                            <group>
+                                <group string="Statistics">
+                                    <field name="day_open"/>
+                                    <field name="day_close"/>
+                                    <field name="working_hours_open" widget="float_time"/>
+                                    <field name="working_hours_close" widget="float_time"/>
+                                    <field name="inactivity_days"/>
+                                    <field name="days_since_creation"/>
+                                </group>
+                                <group string="Status" groups="base.group_no_one">
+                                    <field name="active"/>
+                                </group>
                             </group>
                         </page>
                     </notebook>
diff --git a/addons/project_issue/report/project_issue_report_view.xml b/addons/project_issue/report/project_issue_report_view.xml
index 3382c6e36255869ae587843051343cb3b4f0b3e8..6747387513414ff730c0aeba20982c85eaeaca43 100644
--- a/addons/project_issue/report/project_issue_report_view.xml
+++ b/addons/project_issue/report/project_issue_report_view.xml
@@ -21,13 +21,6 @@
             <field name="user_id" eval="False"/>
             <field name="context">{'group_by': ['project_id', 'user_id']}</field>
         </record>
-        <record id="filter_issue_report_reviewer" model="ir.filters">
-            <field name="name">By Reviewer</field>
-            <field name="model_id">project.issue.report</field>
-            <field name="domain">[]</field>
-            <field name="user_id" eval="False"/>
-            <field name="context">{'group_by': ['project_id', 'reviewer_id']}</field>
-        </record>
 
         <record id="view_project_issue_report_filter" model="ir.ui.view">
             <field name="name">project.issue.report.select</field>
diff --git a/addons/purchase/purchase_view.xml b/addons/purchase/purchase_view.xml
index 8402f9965f5a652a27627124b3e3004ed604f75c..9228e71e1316822a79e272e36c671a9361207781 100644
--- a/addons/purchase/purchase_view.xml
+++ b/addons/purchase/purchase_view.xml
@@ -587,7 +587,7 @@
             <field name="arch" type="xml">
                 <div name="options" position="inside">
                     <div>
-                        <field name="purchase_ok" attrs="{'readonly': [('is_product_variant', '=', False)]}"/>
+                        <field name="purchase_ok"/>
                         <label for="purchase_ok"/>
                     </div>
                 </div>
diff --git a/addons/resource/resource.py b/addons/resource/resource.py
index 5a43234ac46ed7ba2286014ab0e2845e358e3c27..b16fd2105933bb5d48a342c680349f466584c942 100644
--- a/addons/resource/resource.py
+++ b/addons/resource/resource.py
@@ -329,7 +329,8 @@ class resource_calendar(osv.osv):
         # no calendar: try to use the default_interval, then return directly
         if id is None:
             if default_interval:
-                intervals.append((start_dt.replace(hour=default_interval[0]), start_dt.replace(hour=default_interval[1])))
+                working_interval = (start_dt.replace(hour=default_interval[0], minute=0, second=0), start_dt.replace(hour=default_interval[1], minute=0, second=0))
+            intervals = self.interval_remove_leaves(working_interval, work_limits)
             return intervals
 
         working_intervals = []
@@ -371,10 +372,16 @@ class resource_calendar(osv.osv):
                           resource_id=None, default_interval=None, context=None):
         hours = 0.0
         for day in rrule.rrule(rrule.DAILY, dtstart=start_dt,
-                               until=end_dt + datetime.timedelta(days=1),
+                               until=(end_dt + datetime.timedelta(days=1)).replace(hour=0, minute=0, second=0),
                                byweekday=self.get_weekdays(cr, uid, id, context=context)):
+            day_start_dt = day.replace(hour=0, minute=0, second=0)
+            if start_dt and day.date() == start_dt.date():
+                day_start_dt = start_dt
+            day_end_dt = day.replace(hour=23, minute=59, second=59)
+            if end_dt and day.date() == end_dt.date():
+                day_end_dt = end_dt
             hours += self.get_working_hours_of_date(
-                cr, uid, id, start_dt=day,
+                cr, uid, id, start_dt=day_start_dt, end_dt=day_end_dt,
                 compute_leaves=compute_leaves, resource_id=resource_id,
                 default_interval=default_interval,
                 context=context)
diff --git a/addons/stock/stock.py b/addons/stock/stock.py
index 42dad7d1062b4877942bdd2d2bfb06e66b94bb31..818b3ebe1afe1bc4952c978751e87eb8dde0d2d9 100644
--- a/addons/stock/stock.py
+++ b/addons/stock/stock.py
@@ -2598,7 +2598,7 @@ class stock_inventory(osv.osv):
             domain += ' and lot_id = %s'
             args += (inventory.lot_id.id,)
         if inventory.product_id:
-            domain += 'and product_id = %s'
+            domain += ' and product_id = %s'
             args += (inventory.product_id.id,)
         if inventory.package_id:
             domain += ' and package_id = %s'
diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js
index 566179c2a3861223076e695906229102d1279a46..7ed70f7bc6854397e95a41d547756d67f63b9ef1 100644
--- a/addons/web/static/src/js/search.js
+++ b/addons/web/static/src/js/search.js
@@ -1963,7 +1963,7 @@ instance.web.search.Advanced = instance.web.search.Input.extend({
                     context: this.view.dataset.context
                 }).done(function(data) {
                     self.fields = {
-                        id: { string: 'ID', type: 'id' }
+                        id: { string: 'ID', type: 'id', searchable: true }
                     };
                     _.each(data, function(field_def, field_name) {
                         if (field_def.selectable !== false && field_name != 'id') {
@@ -2037,7 +2037,7 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @
         this._super(parent);
         this.fields = _(fields).chain()
             .map(function(val, key) { return _.extend({}, val, {'name': key}); })
-            .filter(function (field) { return !field.deprecated && (field.store === void 0 || field.store || field.fnct_search); })
+            .filter(function (field) { return !field.deprecated && field.searchable; })
             .sortBy(function(field) {return field.string;})
             .value();
         this.attrs = {_: _, fields: this.fields, selected: null};
diff --git a/addons/web/static/test/search.js b/addons/web/static/test/search.js
index d93cb131e0592665af2c69af867e906694b7f790..828347b68a55412641b21004048881fd3d237d7b 100644
--- a/addons/web/static/test/search.js
+++ b/addons/web/static/test/search.js
@@ -157,7 +157,7 @@ var makeSearchView = function (instance, dummy_widget_attributes, defaults) {
             return {
                 type: 'search',
                 fields: {
-                    dummy: {type: 'char', string: "Dummy"}
+                    dummy: {type: 'char', string: "Dummy", searchable: true}
                 },
                 arch: '<search><field name="dummy" widget="dummy"/></search>'
             };
@@ -168,7 +168,7 @@ var makeSearchView = function (instance, dummy_widget_attributes, defaults) {
     };
     instance.session.responses['dummy.model:fields_get'] = function () {
         return {
-            dummy: {type: 'char', string: 'Dummy'}
+            dummy: {type: 'char', string: 'Dummy', searchable: true}
         };
     };
     instance.client = { action_manager: { inner_action: undefined } };
diff --git a/addons/web_kanban/static/src/xml/web_kanban.xml b/addons/web_kanban/static/src/xml/web_kanban.xml
index c1d504e51be69a40fe5fc9980e53eea824608d83..aebdbacb9dda838bc560788994b35b584e07346b 100644
--- a/addons/web_kanban/static/src/xml/web_kanban.xml
+++ b/addons/web_kanban/static/src/xml/web_kanban.xml
@@ -45,8 +45,8 @@
                     <ul class="oe_dropdown_menu oe_kanban_group_dropdown">
                         <li><a data-action="toggle_fold" href="#">Fold</a></li>
                         <t t-if="widget.view.grouped_by_m2o and widget.value">
-                            <li t-if="parent.is_action_enabled('group_edit')"><a data-action="edit" href="#">Edit</a></li>
-                            <li t-if="parent.is_action_enabled('group_delete')"><a data-action="delete" href="#">Delete</a></li>
+                            <li t-if="parent &amp;&amp; parent.is_action_enabled('group_edit')"><a data-action="edit" href="#">Edit</a></li>
+                            <li t-if="parent &amp;&amp; parent.is_action_enabled('group_delete')"><a data-action="delete" href="#">Delete</a></li>
                         </t>
                     </ul>
                 </div>
diff --git a/addons/website_livechat/website_livechat_data.xml b/addons/website_livechat/website_livechat_data.xml
index 55c59895664de1e365ddd5e69a84478873b853c1..5e37397c471f46ee95b31b628dc3d7c45f2837e4 100644
--- a/addons/website_livechat/website_livechat_data.xml
+++ b/addons/website_livechat/website_livechat_data.xml
@@ -2,8 +2,13 @@
  <openerp>
      <data noupdate="1">
 
+         <record id="channel_website" model="im_livechat.channel">
+             <field name="name">YourWebsiteWithOdoo.com</field>
+             <field name="default_message">Hello, how may I help you?</field>
+         </record>
+
          <record id="website.default_website" model="website">
-             <field name="channel_id" ref="im_livechat.channel_website"></field>
+             <field name="channel_id" ref="website_livechat.channel_website"></field>
          </record>
 
      </data>
diff --git a/addons/website_sale_options/models/sale_order.py b/addons/website_sale_options/models/sale_order.py
index f16feaecc7b7319dfadc7ecc370d08c9fb4e9f08..85eaab214f7003cdb9f2df7341c670ac48613980 100644
--- a/addons/website_sale_options/models/sale_order.py
+++ b/addons/website_sale_options/models/sale_order.py
@@ -45,7 +45,7 @@ class sale_order(osv.Model):
                 line.write({
                         "name": _("%s\nOption for: %s") % (line.name, linked.product_id.name_get()[0][1]),
                         "linked_line_id": linked_line_id
-                    }, context=context)
+                    })
 
             # select linked product
             option_ids = [l.id for l in so.order_line if l.linked_line_id.id == line.id]
diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py
index f1ddf4f1b427633b78d718756b3286846a7cd4c7..7102c009264701ddd0569ee3459e57d6aeea2520 100644
--- a/openerp/addons/base/res/res_users.py
+++ b/openerp/addons/base/res/res_users.py
@@ -22,6 +22,7 @@
 import itertools
 import logging
 from functools import partial
+from itertools import repeat
 
 from lxml import etree
 from lxml.builder import E
@@ -650,25 +651,30 @@ class users_implied(osv.osv):
 # Naming conventions for reified groups fields:
 # - boolean field 'in_group_ID' is True iff
 #       ID is in 'groups_id'
-# - boolean field 'in_groups_ID1_..._IDk' is True iff
-#       any of ID1, ..., IDk is in 'groups_id'
 # - selection field 'sel_groups_ID1_..._IDk' is ID iff
 #       ID is in 'groups_id' and ID is maximal in the set {ID1, ..., IDk}
 #----------------------------------------------------------
 
-def name_boolean_group(id): return 'in_group_' + str(id)
-def name_boolean_groups(ids): return 'in_groups_' + '_'.join(map(str, ids))
-def name_selection_groups(ids): return 'sel_groups_' + '_'.join(map(str, ids))
+def name_boolean_group(id):
+    return 'in_group_' + str(id)
+
+def name_selection_groups(ids):
+    return 'sel_groups_' + '_'.join(map(str, ids))
+
+def is_boolean_group(name):
+    return name.startswith('in_group_')
+
+def is_selection_groups(name):
+    return name.startswith('sel_groups_')
 
-def is_boolean_group(name): return name.startswith('in_group_')
-def is_boolean_groups(name): return name.startswith('in_groups_')
-def is_selection_groups(name): return name.startswith('sel_groups_')
 def is_reified_group(name):
-    return is_boolean_group(name) or is_boolean_groups(name) or is_selection_groups(name)
+    return is_boolean_group(name) or is_selection_groups(name)
 
-def get_boolean_group(name): return int(name[9:])
-def get_boolean_groups(name): return map(int, name[10:].split('_'))
-def get_selection_groups(name): return map(int, name[11:].split('_'))
+def get_boolean_group(name):
+    return int(name[9:])
+
+def get_selection_groups(name):
+    return map(int, name[11:].split('_'))
 
 def partition(f, xs):
     "return a pair equivalent to (filter(f, xs), filter(lambda x: not f(x), xs))"
@@ -789,45 +795,39 @@ class users_view(osv.osv):
     _inherit = 'res.users'
 
     def create(self, cr, uid, values, context=None):
-        self._set_reified_groups(values)
+        values = self._remove_reified_groups(values)
         return super(users_view, self).create(cr, uid, values, context)
 
     def write(self, cr, uid, ids, values, context=None):
-        self._set_reified_groups(values)
+        values = self._remove_reified_groups(values)
         return super(users_view, self).write(cr, uid, ids, values, context)
 
-    def _set_reified_groups(self, values):
-        """ reflect reified group fields in values['groups_id'] """
-        if 'groups_id' in values:
-            # groups are already given, ignore group fields
-            for f in filter(is_reified_group, values.iterkeys()):
-                del values[f]
-            return
+    def _remove_reified_groups(self, values):
+        """ return `values` without reified group fields """
+        add, rem = [], []
+        values1 = {}
+
+        for key, val in values.iteritems():
+            if is_boolean_group(key):
+                (add if val else rem).append(get_boolean_group(key))
+            elif is_selection_groups(key):
+                rem += get_selection_groups(key)
+                if val:
+                    add.append(val)
+            else:
+                values1[key] = val
 
-        add, remove = [], []
-        for f in values.keys():
-            if is_boolean_group(f):
-                target = add if values.pop(f) else remove
-                target.append(get_boolean_group(f))
-            elif is_boolean_groups(f):
-                if not values.pop(f):
-                    remove.extend(get_boolean_groups(f))
-            elif is_selection_groups(f):
-                remove.extend(get_selection_groups(f))
-                selected = values.pop(f)
-                if selected:
-                    add.append(selected)
-        # update values *only* if groups are being modified, otherwise
-        # we introduce spurious changes that might break the super.write() call.
-        if add or remove:
-            # remove groups in 'remove' and add groups in 'add'
-            values['groups_id'] = [(3, id) for id in remove] + [(4, id) for id in add]
+        if 'groups_id' not in values and (add or rem):
+            # remove group ids in `rem` and add group ids in `add`
+            values1['groups_id'] = zip(repeat(3), rem) + zip(repeat(4), add)
+
+        return values1
 
     def default_get(self, cr, uid, fields, context=None):
         group_fields, fields = partition(is_reified_group, fields)
         fields1 = (fields + ['groups_id']) if group_fields else fields
         values = super(users_view, self).default_get(cr, uid, fields1, context)
-        self._get_reified_groups(group_fields, values)
+        self._add_reified_groups(group_fields, values)
 
         # add "default_groups_ref" inside the context to set default value for group_id with xml values
         if 'groups_id' in fields and isinstance(context.get("default_groups_ref"), list):
@@ -846,29 +846,35 @@ class users_view(osv.osv):
         return values
 
     def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
-        fields_get = fields if fields is not None else self.fields_get(cr, uid, context=context).keys()
-        group_fields, _ = partition(is_reified_group, fields_get)
+        # determine whether reified groups fields are required, and which ones
+        fields1 = fields or self.fields_get(cr, uid, context=context).keys()
+        group_fields, other_fields = partition(is_reified_group, fields1)
+
+        # read regular fields (other_fields); add 'groups_id' if necessary
+        drop_groups_id = False
+        if group_fields and fields:
+            if 'groups_id' not in other_fields:
+                other_fields.append('groups_id')
+                drop_groups_id = True
+        else:
+            other_fields = fields
 
-        inject_groups_id = group_fields and fields and 'groups_id' not in fields
-        if inject_groups_id:
-            fields.append('groups_id')
-        res = super(users_view, self).read(cr, uid, ids, fields, context=context, load=load)
+        res = super(users_view, self).read(cr, uid, ids, other_fields, context=context, load=load)
 
-        if res and group_fields:
+        # post-process result to add reified group fields
+        if group_fields:
             for values in (res if isinstance(res, list) else [res]):
-                self._get_reified_groups(group_fields, values)
-                if inject_groups_id:
+                self._add_reified_groups(group_fields, values)
+                if drop_groups_id:
                     values.pop('groups_id', None)
         return res
 
-    def _get_reified_groups(self, fields, values):
-        """ compute the given reified group fields from values['groups_id'] """
+    def _add_reified_groups(self, fields, values):
+        """ add the given reified group fields into `values` """
         gids = set(parse_m2m(values.get('groups_id') or []))
         for f in fields:
             if is_boolean_group(f):
                 values[f] = get_boolean_group(f) in gids
-            elif is_boolean_groups(f):
-                values[f] = not gids.isdisjoint(get_boolean_groups(f))
             elif is_selection_groups(f):
                 selected = [gid for gid in get_selection_groups(f) if gid in gids]
                 values[f] = selected and selected[-1] or False
@@ -915,29 +921,26 @@ class change_password_wizard(osv.TransientModel):
         'user_ids': fields.one2many('change.password.user', 'wizard_id', string='Users'),
     }
 
-    def default_get(self, cr, uid, fields, context=None):
-        if context == None:
+    def _default_user_ids(self, cr, uid, context=None):
+        if context is None:
             context = {}
-        user_ids = context.get('active_ids', [])
-        wiz_id = context.get('active_id', None)
-        res = []
-        users = self.pool.get('res.users').browse(cr, uid, user_ids, context=context)
-        for user in users:
-            res.append((0, 0, {
-                'wizard_id': wiz_id,
-                'user_id': user.id,
-                'user_login': user.login,
-            }))
-        return {'user_ids': res}
-
-    def change_password_button(self, cr, uid, id, context=None):
-        wizard = self.browse(cr, uid, id, context=context)[0]
+        user_model = self.pool['res.users']
+        user_ids = context.get('active_model') == 'res.users' and context.get('active_ids') or []
+        return [
+            (0, 0, {'user_id': user.id, 'user_login': user.login})
+            for user in user_model.browse(cr, uid, user_ids, context=context)
+        ]
+
+    _defaults = {
+        'user_ids': _default_user_ids,
+    }
+
+    def change_password_button(self, cr, uid, ids, context=None):
+        wizard = self.browse(cr, uid, ids, context=context)[0]
         need_reload = any(uid == user.user_id.id for user in wizard.user_ids)
-        line_ids = [user.id for user in wizard.user_ids]
 
+        line_ids = [user.id for user in wizard.user_ids]
         self.pool.get('change.password.user').change_password_button(cr, uid, line_ids, context=context)
-        # don't keep temporary password copies in the database longer than necessary
-        self.pool.get('change.password.user').write(cr, uid, line_ids, {'new_passwd': False}, context=context)
 
         if need_reload:
             return {
@@ -965,8 +968,10 @@ class change_password_user(osv.TransientModel):
     }
 
     def change_password_button(self, cr, uid, ids, context=None):
-        for user in self.browse(cr, uid, ids, context=context):
-            self.pool.get('res.users').write(cr, uid, user.user_id.id, {'password': user.new_passwd})
+        for line in self.browse(cr, uid, ids, context=context):
+            line.user_id.write({'password': line.new_passwd})
+        # don't keep temporary passwords in the database longer than necessary
+        self.write(cr, uid, ids, {'new_passwd': False}, context=context)
 
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/addons/test_inherit/models.py b/openerp/addons/test_inherit/models.py
index ebbe71e0521d1ac292eaefcceccc17fd94004159..f620dfe53a97fad252c12225e8f966bedcec51a7 100644
--- a/openerp/addons/test_inherit/models.py
+++ b/openerp/addons/test_inherit/models.py
@@ -7,6 +7,7 @@ class mother(models.Model):
 
     name = fields.Char('Name', required=True)
     surname = fields.Char(compute='_compute_surname')
+    state = fields.Selection([('a', 'A'), ('b', 'B')])
 
     @api.one
     @api.depends('name')
@@ -35,6 +36,9 @@ class mother(models.Model):
     # extend the name field by adding a default value
     name = fields.Char(default='Unknown')
 
+    # extend the selection of the state field
+    state = fields.Selection(selection_add=[('c', 'C')])
+
     # override the computed field, and extend its dependencies
     @api.one
     @api.depends('field_in_mother')
@@ -44,4 +48,11 @@ class mother(models.Model):
         else:
             super(mother, self)._compute_surname()
 
+
+class mother(models.Model):
+    _inherit = 'test.inherit.mother'
+
+    # extend again the selection of the state field
+    state = fields.Selection(selection_add=[('d', 'D')])
+
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/addons/test_inherit/tests/test_inherit.py b/openerp/addons/test_inherit/tests/test_inherit.py
index b663d911f60ec1646cfa6d5a3c009d5a2cc18918..8039e698669d4ad65957297a473718eebe9a4518 100644
--- a/openerp/addons/test_inherit/tests/test_inherit.py
+++ b/openerp/addons/test_inherit/tests/test_inherit.py
@@ -9,15 +9,15 @@ class test_inherits(common.TransactionCase):
         # is accessible from the child model. This test has been written
         # to verify the purpose of the inheritance computing of the class
         # in the openerp.osv.orm._build_model.
-        mother = self.registry('test.inherit.mother')
-        daugther = self.registry('test.inherit.daugther')
+        mother = self.env['test.inherit.mother']
+        daugther = self.env['test.inherit.daugther']
 
         self.assertIn('field_in_mother', mother._fields)
         self.assertIn('field_in_mother', daugther._fields)
 
     def test_field_extension(self):
         """ check the extension of a field in an inherited model """
-        mother = self.registry('test.inherit.mother')
+        mother = self.env['test.inherit.mother']
         field = mother._fields['name']
 
         # the field should inherit required=True, and have a default value
@@ -26,11 +26,19 @@ class test_inherits(common.TransactionCase):
 
     def test_depends_extension(self):
         """ check that @depends on overridden compute methods extends dependencies """
-        mother = self.registry('test.inherit.mother')
+        mother = self.env['test.inherit.mother']
         field = mother._fields['surname']
 
         # the field dependencies are added
         self.assertItemsEqual(field.depends, ['name', 'field_in_mother'])
 
+    def test_selection_extension(self):
+        """ check that attribute selection_add=... extends selection on fields. """
+        mother = self.env['test.inherit.mother']
+        field = mother._fields['state']
+
+        # the extra values are added
+        self.assertEqual(field.selection, [('a', 'A'), ('b', 'B'), ('c', 'C'), ('d', 'D')])
+
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/fields.py b/openerp/fields.py
index d85ce82eccb7457fd803d568554e49fc163b4622..1b3cdabe29c459dbd6cfa0735cf2a0cd141ad227 100644
--- a/openerp/fields.py
+++ b/openerp/fields.py
@@ -284,6 +284,8 @@ class Field(object):
     required = False
     states = None
     groups = False              # csv list of group xml ids
+    change_default = None       # whether the field may trigger a "user-onchange"
+    deprecated = None           # whether the field is ... deprecated
 
     def __init__(self, string=None, **kwargs):
         kwargs['string'] = string
@@ -408,7 +410,8 @@ class Field(object):
         self.depends = ('.'.join(self.related),)
         self.compute = self._compute_related
         self.inverse = self._inverse_related
-        self.search = self._search_related
+        if field._description_searchable(env):
+            self.search = self._search_related
 
         # copy attributes from field to self (string, help, etc.)
         for attr, prop in self.related_attrs:
@@ -417,9 +420,9 @@ class Field(object):
 
     def _compute_related(self, records):
         """ Compute the related field `self` on `records`. """
-        for record in records:
+        for record, sudo_record in zip(records, records.sudo()):
             # bypass access rights check when traversing the related path
-            value = record.sudo() if record.id else record
+            value = sudo_record if record.id else record
             # traverse the intermediate fields, and keep at most one record
             for name in self.related[:-1]:
                 value = value[name][:1]
@@ -524,23 +527,27 @@ class Field(object):
     def get_description(self, env):
         """ Return a dictionary that describes the field `self`. """
         desc = {'type': self.type}
-        # determine 'store'
-        if self.store:
-            # if the corresponding column is a function field, check the column
-            column = env[self.model_name]._columns.get(self.name)
-            desc['store'] = bool(getattr(column, 'store', True))
-        else:
-            desc['store'] = False
-        # determine other attributes
         for attr, prop in self.description_attrs:
             value = getattr(self, prop)
             if callable(value):
                 value = value(env)
-            if value:
+            if value is not None:
                 desc[attr] = value
+
         return desc
 
     # properties used by get_description()
+
+    def _description_store(self, env):
+        if self.store:
+            # if the corresponding column is a function field, check the column
+            column = env[self.model_name]._columns.get(self.name)
+            return bool(getattr(column, 'store', True))
+        return False
+
+    def _description_searchable(self, env):
+        return self._description_store(env) or bool(self.search)
+
     _description_depends = property(attrgetter('depends'))
     _description_related = property(attrgetter('related'))
     _description_company_dependent = property(attrgetter('company_dependent'))
@@ -548,6 +555,8 @@ class Field(object):
     _description_required = property(attrgetter('required'))
     _description_states = property(attrgetter('states'))
     _description_groups = property(attrgetter('groups'))
+    _description_change_default = property(attrgetter('change_default'))
+    _description_deprecated = property(attrgetter('deprecated'))
 
     def _description_string(self, env):
         if self.string and env.lang:
@@ -599,6 +608,8 @@ class Field(object):
     _column_required = property(attrgetter('required'))
     _column_states = property(attrgetter('states'))
     _column_groups = property(attrgetter('groups'))
+    _column_change_default = property(attrgetter('change_default'))
+    _column_deprecated = property(attrgetter('deprecated'))
 
     ############################################################################
     #
@@ -609,11 +620,13 @@ class Field(object):
         """ return the null value for this field in the given environment """
         return False
 
-    def convert_to_cache(self, value, env, validate=True):
+    def convert_to_cache(self, value, record, validate=True):
         """ convert `value` to the cache level in `env`; `value` may come from
             an assignment, or have the format of methods :meth:`BaseModel.read`
             or :meth:`BaseModel.write`
 
+            :param record: the target record for the assignment, or an empty recordset
+
             :param bool validate: when True, field-specific validation of
                 `value` will be performed
         """
@@ -698,7 +711,7 @@ class Field(object):
         record.ensure_one()
 
         # adapt value to the cache level
-        value = self.convert_to_cache(value, env)
+        value = self.convert_to_cache(value, record)
 
         if env.in_draft or not record.id:
             # determine dependent fields
@@ -861,7 +874,7 @@ class Boolean(Field):
     """ Boolean field. """
     type = 'boolean'
 
-    def convert_to_cache(self, value, env, validate=True):
+    def convert_to_cache(self, value, record, validate=True):
         return bool(value)
 
     def convert_to_export(self, value, env):
@@ -874,7 +887,7 @@ class Integer(Field):
     """ Integer field. """
     type = 'integer'
 
-    def convert_to_cache(self, value, env, validate=True):
+    def convert_to_cache(self, value, record, validate=True):
         return int(value or 0)
 
     def convert_to_read(self, value, use_name_get=True):
@@ -914,7 +927,7 @@ class Float(Field):
     _column_digits = property(lambda self: not callable(self._digits) and self._digits)
     _column_digits_compute = property(lambda self: callable(self._digits) and self._digits)
 
-    def convert_to_cache(self, value, env, validate=True):
+    def convert_to_cache(self, value, record, validate=True):
         # apply rounding here, otherwise value in cache may be wrong!
         if self.digits:
             return float_round(float(value or 0.0), precision_digits=self.digits[1])
@@ -948,7 +961,7 @@ class Char(_String):
     _related_size = property(attrgetter('size'))
     _description_size = property(attrgetter('size'))
 
-    def convert_to_cache(self, value, env, validate=True):
+    def convert_to_cache(self, value, record, validate=True):
         return bool(value) and ustr(value)[:self.size]
 
 
@@ -962,7 +975,7 @@ class Text(_String):
     """
     type = 'text'
 
-    def convert_to_cache(self, value, env, validate=True):
+    def convert_to_cache(self, value, record, validate=True):
         return bool(value) and ustr(value)
 
 
@@ -970,7 +983,7 @@ class Html(_String):
     """ Html field. """
     type = 'html'
 
-    def convert_to_cache(self, value, env, validate=True):
+    def convert_to_cache(self, value, record, validate=True):
         return bool(value) and html_sanitize(value)
 
 
@@ -1019,7 +1032,7 @@ class Date(Field):
         """ Convert a :class:`date` value into the format expected by the ORM. """
         return value.strftime(DATE_FORMAT)
 
-    def convert_to_cache(self, value, env, validate=True):
+    def convert_to_cache(self, value, record, validate=True):
         if not value:
             return False
         if isinstance(value, basestring):
@@ -1084,7 +1097,7 @@ class Datetime(Field):
         """ Convert a :class:`datetime` value into the format expected by the ORM. """
         return value.strftime(DATETIME_FORMAT)
 
-    def convert_to_cache(self, value, env, validate=True):
+    def convert_to_cache(self, value, record, validate=True):
         if not value:
             return False
         if isinstance(value, basestring):
@@ -1109,12 +1122,16 @@ class Selection(Field):
             It is given as either a list of pairs (`value`, `string`), or a
             model method, or a method name.
 
+        :param selection_add: provides an extension of the selection in the case
+            of an overridden field. It is a list of pairs (`value`, `string`).
+
         The attribute `selection` is mandatory except in the case of related
         fields (see :ref:`field-related`) or field extensions
         (see :ref:`field-incremental-definition`).
     """
     type = 'selection'
-    selection = None        # [(value, string), ...], model method or method name
+    selection = None        # [(value, string), ...], function or method name
+    selection_add = None    # [(value, string), ...]
 
     def __init__(self, selection=None, string=None, **kwargs):
         if callable(selection):
@@ -1128,6 +1145,23 @@ class Selection(Field):
         field = self.related_field
         self.selection = lambda model: field._description_selection(model.env)
 
+    def _setup_regular(self, env):
+        super(Selection, self)._setup_regular(env)
+        # determine selection (applying extensions)
+        cls = type(env[self.model_name])
+        selection = None
+        for field in resolve_all_mro(cls, self.name, reverse=True):
+            if isinstance(field, type(self)):
+                # We cannot use field.selection or field.selection_add here
+                # because those attributes are overridden by `set_class_name`.
+                if 'selection' in field._attrs:
+                    selection = field._attrs['selection']
+                if 'selection_add' in field._attrs:
+                    selection = selection + field._attrs['selection_add']
+            else:
+                selection = None
+        self.selection = selection
+
     def _description_selection(self, env):
         """ return the selection list (pairs (value, label)); labels are
             translated according to context language
@@ -1164,10 +1198,10 @@ class Selection(Field):
             selection = selection(env[self.model_name])
         return [value for value, _ in selection]
 
-    def convert_to_cache(self, value, env, validate=True):
+    def convert_to_cache(self, value, record, validate=True):
         if not validate:
             return value or False
-        if value in self.get_values(env):
+        if value in self.get_values(record.env):
             return value
         elif not value:
             return False
@@ -1204,14 +1238,14 @@ class Reference(Selection):
 
     _column_size = property(attrgetter('size'))
 
-    def convert_to_cache(self, value, env, validate=True):
+    def convert_to_cache(self, value, record, validate=True):
         if isinstance(value, BaseModel):
-            if ((not validate or value._name in self.get_values(env))
+            if ((not validate or value._name in self.get_values(record.env))
                     and len(value) <= 1):
-                return value.with_env(env) or False
+                return value.with_env(record.env) or False
         elif isinstance(value, basestring):
             res_model, res_id = value.split(',')
-            return env[res_model].browse(int(res_id))
+            return record.env[res_model].browse(int(res_id))
         elif not value:
             return False
         raise ValueError("Wrong value for %s: %r" % (self, value))
@@ -1302,19 +1336,19 @@ class Many2one(_Relational):
         """ Update the cached value of `self` for `records` with `value`. """
         records._cache[self] = value
 
-    def convert_to_cache(self, value, env, validate=True):
+    def convert_to_cache(self, value, record, validate=True):
         if isinstance(value, (NoneType, int)):
-            return env[self.comodel_name].browse(value)
+            return record.env[self.comodel_name].browse(value)
         if isinstance(value, BaseModel):
             if value._name == self.comodel_name and len(value) <= 1:
-                return value.with_env(env)
+                return value.with_env(record.env)
             raise ValueError("Wrong value for %s: %r" % (self, value))
         elif isinstance(value, tuple):
-            return env[self.comodel_name].browse(value[0])
+            return record.env[self.comodel_name].browse(value[0])
         elif isinstance(value, dict):
-            return env[self.comodel_name].new(value)
+            return record.env[self.comodel_name].new(value)
         else:
-            return env[self.comodel_name].browse(value)
+            return record.env[self.comodel_name].browse(value)
 
     def convert_to_read(self, value, use_name_get=True):
         if use_name_get and value:
@@ -1355,27 +1389,30 @@ class _RelationalMulti(_Relational):
         for record in records:
             record._cache[self] = record[self.name] | value
 
-    def convert_to_cache(self, value, env, validate=True):
+    def convert_to_cache(self, value, record, validate=True):
         if isinstance(value, BaseModel):
             if value._name == self.comodel_name:
-                return value.with_env(env)
+                return value.with_env(record.env)
         elif isinstance(value, list):
             # value is a list of record ids or commands
-            result = env[self.comodel_name]
+            if not record.id:
+                record = record.browse()        # new record has no value
+            result = record[self.name]
+            # modify result with the commands;
+            # beware to not introduce duplicates in result
             for command in value:
                 if isinstance(command, (tuple, list)):
                     if command[0] == 0:
                         result += result.new(command[2])
                     elif command[0] == 1:
-                        record = result.browse(command[1])
-                        record.update(command[2])
-                        result += record
+                        result.browse(command[1]).update(command[2])
                     elif command[0] == 2:
-                        pass
+                        # note: the record will be deleted by write()
+                        result -= result.browse(command[1])
                     elif command[0] == 3:
-                        pass
+                        result -= result.browse(command[1])
                     elif command[0] == 4:
-                        result += result.browse(command[1])
+                        result += result.browse(command[1]) - result
                     elif command[0] == 5:
                         result = result.browse()
                     elif command[0] == 6:
@@ -1383,10 +1420,10 @@ class _RelationalMulti(_Relational):
                 elif isinstance(command, dict):
                     result += result.new(command)
                 else:
-                    result += result.browse(command)
+                    result += result.browse(command) - result
             return result
         elif not value:
-            return self.null(env)
+            return self.null(record.env)
         raise ValueError("Wrong value for %s: %s" % (self, value))
 
     def convert_to_read(self, value, use_name_get=True):
diff --git a/openerp/models.py b/openerp/models.py
index af55db1f1cbbf825668cfe4e8770869cecb9f84a..8beb60d53b7129aac29e692f36f9e7ccd9d80cab 100644
--- a/openerp/models.py
+++ b/openerp/models.py
@@ -841,10 +841,10 @@ class BaseModel(object):
         ir_model_data = self.sudo().env['ir.model.data']
         data = ir_model_data.search([('model', '=', self._name), ('res_id', '=', self.id)])
         if data:
-            if data.module:
-                return '%s.%s' % (data.module, data.name)
+            if data[0].module:
+                return '%s.%s' % (data[0].module, data[0].name)
             else:
-                return data.name
+                return data[0].name
         else:
             postfix = 0
             name = '%s_%s' % (self._table, self.id)
@@ -1729,12 +1729,7 @@ class BaseModel(object):
             :rtype: list
             :return: list of pairs ``(id, text_repr)`` for all matching records.
         """
-        args = list(args or [])
-        if not self._rec_name:
-            _logger.warning("Cannot execute name_search, no _rec_name defined on %s", self._name)
-        elif not (name == '' and operator == 'ilike'):
-            args += [(self._rec_name, operator, name)]
-        return self.search(args, limit=limit).name_get()
+        return self._name_search(name, args, operator, limit=limit)
 
     def _name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=100, name_get_uid=None):
         # private implementation of name_search, allows passing a dedicated user
@@ -2621,7 +2616,7 @@ class BaseModel(object):
 
                             if isinstance(f, fields.many2one) or (isinstance(f, fields.function) and f._type == 'many2one' and f.store):
                                 dest_model = self.pool[f._obj]
-                                if dest_model._table != 'ir_actions':
+                                if dest_model._auto and dest_model._table != 'ir_actions':
                                     self._m2o_fix_foreign_key(cr, self._table, k, dest_model, f.ondelete)
 
                     # The field doesn't exist in database. Create it if necessary.
@@ -3627,7 +3622,8 @@ class BaseModel(object):
 
         # put the values of pure new-style fields into cache, and inverse them
         if new_vals:
-            self._cache.update(self._convert_to_cache(new_vals))
+            for record in self:
+                record._cache.update(record._convert_to_cache(new_vals, update=True))
             for key in new_vals:
                 self._fields[key].determine_inverse(self)
 
@@ -4973,9 +4969,10 @@ class BaseModel(object):
         """ stuff to do right after the registry is built """
         pass
 
-    def _patch_method(self, name, method):
+    @classmethod
+    def _patch_method(cls, name, method):
         """ Monkey-patch a method for all instances of this model. This replaces
-            the method called `name` by `method` in `self`'s class.
+            the method called `name` by `method` in the given class.
             The original method is then accessible via ``method.origin``, and it
             can be restored with :meth:`~._revert_method`.
 
@@ -4996,7 +4993,6 @@ class BaseModel(object):
                 # restore the original method
                 model._revert_method('write')
         """
-        cls = type(self)
         origin = getattr(cls, name)
         method.origin = origin
         # propagate decorators from origin to method, and apply api decorator
@@ -5004,11 +5000,11 @@ class BaseModel(object):
         wrapped.origin = origin
         setattr(cls, name, wrapped)
 
-    def _revert_method(self, name):
-        """ Revert the original method of `self` called `name`.
+    @classmethod
+    def _revert_method(cls, name):
+        """ Revert the original method called `name` in the given class.
             See :meth:`~._patch_method`.
         """
-        cls = type(self)
         method = getattr(cls, name)
         setattr(cls, name, method.origin)
 
@@ -5098,11 +5094,17 @@ class BaseModel(object):
         context = dict(args[0] if args else self._context, **kwargs)
         return self.with_env(self.env(context=context))
 
-    def _convert_to_cache(self, values, validate=True):
-        """ Convert the `values` dictionary into cached values. """
+    def _convert_to_cache(self, values, update=False, validate=True):
+        """ Convert the `values` dictionary into cached values.
+
+            :param update: whether the conversion is made for updating `self`;
+                this is necessary for interpreting the commands of *2many fields
+            :param validate: whether values must be checked
+        """
         fields = self._fields
+        target = self if update else self.browse()
         return {
-            name: fields[name].convert_to_cache(value, self.env, validate=validate)
+            name: fields[name].convert_to_cache(value, target, validate=validate)
             for name, value in values.iteritems()
             if name in fields
         }
@@ -5191,7 +5193,7 @@ class BaseModel(object):
             exist in the database.
         """
         record = self.browse([NewId()])
-        record._cache.update(self._convert_to_cache(values))
+        record._cache.update(record._convert_to_cache(values, update=True))
 
         if record.env.in_onchange:
             # The cache update does not set inverse fields, so do it manually.
diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py
index e00204caf9e79d5d3cc259e5bc097eaa3072fa27..2d9c38bbd4a050a634c43de1f6208bc1f3cc1bcf 100644
--- a/openerp/osv/fields.py
+++ b/openerp/osv/fields.py
@@ -146,8 +146,10 @@ class _column(object):
             ('translate', self.translate),
             ('domain', self._domain),
             ('context', self._context),
+            ('change_default', self.change_default),
+            ('deprecated', self.deprecated),
         ]
-        return dict(item for item in items if items[1])
+        return dict(item for item in items if item[1])
 
     def restart(self):
         pass