From: Denis Ledoux Date: Tue, 25 Mar 2014 11:24:13 +0000 (+0100) Subject: [MERGE] Forward-port of latest 7.0 bugfixes, up to rev. 9929 revid:dle@openerp.com... X-Git-Tag: InsPy_master01~208^2~63^2~3 X-Git-Url: http://git.inspyration.org/?a=commitdiff_plain;h=02459f8d4a97ef8ee82464389b269fafac7fec21;p=odoo%2Fodoo.git [MERGE] Forward-port of latest 7.0 bugfixes, up to rev. 9929 revid:dle@openerp.com-20140325104921-x8zjx5p71l1o3uif bzr revid: dle@openerp.com-20140310133913-465x5t3n1bo7fu98 bzr revid: dle@openerp.com-20140311164146-2s599kogbqj8e94l bzr revid: dle@openerp.com-20140312111149-u6y036aej3ywq7et bzr revid: dle@openerp.com-20140312121145-06s1jvct9v4m7l6s bzr revid: mat@openerp.com-20140313084409-c0kckxemy3in0mlo bzr revid: chs@openerp.com-20140313163420-ifa4hyixj722d6jo bzr revid: chs@openerp.com-20140314102034-g0nzryvwhrpzdas9 bzr revid: chs@openerp.com-20140314104803-19c5snl2fcuih91o bzr revid: odo@openerp.com-20140314143519-x6rzcfkkqxwc0e1g bzr revid: chs@openerp.com-20140318110229-y8098w3shdpmoig2 bzr revid: dle@openerp.com-20140318151824-sscl4m8p87emjl8s bzr revid: dle@openerp.com-20140320112618-yfyihlwz66ryeqf5 bzr revid: dle@openerp.com-20140320161003-j01cc6sqves2wnp2 bzr revid: dle@openerp.com-20140320181252-4gqcog22p1ex0pz7 bzr revid: dle@openerp.com-20140321140450-8ulnhr76qybiadks bzr revid: dle@openerp.com-20140324104743-ubvu8st7emq9pg1q bzr revid: dle@openerp.com-20140325112413-xs5z7y81rhyjt0rd --- 02459f8d4a97ef8ee82464389b269fafac7fec21 diff --cc addons/account/account.py index c2c57c6,2910d3d..5930377 --- a/addons/account/account.py +++ b/addons/account/account.py @@@ -27,10 -27,10 +27,10 @@@ import tim import openerp from openerp import SUPERUSER_ID -from openerp import pooler, tools +from openerp import tools from openerp.osv import fields, osv, expression from openerp.tools.translate import _ - from openerp.tools.float_utils import float_round + from openerp.tools.float_utils import float_round as round import openerp.addons.decimal_precision as dp diff --cc addons/audittrail/audittrail.py index ca4a15b,b68a8e2..71008e0 --- a/addons/audittrail/audittrail.py +++ b/addons/audittrail/audittrail.py @@@ -349,188 -413,123 +349,190 @@@ def get_data(cr, uid, pool, res_ids, mo x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) x2m_model = pool.get('ir.model').browse(cr, SUPERUSER_ID, x2m_model_id) - # the resource_ids that need to be checked are the sum of both old and previous values (because we - # need to log also creation or deletion in those lists). - x2m_old_values_ids = old_values.get(key, {'value': {}})['value'].get(field_name, []) - x2m_new_values_ids = new_values.get(key, {'value': {}})['value'].get(field_name, []) - # We use list(set(...)) to remove duplicates. - res_ids = list(set(x2m_old_values_ids + x2m_new_values_ids)) + field_resource_ids = list(set(resource[field])) if model.model == x2m_model.model: # we need to remove current resource_id from the many2many to prevent an infinit loop - if resource_id in res_ids: - res_ids.remove(resource_id) - for res_id in res_ids: - lines.update(self.prepare_audittrail_log_line(cr, SUPERUSER_ID, pool, x2m_model, res_id, method, old_values, new_values, field_list)) - # if the value value is different than the old value: record the change - if key not in old_values or key not in new_values or old_values[key]['value'][field_name] != new_values[key]['value'][field_name]: - data = { - 'name': field_name, - 'new_value': key in new_values and new_values[key]['value'].get(field_name), - 'old_value': key in old_values and old_values[key]['value'].get(field_name), - 'new_value_text': key in new_values and new_values[key]['text'].get(field_name), - 'old_value_text': key in old_values and old_values[key]['text'].get(field_name) - } - lines[key].append(data) - return lines + if resource_id in field_resource_ids: + field_resource_ids.remove(resource_id) + data.update(get_data(cr, SUPERUSER_ID, pool, field_resource_ids, x2m_model, method)) - def process_data(self, cr, uid, pool, res_ids, model, method, old_values=None, new_values=None, field_list=None): - """ - This function processes and iterates recursively to log the difference between the old - data (i.e before the method was executed) and the new data and creates audittrail log - accordingly. + data[(model.id, resource_id)] = {'text':values_text, 'value': values} + return data - :param cr: the current row, from the database cursor, - :param uid: the current user’s ID, - :param pool: current db's pooler object. - :param res_ids: Id's of resource to be logged/compared. - :param model: model object which values are being changed - :param method: method to log: create, read, unlink, write, actions, workflow actions - :param old_values: dict of values read before execution of the method - :param new_values: dict of values read after execution of the method - :param field_list: optional argument containing the list of fields to log. Currently only - used when performing a read, it could be usefull later on if we want to log the write - on specific fields only. - :return: True - """ - if field_list is None: - field_list = [] - # loop on all the given ids - for res_id in res_ids: - # compare old and new values and get audittrail log lines accordingly - lines = self.prepare_audittrail_log_line(cr, uid, pool, model, res_id, method, old_values, new_values, field_list) - - # if at least one modification has been found - for model_id, resource_id in lines: - line_model = pool.get('ir.model').browse(cr, SUPERUSER_ID, model_id).model - - vals = { - 'method': method, - 'object_id': model_id, - 'user_id': uid, - 'res_id': resource_id, - } - if (model_id, resource_id) not in old_values and method not in ('copy', 'read'): - # the resource was not existing so we are forcing the method to 'create' - # (because it could also come with the value 'write' if we are creating - # new record through a one2many field) - vals.update({'method': 'create'}) - if (model_id, resource_id) not in new_values and method not in ('copy', 'read'): - # the resource is not existing anymore so we are forcing the method to 'unlink' - # (because it could also come with the value 'write' if we are deleting the - # record through a one2many field) - name = old_values[(model_id, resource_id)]['value'].get('name',False) - vals.update({'method': 'unlink'}) - else : - name = pool[line_model].name_get(cr, uid, [resource_id])[0][1] - vals.update({'name': name}) - # create the audittrail log in super admin mode, only if a change has been detected - if lines[(model_id, resource_id)]: - log_id = pool.get('audittrail.log').create(cr, SUPERUSER_ID, vals) - model = pool.get('ir.model').browse(cr, uid, model_id) - self.create_log_line(cr, SUPERUSER_ID, log_id, model, lines[(model_id, resource_id)]) - return True +def prepare_audittrail_log_line(cr, uid, pool, model, resource_id, method, old_values, new_values, field_list=None): + """ + This function compares the old data (i.e before the method was executed) and the new data + (after the method was executed) and returns a structure with all the needed information to + log those differences. + + :param cr: the current row, from the database cursor, + :param uid: the current user’s ID. This parameter is currently not used as every + operation to get data is made as super admin. Though, it could be usefull later. + :param pool: current db's pooler object. + :param model: model object which values are being changed + :param resource_id: ID of record to which values are being changed + :param method: method to log: create, read, unlink, write, actions, workflow actions + :param old_values: dict of values read before execution of the method + :param new_values: dict of values read after execution of the method + :param field_list: optional argument containing the list of fields to log. Currently only + used when performing a read, it could be usefull later on if we want to log the write + on specific fields only. + + :return: dictionary with + * keys: tuples build as ID of model object to log and ID of resource to log + * values: list of all the changes in field values for this couple (model, resource) + return { + (model.id, resource_id): [] + } + + The reason why the structure returned is build as above is because when modifying an existing + record, we may have to log a change done in a x2many field of that object + """ + if field_list is None: + field_list = [] + key = (model.id, resource_id) + lines = { + key: [] + } + # loop on all the fields + for field_name, field_definition in pool[model.model]._all_columns.items(): + if field_name in ('__last_update', 'id'): + continue + #if the field_list param is given, skip all the fields not in that list + if field_list and field_name not in field_list: + continue + field_obj = field_definition.column + if field_obj._type in ('one2many','many2many'): + # checking if an audittrail rule apply in super admin mode + if check_rules(cr, SUPERUSER_ID, field_obj._obj, method): + # checking if the model associated to a *2m field exists, in super admin mode + x2m_model_ids = pool.get('ir.model').search(cr, SUPERUSER_ID, [('model', '=', field_obj._obj)]) + x2m_model_id = x2m_model_ids and x2m_model_ids[0] or False + assert x2m_model_id, _("'%s' Model does not exist..." %(field_obj._obj)) + x2m_model = pool.get('ir.model').browse(cr, SUPERUSER_ID, x2m_model_id) + # the resource_ids that need to be checked are the sum of both old and previous values (because we + # need to log also creation or deletion in those lists). + x2m_old_values_ids = old_values.get(key, {'value': {}})['value'].get(field_name, []) + x2m_new_values_ids = new_values.get(key, {'value': {}})['value'].get(field_name, []) + # We use list(set(...)) to remove duplicates. + res_ids = list(set(x2m_old_values_ids + x2m_new_values_ids)) + if model.model == x2m_model.model: + # we need to remove current resource_id from the many2many to prevent an infinit loop + if resource_id in res_ids: + res_ids.remove(resource_id) + for res_id in res_ids: + lines.update(prepare_audittrail_log_line(cr, SUPERUSER_ID, pool, x2m_model, res_id, method, old_values, new_values, field_list)) + # if the value value is different than the old value: record the change + if key not in old_values or key not in new_values or old_values[key]['value'][field_name] != new_values[key]['value'][field_name]: + data = { + 'name': field_name, + 'new_value': key in new_values and new_values[key]['value'].get(field_name), + 'old_value': key in old_values and old_values[key]['value'].get(field_name), + 'new_value_text': key in new_values and new_values[key]['text'].get(field_name), + 'old_value_text': key in old_values and old_values[key]['text'].get(field_name) + } + lines[key].append(data) + return lines - def check_rules(self, cr, uid, model, method): - """ - Checks if auditrails is installed for that db and then if one rule match - @param cr: the current row, from the database cursor, - @param uid: the current user’s ID, - @param model: value of _name of the object which values are being changed - @param method: method to log: create, read, unlink,write,actions,workflow actions - @return: True or False - """ - pool = pooler.get_pool(cr.dbname) - if 'audittrail.rule' in pool.models: - model_ids = pool.get('ir.model').search(cr, SUPERUSER_ID, [('model', '=', model)]) - model_id = model_ids and model_ids[0] or False - if model_id: - rule_ids = pool.get('audittrail.rule').search(cr, SUPERUSER_ID, [('object_id', '=', model_id), ('state', '=', 'subscribed')]) - for rule in pool.get('audittrail.rule').read(cr, SUPERUSER_ID, rule_ids, ['user_id','log_read','log_write','log_create','log_unlink','log_action','log_workflow']): - if len(rule['user_id']) == 0 or uid in rule['user_id']: - if rule.get('log_'+method,0): +def process_data(cr, uid, pool, res_ids, model, method, old_values=None, new_values=None, field_list=None): + """ + This function processes and iterates recursively to log the difference between the old + data (i.e before the method was executed) and the new data and creates audittrail log + accordingly. + + :param cr: the current row, from the database cursor, + :param uid: the current user’s ID, + :param pool: current db's pooler object. + :param res_ids: Id's of resource to be logged/compared. + :param model: model object which values are being changed + :param method: method to log: create, read, unlink, write, actions, workflow actions + :param old_values: dict of values read before execution of the method + :param new_values: dict of values read after execution of the method + :param field_list: optional argument containing the list of fields to log. Currently only + used when performing a read, it could be usefull later on if we want to log the write + on specific fields only. + :return: True + """ + if field_list is None: + field_list = [] + # loop on all the given ids + for res_id in res_ids: + # compare old and new values and get audittrail log lines accordingly + lines = prepare_audittrail_log_line(cr, uid, pool, model, res_id, method, old_values, new_values, field_list) + + # if at least one modification has been found + for model_id, resource_id in lines: + line_model = pool.get('ir.model').browse(cr, SUPERUSER_ID, model_id).model - name = pool.get(line_model).name_get(cr, uid, [resource_id])[0][1] + + vals = { + 'method': method, + 'object_id': model_id, + 'user_id': uid, + 'res_id': resource_id, - 'name': name, + } + if (model_id, resource_id) not in old_values and method not in ('copy', 'read'): + # the resource was not existing so we are forcing the method to 'create' + # (because it could also come with the value 'write' if we are creating + # new record through a one2many field) + vals.update({'method': 'create'}) + if (model_id, resource_id) not in new_values and method not in ('copy', 'read'): + # the resource is not existing anymore so we are forcing the method to 'unlink' + # (because it could also come with the value 'write' if we are deleting the + # record through a one2many field) ++ name = old_values[(model_id, resource_id)]['value'].get('name',False) + vals.update({'method': 'unlink'}) ++ else : ++ name = pool[line_model].name_get(cr, uid, [resource_id])[0][1] ++ vals.update({'name': name}) + # create the audittrail log in super admin mode, only if a change has been detected + if lines[(model_id, resource_id)]: + log_id = pool.get('audittrail.log').create(cr, SUPERUSER_ID, vals) + model = pool.get('ir.model').browse(cr, uid, model_id) + create_log_line(cr, SUPERUSER_ID, log_id, model, lines[(model_id, resource_id)]) + return True + +def check_rules(cr, uid, model, method): + """ + Checks if auditrails is installed for that db and then if one rule match + @param cr: the current row, from the database cursor, + @param uid: the current user’s ID, + @param model: value of _name of the object which values are being changed + @param method: method to log: create, read, unlink,write,actions,workflow actions + @return: True or False + """ + pool = openerp.registry(cr.dbname) + if 'audittrail.rule' in pool.models: + model_ids = pool.get('ir.model').search(cr, SUPERUSER_ID, [('model', '=', model)]) + model_id = model_ids and model_ids[0] or False + if model_id: + rule_ids = pool.get('audittrail.rule').search(cr, SUPERUSER_ID, [('object_id', '=', model_id), ('state', '=', 'subscribed')]) + for rule in pool.get('audittrail.rule').read(cr, SUPERUSER_ID, rule_ids, ['user_id','log_read','log_write','log_create','log_unlink','log_action','log_workflow']): + if len(rule['user_id']) == 0 or uid in rule['user_id']: + if rule.get('log_'+method,0): + return True + elif method not in ('default_get','read','fields_view_get','fields_get','search','search_count','name_search','name_get','get','request_get', 'get_sc', 'unlink', 'write', 'create', 'read_group', 'import_data'): + if rule['log_action']: return True - elif method not in ('default_get','read','fields_view_get','fields_get','search','search_count','name_search','name_get','get','request_get', 'get_sc', 'unlink', 'write', 'create', 'read_group', 'import_data'): - if rule['log_action']: - return True - - def execute_cr(self, cr, uid, model, method, *args, **kw): - fct_src = super(audittrail_objects_proxy, self).execute_cr - if self.check_rules(cr,uid,model,method): - return self.log_fct(cr, uid, model, method, fct_src, *args, **kw) - return fct_src(cr, uid, model, method, *args, **kw) - - def exec_workflow_cr(self, cr, uid, model, method, *args, **kw): - fct_src = super(audittrail_objects_proxy, self).exec_workflow_cr - if self.check_rules(cr,uid,model,'workflow'): - return self.log_fct(cr, uid, model, method, fct_src, *args, **kw) - return fct_src(cr, uid, model, method, *args, **kw) - -audittrail_objects_proxy() + +# Replace the openerp.service.model functions. + +original_execute_cr = openerp.service.model.execute_cr +original_exec_workflow_cr = openerp.service.model.exec_workflow_cr + +def execute_cr(cr, uid, model, method, *args, **kw): + fct_src = original_execute_cr + if check_rules(cr,uid,model,method): + return log_fct(cr, uid, model, method, fct_src, *args, **kw) + return fct_src(cr, uid, model, method, *args, **kw) + +def exec_workflow_cr(cr, uid, model, method, *args, **kw): + fct_src = original_exec_workflow_cr + if check_rules(cr,uid,model,'workflow'): + return log_fct(cr, uid, model, method, fct_src, *args, **kw) + return fct_src(cr, uid, model, method, *args, **kw) + +openerp.service.model.execute_cr = execute_cr +openerp.service.model.exec_workflow_cr = exec_workflow_cr # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --cc addons/crm/crm_lead.py index 2ef6e7d,bd3c6f3..2dfd84f --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@@ -308,13 -332,13 +308,16 @@@ class crm_lead(format_address, osv.osv) def onchange_stage_id(self, cr, uid, ids, stage_id, context=None): if not stage_id: - return {'value':{}} - stage = self.pool.get('crm.case.stage').browse(cr, uid, stage_id, context) + return {'value': {}} + stage = self.pool.get('crm.case.stage').browse(cr, uid, stage_id, context=context) if not stage.on_change: - return {'value':{}} - return {'value':{'probability': stage.probability}} + return {'value': {}} - return {'value': {'probability': stage.probability}} ++ vals = {'probability': stage.probability} ++ if stage.probability >= 100 or (stage.probability == 0 and stage.sequence > 1): ++ vals['date_closed'] = fields.datetime.now() ++ return {'value': vals} - def on_change_partner(self, cr, uid, ids, partner_id, context=None): + def on_change_partner_id(self, cr, uid, ids, partner_id, context=None): values = {} if partner_id: partner = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context) @@@ -388,66 -423,38 +391,66 @@@ return stage_ids[0] return False - def case_cancel(self, cr, uid, ids, context=None): - """ Overrides case_cancel from base_stage to set probability """ - res = super(crm_lead, self).case_cancel(cr, uid, ids, context=context) - self.write(cr, uid, ids, {'probability' : 0.0}, context=context) - return res - - def case_reset(self, cr, uid, ids, context=None): - """ Overrides case_reset from base_stage to set probability """ - res = super(crm_lead, self).case_reset(cr, uid, ids, context=context) - self.write(cr, uid, ids, {'probability': 0.0}, context=context) - return res - def case_mark_lost(self, cr, uid, ids, context=None): - """ Mark the case as lost: state=cancel and probability=0 """ - for lead in self.browse(cr, uid, ids): - stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 0.0),('on_change','=',True)], context=context) + """ Mark the case as lost: state=cancel and probability=0 + :deprecated: this method will be removed in OpenERP v8. + """ + stages_leads = {} + for lead in self.browse(cr, uid, ids, context=context): + stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 0.0), ('fold', '=', True), ('sequence', '>', 1)], context=context) if stage_id: - self.case_set(cr, uid, [lead.id], values_to_update={'probability': 0.0, 'date_closed': fields.datetime.now()}, new_stage_id=stage_id, context=context) + if stages_leads.get(stage_id): + stages_leads[stage_id].append(lead.id) + else: + stages_leads[stage_id] = [lead.id] + else: + raise osv.except_osv(_('Warning!'), + _('To relieve your sales pipe and group all Lost opportunities, configure one of your sales stage as follow:\n' + 'probability = 0 %, select "Change Probability Automatically".\n' + 'Create a specific stage or edit an existing one by editing columns of your opportunity pipe.')) + for stage_id, lead_ids in stages_leads.items(): - self.write(cr, uid, lead_ids, {'stage_id': stage_id, 'date_closed': fields.datetime.now()}, context=context) ++ self.write(cr, uid, lead_ids, {'stage_id': stage_id}, context=context) return True def case_mark_won(self, cr, uid, ids, context=None): - """ Mark the case as won: state=done and probability=100 """ - for lead in self.browse(cr, uid, ids): - stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 100.0),('on_change','=',True)], context=context) + """ Mark the case as won: state=done and probability=100 + :deprecated: this method will be removed in OpenERP v8. + """ + stages_leads = {} + for lead in self.browse(cr, uid, ids, context=context): + stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 100.0), ('fold', '=', True)], context=context) if stage_id: - self.case_set(cr, uid, [lead.id], values_to_update={'probability': 100.0, 'date_closed': fields.datetime.now()}, new_stage_id=stage_id, context=context) + if stages_leads.get(stage_id): + stages_leads[stage_id].append(lead.id) + else: + stages_leads[stage_id] = [lead.id] + else: + raise osv.except_osv(_('Warning!'), + _('To relieve your sales pipe and group all Won opportunities, configure one of your sales stage as follow:\n' + 'probability = 100 % and select "Change Probability Automatically".\n' + 'Create a specific stage or edit an existing one by editing columns of your opportunity pipe.')) + for stage_id, lead_ids in stages_leads.items(): - self.write(cr, uid, lead_ids, {'stage_id': stage_id, 'date_closed': fields.datetime.now()}, context=context) ++ self.write(cr, uid, lead_ids, {'stage_id': stage_id}, context=context) + return True + + def case_escalate(self, cr, uid, ids, context=None): + """ Escalates case to parent level """ + for case in self.browse(cr, uid, ids, context=context): + data = {'active': True} + if case.section_id.parent_id: + data['section_id'] = case.section_id.parent_id.id + if case.section_id.parent_id.change_responsible: + if case.section_id.parent_id.user_id: + data['user_id'] = case.section_id.parent_id.user_id.id + else: + raise osv.except_osv(_('Error!'), _("You are already at the top level of your sales-team category.\nTherefore you cannot escalate furthermore.")) + self.write(cr, uid, [case.id], data, context=context) return True - def set_priority(self, cr, uid, ids, priority): + def set_priority(self, cr, uid, ids, priority, context=None): """ Set lead priority """ - return self.write(cr, uid, ids, {'priority' : priority}) + return self.write(cr, uid, ids, {'priority': priority}, context=context) def set_high_priority(self, cr, uid, ids, context=None): """ Set lead priority to high diff --cc addons/mail/mail_thread.py index 4c4a60b,0c911bc..6b587f4 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@@ -156,22 -111,10 +156,23 @@@ class mail_thread(osv.AbstractModel) if res[id]['message_unread_count']: title = res[id]['message_unread_count'] > 1 and _("You have %d unread messages") % res[id]['message_unread_count'] or _("You have one unread message") res[id]['message_summary'] = "9 %d %s" % (title, res[id].pop('message_unread_count'), _("New")) + res[id].pop('message_unread_count', None) return res - def _get_subscription_data(self, cr, uid, ids, name, args, context=None): + def read_followers_data(self, cr, uid, follower_ids, context=None): + result = [] + technical_group = self.pool.get('ir.model.data').get_object(cr, uid, 'base', 'group_no_one') + for follower in self.pool.get('res.partner').browse(cr, uid, follower_ids, context=context): + is_editable = uid in map(lambda x: x.id, technical_group.users) + is_uid = uid in map(lambda x: x.id, follower.user_ids) + data = (follower.id, + follower.name, + {'is_editable': is_editable, 'is_uid': is_uid}, + ) + result.append(data) + return result + + def _get_subscription_data(self, cr, uid, ids, name, args, user_pid=None, context=None): """ Computes: - message_subtype_data: data about document subtypes: which are available, which are followed if any """ diff --cc addons/point_of_sale/point_of_sale.py index ea43de0,f79b8b3..9a20047 --- a/addons/point_of_sale/point_of_sale.py +++ b/addons/point_of_sale/point_of_sale.py @@@ -497,14 -488,15 +497,18 @@@ class pos_order(osv.osv) _description = "Point of Sale" _order = "id desc" - def create_from_ui(self, cr, uid, orders, context=None): - #_logger.info("orders: %r", orders) + def create_from_ui(self, cr, uid, orders, context=None): + # Keep only new orders + submitted_references = [o['data']['name'] for o in orders] + existing_orders = self.search_read(cr, uid, domain=[('pos_reference', 'in', submitted_references)], fields=['pos_reference'], context=context) + existing_references = set([o['pos_reference'] for o in existing_orders]) + orders_to_save = [o for o in orders if o['data']['name'] not in existing_references] order_ids = [] - for tmp_order in orders: + for tmp_order in orders_to_save: + to_invoice = tmp_order['to_invoice'] order = tmp_order['data'] + + order_id = self.create(cr, uid, { 'name': order['name'], 'user_id': order['user_id'] or False, diff --cc addons/point_of_sale/security/point_of_sale_security.xml index 54572ee,47cdf47..5e98bcb --- a/addons/point_of_sale/security/point_of_sale_security.xml +++ b/addons/point_of_sale/security/point_of_sale_security.xml @@@ -19,5 -19,11 +19,11 @@@ [('company_id', '=', user.company_id.id)] + + Point Of Sale Config + + - ['|',('shop_id.company_id','=',False),('shop_id.company_id','child_of',[user.company_id.id])] ++ [('warehouse_id.company_id','child_of',[user.company_id.id])] + diff --cc addons/portal/mail_message.py index 4429df3,3929908..36b0648 --- a/addons/portal/mail_message.py +++ b/addons/portal/mail_message.py @@@ -39,10 -39,10 +39,10 @@@ class mail_message(osv.Model) group_ids = self.pool.get('res.users').browse(cr, uid, uid, context=context).groups_id group_user_id = self.pool.get("ir.model.data").get_object_reference(cr, uid, 'base', 'group_user')[1] if group_user_id not in [group.id for group in group_ids]: - args = ['&', '|', ('type', '!=', 'comment'), ('subtype_id', '!=', False)] + list(args) + args = [('subtype_id', '!=', False)] + list(args) return super(mail_message, self)._search(cr, uid, args, offset=offset, limit=limit, order=order, - context=context, count=False, access_rights_uid=access_rights_uid) + context=context, count=count, access_rights_uid=access_rights_uid) def check_access_rule(self, cr, uid, ids, operation, context=None): """ Add Access rules of mail.message for non-employee user: diff --cc addons/report_webkit/webkit_report.py index 4f56d7e,c6a30f5..60fb536 --- a/addons/report_webkit/webkit_report.py +++ b/addons/report_webkit/webkit_report.py @@@ -83,35 -58,10 +83,36 @@@ def mako_template(text) This template uses UTF-8 encoding """ - tmp_lookup = TemplateLookup() #we need it in order to allow inclusion and inheritance - return Template(text, input_encoding='utf-8', output_encoding='utf-8', lookup=tmp_lookup) + + return mako_template_env.from_string(text) + +_extender_functions = {} + +def webkit_report_extender(report_name): + """ + A decorator to define functions to extend the context used in a template rendering. + report_name must be the xml id of the desired report (it is mandatory to indicate the + module in that xml id). + + The given function will be called at the creation of the report. The following arguments + will be passed to it (in this order): + - pool The model pool. + - cr The cursor. + - uid The user id. + - localcontext The context given to the template engine to render the templates for the + current report. This is the context that should be modified. + - context The OpenERP context. + """ + def fct1(fct): + lst = _extender_functions.get(report_name) + if not lst: + lst = [] + _extender_functions[report_name] = lst + lst.append(fct) + return fct + return fct1 + class WebKitParser(report_sxw): """Custom class that use webkit to render HTML reports Code partially taken from report openoffice. Thanks guys :) @@@ -173,7 -123,7 +174,7 @@@ ), 'w' ) - head_file.write(header.encode('utf-8')) - head_file.write(self._sanitize_html(header)) ++ head_file.write(self._sanitize_html(header.encode('utf-8'))) head_file.close() file_to_del.append(head_file.name) command.extend(['--header-html', head_file.name]) @@@ -184,7 -134,7 +185,7 @@@ ), 'w' ) - foot_file.write(footer.encode('utf-8')) - foot_file.write(self._sanitize_html(footer)) ++ foot_file.write(self._sanitize_html(footer.encode('utf-8'))) foot_file.close() file_to_del.append(foot_file.name) command.extend(['--footer-html', foot_file.name]) @@@ -205,7 -155,7 +206,7 @@@ for html in html_list : html_file = file(os.path.join(tmp_dir, str(time.time()) + str(count) +'.body.html'), 'w') count += 1 - html_file.write(html.encode('utf-8')) - html_file.write(self._sanitize_html(html)) ++ html_file.write(self._sanitize_html(html.encode('utf-8'))) html_file.close() file_to_del.append(html_file.name) command.append(html_file.name) diff --cc addons/sale/wizard/sale_make_invoice.py index 3712fed,4405349..1702598 --- a/addons/sale/wizard/sale_make_invoice.py +++ b/addons/sale/wizard/sale_make_invoice.py @@@ -55,11 -57,13 +55,12 @@@ class sale_make_invoice(osv.osv_memory) raise osv.except_osv(_('Warning!'), _("You shouldn't manually invoice the following sale order %s") % (sale_order.name)) order_obj.action_invoice_create(cr, uid, context.get(('active_ids'), []), data['grouped'], date_invoice=data['invoice_date']) - - for o in order_obj.browse(cr, uid, context.get(('active_ids'), []), context=context): + orders = order_obj.browse(cr, uid, context.get(('active_ids'), []), context=context) + for o in orders: for i in o.invoice_ids: newinv.append(i.id) - + # Dummy call to workflow, will not create another invoice but bind the new invoice to the subflow - for id in [o.id for o in orders if o.order_policy == 'manual']: - wf_service.trg_validate(uid, 'sale.order', id, 'manual_invoice', cr) ++ order_obj.signal_manual_invoice(cr, uid, [o.id for o in orders if o.order_policy == 'manual']) result = mod_obj.get_object_reference(cr, uid, 'account', 'action_invoice_tree1') id = result and result[1] or False result = act_obj.read(cr, uid, [id], context=context)[0] diff --cc addons/stock/stock.py index d48ff80,eaacbcb..7e73d7f --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@@ -2232,17 -2245,19 +2232,17 @@@ class stock_move(osv.osv) if move.picking_id: pickings.add(move.picking_id.id) if move.move_dest_id and move.move_dest_id.state == 'waiting': - self.write(cr, uid, [move.move_dest_id.id], {'state': 'confirmed'}) + self.write(cr, uid, [move.move_dest_id.id], {'state': 'confirmed'}, context=context) if context.get('call_unlink',False) and move.move_dest_id.picking_id: - wf_service = netsvc.LocalService("workflow") - wf_service.trg_write(uid, 'stock.picking', move.move_dest_id.picking_id.id, cr) + workflow.trg_write(uid, 'stock.picking', move.move_dest_id.picking_id.id, cr) - self.write(cr, uid, ids, {'state': 'cancel', 'move_dest_id': False}) + self.write(cr, uid, ids, {'state': 'cancel', 'move_dest_id': False}, context=context) if not context.get('call_unlink',False): for pick in self.pool.get('stock.picking').browse(cr, uid, list(pickings), context=context): if all(move.state == 'cancel' for move in pick.move_lines): - self.pool.get('stock.picking').write(cr, uid, [pick.id], {'state': 'cancel'}) + self.pool.get('stock.picking').write(cr, uid, [pick.id], {'state': 'cancel'}, context=context) - wf_service = netsvc.LocalService("workflow") for id in ids: - wf_service.trg_trigger(uid, 'stock.move', id, cr) + workflow.trg_trigger(uid, 'stock.move', id, cr) return True def _get_accounting_data_for_valuation(self, cr, uid, move, context=None): diff --cc addons/survey/wizard/survey_send_invitation.py index 44d3bec,177815c..e16d0d6 --- a/addons/survey/wizard/survey_send_invitation.py +++ b/addons/survey/wizard/survey_send_invitation.py @@@ -128,17 -127,10 +128,8 @@@ Thanks,''') % (name, self.pool.get('ir. for use in exist_user: new_user.append(use.id) for id in survey_ref.browse(cr, uid, survey_ids): - report = self.create_report(cr, uid, [id.id], 'report.survey.form', id.title) - file = open(get_module_resource('survey', 'report') + id.title +".pdf") - file_data = "" - while 1: - line = file.readline() - file_data += line - if not line: - break - file.close() - attachments[id.title +".pdf"] = file_data - os.remove(get_module_resource('survey', 'report') + id.title +".pdf") - service = netsvc.LocalService('report.survey.form'); - (result, format) = service.create(cr, uid, [id.id], {}, {}) - ++ result, format = openerp.report.render_report(cr, uid, [id.id], 'survey.form', {}, {}) + attachments[id.title +".pdf"] = result for partner in self.pool.get('res.partner').browse(cr, uid, partner_ids): if not partner.email: