From 4661fb71d202390f0bf55c1f92073d3fce24878f Mon Sep 17 00:00:00 2001 From: "Turkesh Patel (Open ERP)" Date: Fri, 18 May 2012 12:03:48 +0530 Subject: [PATCH 001/100] [FIX] account: set ondelete='cascade' on payment_id for allow to delete payment term. bzr revid: tpa@tinyerp.com-20120518063348-1lm9oyy0kw5pkwdy --- addons/account/account.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/account/account.py b/addons/account/account.py index 26af7a5f9bd..8d0fb8eb818 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -106,7 +106,7 @@ class account_payment_term_line(osv.osv): 'days': fields.integer('Number of Days', required=True, help="Number of days to add before computation of the day of month." \ "If Date=15/01, Number of Days=22, Day of Month=-1, then the due date is 28/02."), 'days2': fields.integer('Day of the Month', required=True, help="Day of the month, set -1 for the last day of the current month. If it's positive, it gives the day of the next month. Set 0 for net days (otherwise it's based on the beginning of the month)."), - 'payment_id': fields.many2one('account.payment.term', 'Payment Term', required=True, select=True), + 'payment_id': fields.many2one('account.payment.term', 'Payment Term', required=True, select=True, ondelete='cascade'), } _defaults = { 'value': 'balance', From da13d90912fb12bd8f82a12300325f6f57dfee17 Mon Sep 17 00:00:00 2001 From: "Turkesh Patel (Open ERP)" Date: Mon, 11 Jun 2012 14:38:49 +0530 Subject: [PATCH 002/100] [FIX] stock:'product level forecast' report does not support accented char. bzr revid: tpa@tinyerp.com-20120611090849-cmir9qms3blrjjw4 --- addons/stock/report/stock_graph.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/stock/report/stock_graph.py b/addons/stock/report/stock_graph.py index 5ee58bb9d2c..b5d08f93d3f 100644 --- a/addons/stock/report/stock_graph.py +++ b/addons/stock/report/stock_graph.py @@ -22,6 +22,7 @@ from pychart import * import pychart.legend import time from report.misc import choice_colors +import base64 # # Draw a graph for stocks @@ -41,7 +42,7 @@ class stock_graph(object): product_name=product_name.replace('/', '//') if product_id not in self._datas: self._datas[product_id] = {} - self._names[product_id] = product_name + self._names[product_id] = product_name.decode('utf-8') for (dt,stock) in datas: if not dt in self._datas[product_id]: self._datas[product_id][dt]=0 From 61a3238d978ab40e661974dc2b75fbda700f7c70 Mon Sep 17 00:00:00 2001 From: "Mayur Maheshwari (OpenERP)" Date: Mon, 11 Jun 2012 16:20:38 +0530 Subject: [PATCH 003/100] [FIX]stock: fix the issue of counting of Deliveries in kanban view and improve a action string lp bug: https://launchpad.net/bugs/1011541 fixed bzr revid: mma@tinyerp.com-20120611105038-wrospxpjr2wbna6h --- addons/stock/product.py | 2 +- addons/stock/product_view.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/stock/product.py b/addons/stock/product.py index 62fdbb24ca2..9f9faa1cc24 100644 --- a/addons/stock/product.py +++ b/addons/stock/product.py @@ -44,7 +44,7 @@ class product_product(osv.osv): ], ['product_id'], ['product_id']) for move in moves: product_id = move['product_id'][0] - res[product_id]['reception_count'] = move['product_id_count'] + res[product_id]['delivery_count'] = move['product_id_count'] return res def get_product_accounts(self, cr, uid, product_id, context=None): diff --git a/addons/stock/product_view.xml b/addons/stock/product_view.xml index 49e0e9c1880..e1840ac7497 100644 --- a/addons/stock/product_view.xml +++ b/addons/stock/product_view.xml @@ -140,7 +140,7 @@ - Receive Products + Deliver Products stock.move ir.actions.act_window form From 344ddfbdd5fcf2ff6f22a76f5aa405e8ebeee185 Mon Sep 17 00:00:00 2001 From: "Mayur Maheshwari (OpenERP)" Date: Tue, 19 Jun 2012 11:54:26 +0530 Subject: [PATCH 004/100] [FIX]base:fix the issue of KeyError when changes in line of Journal Entry lp bug: https://launchpad.net/bugs/955910 fixed bzr revid: mma@tinyerp.com-20120619062426-x5ykv2thycvpvs4l --- addons/account/account.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/account/account.py b/addons/account/account.py index f0c16d8586c..a441a262003 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -1363,7 +1363,7 @@ class account_move(osv.osv): balance = 0.0 for line in line_ids: if line[2]: - balance += (line[2]['debit'] or 0.00)- (line[2]['credit'] or 0.00) + balance += (line[2].get('debit',0.00)- (line[2].get('credit',0.00))) return {'value': {'balance': balance}} def write(self, cr, uid, ids, vals, context=None): From 41c90e8755b5b12f8e6f4e3870eb3a7f8e2b7b5b Mon Sep 17 00:00:00 2001 From: "Ajay Chauhan (OpenERP)" Date: Thu, 5 Jul 2012 18:34:55 +0530 Subject: [PATCH 005/100] [FIX] account: add else condition in onchange_chart_id lp bug: https://launchpad.net/bugs/1021152 fixed bzr revid: cha@tinyerp.com-20120705130455-iy00wseff3lroj25 --- addons/account/wizard/account_report_common.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/account/wizard/account_report_common.py b/addons/account/wizard/account_report_common.py index fa3c195cfb7..f84c4e909a2 100644 --- a/addons/account/wizard/account_report_common.py +++ b/addons/account/wizard/account_report_common.py @@ -32,6 +32,8 @@ class account_common_report(osv.osv_memory): def onchange_chart_id(self, cr, uid, ids, chart_account_id=False, context=None): if chart_account_id: company_id = self.pool.get('account.account').browse(cr, uid, chart_account_id, context=context).company_id.id + else: + return {'value': {'company_id': False}} return {'value': {'company_id': company_id}} _columns = { From c02116b41f9c500828c54725c11541ddcd1c5dfd Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Tue, 14 Aug 2012 21:44:12 +0200 Subject: [PATCH 006/100] [IMP] cleaning of need action bzr revid: fp@openerp.com-20120814194412-2bcujivyd45buikx --- openerp/addons/base/ir/ir.xml | 24 --- openerp/addons/base/ir/ir_needaction.py | 182 +++--------------- openerp/addons/base/ir/ir_ui_menu.py | 18 +- .../addons/base/security/ir.model.access.csv | 1 - openerp/osv/orm.py | 33 +--- 5 files changed, 36 insertions(+), 222 deletions(-) diff --git a/openerp/addons/base/ir/ir.xml b/openerp/addons/base/ir/ir.xml index fac2946e204..c554a8896aa 100644 --- a/openerp/addons/base/ir/ir.xml +++ b/openerp/addons/base/ir/ir.xml @@ -556,30 +556,6 @@ - - - ir.needaction_users_rel.tree - ir.needaction_users_rel - 10 - - - - - - - - - - - Need action relationships - ir.needaction_users_rel - form - tree,form - - - - - ir.ui.view diff --git a/openerp/addons/base/ir/ir_needaction.py b/openerp/addons/base/ir/ir_needaction.py index 0f28c33ded9..95fc6d81b09 100644 --- a/openerp/addons/base/ir/ir_needaction.py +++ b/openerp/addons/base/ir/ir_needaction.py @@ -19,180 +19,48 @@ # ############################################################################## -import openerp.pooler as pooler -from operator import itemgetter from osv import osv, fields -from tools.translate import _ - -class ir_needaction_users_rel(osv.Model): - ''' ir_needaction_users_rel holds data related to the needaction - mechanism inside OpenERP. A row in this model is characterized - by: - - res_model: model of the record requiring an action - - res_id: ID of the record requiring an action - - user_id: foreign key to the res.users table, to the user that has to - perform the action - This model can be seen as a many2many, linking (res_model, res_id) to users - (those whose attention is required on the record). ''' - - _name = 'ir.needaction_users_rel' - _description = 'Needaction relationship table' - _rec_name = 'id' - _order = 'id desc' - _columns = { - 'res_model': fields.char('Related Document Model', size=128, - select=1, required=True), - 'res_id': fields.integer('Related Document ID', - select=1, required=True), - 'user_id': fields.many2one('res.users', string='Related User', - ondelete='cascade', select=1, required=True), - } - - def _get_users(self, cr, uid, res_ids, res_model, context=None): - """Given res_ids of res_model, get user_ids present in table""" - rel_ids = self.search(cr, uid, [('res_model', '=', res_model), ('res_id', 'in', res_ids)], context=context) - return list(set(map(itemgetter('user_id'), self.read(cr, uid, rel_ids, ['user_id'], context=context)))) - - def create_users(self, cr, uid, res_ids, res_model, user_ids, context=None): - """Given res_ids of res_model, add user_ids to the relationship table""" - for res_id in res_ids: - for user_id in user_ids: - self.create(cr, uid, {'res_model': res_model, 'res_id': res_id, 'user_id': user_id}, context=context) - return True - - def unlink_users(self, cr, uid, res_ids, res_model, context=None): - """Given res_ids of res_model, delete all entries in the relationship table""" - to_del_ids = self.search(cr, uid, [('res_model', '=', res_model), ('res_id', 'in', res_ids)], context=context) - return self.unlink(cr, uid, to_del_ids, context=context) - - def update_users(self, cr, uid, res_ids, res_model, user_ids, context=None): - """Given res_ids of res_model, update their entries in the relationship table to user_ids""" - # read current records - cur_users = self._get_users(cr, uid, res_ids, res_model, context=context) - if len(cur_users) == len(user_ids) and all(cur_user in user_ids for cur_user in cur_users): - return True - # unlink old records - self.unlink_users(cr, uid, res_ids, res_model, context=context) - # link new records - self.create_users(cr, uid, res_ids, res_model, user_ids, context=context) - return True - class ir_needaction_mixin(osv.Model): '''Mixin class for objects using the need action feature. - - Need action feature can be used by objects having to be able to - signal that an action is required on a particular record. If in - the business logic an action must be performed by somebody, for - instance validation by a manager, this mechanism allows to set a + + Need action feature can be used by objects having to be able to + signal that an action is required on a particular record. If in + the business logic an action must be performed by somebody, for + instance validation by a manager, this mechanism allows to set a list of users asked to perform an action. - - This class wraps a class (ir.ir_needaction_users_rel) that - behaves like a many2many field. This class handles the low-level - considerations of updating relationships. Every change made on - the record calls a method that updates the relationships. - - Objects using the 'need_action' feature should override the - ``get_needaction_user_ids`` method. This methods returns a - dictionary whose keys are record ids, and values a list of user - ids, like in a many2many relationship. Therefore by defining - only one method, you can specify if an action is required by - defining the users that have to do it, in every possible - situation. - - This class also offers several global services: - - ``needaction_get_record_ids``: for the current model and uid, get - all record ids that ask this user to perform an action. This - mechanism is used for instance to display the number of pending - actions in menus, such as Leads (12) + + Objects using the 'need_action' feature should override the + ``needaction_domain_get`` method. This methods returns a + domain to filter records requiring an action for a specific user. + + This class also offers several global services: - ``needaction_get_action_count``: as ``needaction_get_record_ids`` - but returns only the number of action, not the ids (performs a + but returns only the number of action, not the ids (performs a search with count=True) + ''' - The ``ir_needaction_mixin`` class adds a calculated field - ``needaction_pending``. This function field allows to state - whether a given record has a needaction for the current user. - This is usefull if you want to customize views according to the - needaction feature. For example, you may want to set records in - bold in a list view if the current user has an action to perform - on the record. ''' - _name = 'ir.needaction_mixin' - _description = 'Need action mixin' - - def get_needaction_pending(self, cr, uid, ids, name, arg, context=None): - res = {} - needaction_user_ids = self.get_needaction_user_ids(cr, uid, ids, context=context) - for id in ids: - res[id] = uid in needaction_user_ids[id] - return res + _description = 'Need Action Mixin' + _needaction = True - def search_needaction_pending(self, cr, uid, self_again, field_name, criterion, context=None): - ids = self.needaction_get_record_ids( - cr, uid, uid, limit=1024, context=context) - return [('id', 'in', ids)] - - _columns = { - 'needaction_pending': fields.function( - get_needaction_pending, type='boolean', - fnct_search=search_needaction_pending, - string='Need action pending', - help="If True, this field states that users have to perform an " \ - "action This field comes from the ir.needaction_mixin class."), - } - #------------------------------------------------------ # Addon API #------------------------------------------------------ - - def get_needaction_user_ids(self, cr, uid, ids, context=None): - """ Returns the user_ids that have to perform an action - :return: dict { record_id: [user_ids], } + + def _needaction_domain_get(self, cr, uid, context=None): + """ Returns the domain to filter records that require an action + :return: domain or False is no need action """ - return dict((id,list()) for id in ids) - - def create(self, cr, uid, values, context=None): - rel_obj = self.pool.get('ir.needaction_users_rel') - # perform create - obj_id = super(ir_needaction_mixin, self).create(cr, uid, values, context=context) - # link user_ids - needaction_user_ids = self.get_needaction_user_ids(cr, uid, [obj_id], context=context) - rel_obj.create_users(cr, uid, [obj_id], self._name, needaction_user_ids[obj_id], context=context) - return obj_id - - def write(self, cr, uid, ids, values, context=None): - rel_obj = self.pool.get('ir.needaction_users_rel') - # perform write - write_res = super(ir_needaction_mixin, self).write(cr, uid, ids, values, context=context) - # get and update user_ids - needaction_user_ids = self.get_needaction_user_ids(cr, uid, ids, context=context) - for id in ids: - rel_obj.update_users(cr, uid, [id], self._name, needaction_user_ids[id], context=context) - return write_res - - def unlink(self, cr, uid, ids, context=None): - # unlink user_ids - rel_obj = self.pool.get('ir.needaction_users_rel') - rel_obj.unlink_users(cr, uid, ids, self._name, context=context) - # perform unlink - return super(ir_needaction_mixin, self).unlink(cr, uid, ids, context=context) - + return False + #------------------------------------------------------ # "Need action" API #------------------------------------------------------ - - def needaction_get_record_ids(self, cr, uid, user_id, limit=80, context=None): - """Given the current model and a user_id - return the record ids that require the user to perform an - action""" - rel_obj = self.pool.get('ir.needaction_users_rel') - rel_ids = rel_obj.search(cr, uid, [('res_model', '=', self._name), ('user_id', '=', user_id)], limit=limit, context=context) - return map(itemgetter('res_id'), rel_obj.read(cr, uid, rel_ids, ['res_id'], context=context)) - - def needaction_get_action_count(self, cr, uid, user_id, limit=80, context=None): + + def _needaction_count(self, cr, uid, domain=[], context=None): """Given the current model and a user_id get the number of actions it has to perform""" - rel_obj = self.pool.get('ir.needaction_users_rel') - return rel_obj.search(cr, uid, [('res_model', '=', self._name), ('user_id', '=', user_id)], limit=limit, count=True, context=context) + dom = self._needaction_domain_get(cr, uid, context=context) + return self.search(cr, uid, domain+dom, context=context, count=True) -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py index 77c0c4d738a..1bb517c570f 100644 --- a/openerp/addons/base/ir/ir_ui_menu.py +++ b/openerp/addons/base/ir/ir_ui_menu.py @@ -255,23 +255,23 @@ class ir_ui_menu(osv.osv): return res - def _get_needaction_info(self, cr, uid, id, domain=[], context={}): - return [False, 0] - def _get_needaction(self, cr, uid, ids, field_names, args, context=None): if context is None: context = {} res = {} for menu in self.browse(cr, uid, ids, context=context): + res[menu.id]['needaction_enabled'] = False + res[menu.id]['needaction_counter'] = False res[menu.id] = {} if menu.action and menu.action.type == 'ir.actions.act_window' and menu.action.res_model: - menu_needaction_res = self.pool.get(menu.action.res_model)._get_needaction_info(cr, uid, uid, domain=menu.action.domain, context=context) - else: - menu_needaction_res = [False, 0] - res[menu.id]['needaction_enabled'] = menu_needaction_res[0] - res[menu.id]['needaction_counter'] = menu_needaction_res[1] + obj = self.pool.get(menu.action.res_model) + if obj._needaction_active: + res[menu.id]['needaction_enabled'] = obj._needaction_active + # check domain and context: should we evaluate the domain ? + # and add context of the action ? + res[menu.id]['needaction_counter'] = obj._needaction_count(cr, uid, menu.action.domain, context=context) return res - + _columns = { 'name': fields.char('Menu', size=64, required=True, translate=True), 'sequence': fields.integer('Sequence'), diff --git a/openerp/addons/base/security/ir.model.access.csv b/openerp/addons/base/security/ir.model.access.csv index d49aa18db8c..b0218e977bc 100644 --- a/openerp/addons/base/security/ir.model.access.csv +++ b/openerp/addons/base/security/ir.model.access.csv @@ -118,6 +118,5 @@ "access_ir_config_parameter","ir_config_parameter","model_ir_config_parameter",,1,0,0,0 "access_ir_mail_server_all","ir_mail_server","model_ir_mail_server",,1,0,0,0 "access_ir_actions_client","ir_actions_client all","model_ir_actions_client",,1,0,0,0 -"access_ir_needaction_users_rel","ir_needaction_users_rel","model_ir_needaction_users_rel",,1,1,1,1 "access_ir_needaction_mixin","ir_needaction_mixin","model_ir_needaction_mixin",,1,1,1,1 diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 7c8085ea8ed..368a37f455a 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -666,6 +666,7 @@ class BaseModel(object): _order = 'id' _sequence = None _description = None + _needaction = False # dict of {field:method}, with method returning the name_get of records # to include in the _read_group, if grouped on this field @@ -4960,37 +4961,7 @@ class BaseModel(object): # backwards compatibility get_xml_id = get_external_id _get_xml_ids = _get_external_ids - - def _get_needaction_info(self, cr, uid, user_id, limit=None, order=None, domain=False, context=None): - """Base method for needaction mechanism - - see ir.needaction for actual implementation - - if the model uses the need action mechanism - (hasattr(model_obj, 'needaction_get_record_ids')): - - get the record ids on which the user has actions to perform - - evaluate the menu domain - - compose a new domain: menu domain, limited to ids of - records requesting an action - - count the number of records maching that domain, that - is the number of actions the user has to perform - - this method returns default values - :param: model_name: the name of the model (ex: hr.holidays) - :param: user_id: the id of user - :return: [uses_needaction=True/False, needaction_uid_ctr=%d] - """ - if hasattr(self, 'needaction_get_record_ids'): - # Arbitrary limit, but still much lower thant infinity, to avoid - # getting too much data. - ids = self.needaction_get_record_ids(cr, uid, user_id, limit=8192, context=context) - if not ids: - return [True, 0] - if domain: - new_domain = eval(domain, locals_dict={'uid': user_id}) + [('id', 'in', ids)] - else: - new_domain = [('id', 'in', ids)] - return [True, self.search(cr, uid, new_domain, limit=limit, order=order, count=True, context=context)] - else: - return [False, 0] - + # Transience def is_transient(self): """ Return whether the model is transient. From 560e9e7fd259c4da0285d3730ec72c1f462b755a Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Tue, 14 Aug 2012 21:58:40 +0200 Subject: [PATCH 007/100] [IMP] put needaction_pending again, new implementation bzr revid: fp@openerp.com-20120814195840-yaha9r3qvj8o13zr --- openerp/addons/base/ir/ir_needaction.py | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/openerp/addons/base/ir/ir_needaction.py b/openerp/addons/base/ir/ir_needaction.py index 95fc6d81b09..5552b42052e 100644 --- a/openerp/addons/base/ir/ir_needaction.py +++ b/openerp/addons/base/ir/ir_needaction.py @@ -38,12 +38,39 @@ class ir_needaction_mixin(osv.Model): - ``needaction_get_action_count``: as ``needaction_get_record_ids`` but returns only the number of action, not the ids (performs a search with count=True) + + The ``ir_needaction_mixin`` class adds a calculated field + ``needaction_pending``. This function field allows to state + whether a given record has a needaction for the current user. + This is usefull if you want to customize views according to the + needaction feature. For example, you may want to set records in + bold in a list view if the current user has an action to perform + on the record. ''' _name = 'ir.needaction_mixin' _description = 'Need Action Mixin' _needaction = True + def get_needaction_pending(self, cr, uid, ids, name, arg, context=None): + dom = self._needaction_domain_get(cr, uid, context=context) + result = dict.fromkeys(ids, False) + ids2 = self.search(cr, uid, [('id','in',ids)+dom], context=context) + for idna in ids2: + result[idna] = True + return result + + def search_needaction_pending(self, cr, uid, field, field_name, criterion, context=None): + return self._needaction_domain_get(cr, uid, context=context) + + _columns = { + 'needaction_pending': fields.function( + get_needaction_pending, type='boolean', + fnct_search=search_needaction_pending, + string='Need an Action', + help="Do the current user requires to perform an action."), + } + #------------------------------------------------------ # Addon API #------------------------------------------------------ From 1353759beca8ada3d739f9c57117255c9909e25d Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Wed, 15 Aug 2012 15:37:10 +0200 Subject: [PATCH 008/100] [IMP] dynamic domains on O2M, remove needaction_pending bzr revid: fp@openerp.com-20120815133710-138x0d52qqcd8ex2 --- openerp/addons/base/ir/ir_needaction.py | 30 ++----------------------- openerp/addons/base/ir/ir_ui_menu.py | 5 +++-- openerp/osv/fields.py | 15 ++++++++++--- 3 files changed, 17 insertions(+), 33 deletions(-) diff --git a/openerp/addons/base/ir/ir_needaction.py b/openerp/addons/base/ir/ir_needaction.py index 5552b42052e..9112d60c1f4 100644 --- a/openerp/addons/base/ir/ir_needaction.py +++ b/openerp/addons/base/ir/ir_needaction.py @@ -38,39 +38,11 @@ class ir_needaction_mixin(osv.Model): - ``needaction_get_action_count``: as ``needaction_get_record_ids`` but returns only the number of action, not the ids (performs a search with count=True) - - The ``ir_needaction_mixin`` class adds a calculated field - ``needaction_pending``. This function field allows to state - whether a given record has a needaction for the current user. - This is usefull if you want to customize views according to the - needaction feature. For example, you may want to set records in - bold in a list view if the current user has an action to perform - on the record. ''' _name = 'ir.needaction_mixin' - _description = 'Need Action Mixin' _needaction = True - def get_needaction_pending(self, cr, uid, ids, name, arg, context=None): - dom = self._needaction_domain_get(cr, uid, context=context) - result = dict.fromkeys(ids, False) - ids2 = self.search(cr, uid, [('id','in',ids)+dom], context=context) - for idna in ids2: - result[idna] = True - return result - - def search_needaction_pending(self, cr, uid, field, field_name, criterion, context=None): - return self._needaction_domain_get(cr, uid, context=context) - - _columns = { - 'needaction_pending': fields.function( - get_needaction_pending, type='boolean', - fnct_search=search_needaction_pending, - string='Need an Action', - help="Do the current user requires to perform an action."), - } - #------------------------------------------------------ # Addon API #------------------------------------------------------ @@ -89,5 +61,7 @@ class ir_needaction_mixin(osv.Model): """Given the current model and a user_id get the number of actions it has to perform""" dom = self._needaction_domain_get(cr, uid, context=context) + if dom is False: + return 0 return self.search(cr, uid, domain+dom, context=context, count=True) diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py index 1bb517c570f..f5e4ee2ba05 100644 --- a/openerp/addons/base/ir/ir_ui_menu.py +++ b/openerp/addons/base/ir/ir_ui_menu.py @@ -260,13 +260,14 @@ class ir_ui_menu(osv.osv): context = {} res = {} for menu in self.browse(cr, uid, ids, context=context): + res[menu.id] = {} res[menu.id]['needaction_enabled'] = False res[menu.id]['needaction_counter'] = False res[menu.id] = {} if menu.action and menu.action.type == 'ir.actions.act_window' and menu.action.res_model: obj = self.pool.get(menu.action.res_model) - if obj._needaction_active: - res[menu.id]['needaction_enabled'] = obj._needaction_active + if obj._needaction: + res[menu.id]['needaction_enabled'] = obj._needaction # check domain and context: should we evaluate the domain ? # and add context of the action ? res[menu.id]['needaction_counter'] = obj._needaction_count(cr, uid, menu.action.domain, context=context) diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index d6a5f4f63d8..fd23c246a16 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -514,7 +514,10 @@ class one2many(_column): for id in ids: res[id] = [] - ids2 = obj.pool.get(self._obj).search(cr, user, self._domain + [(self._fields_id, 'in', ids)], limit=self._limit, context=context) + dom = self._domain + if isinstance(self._domain, type(lambda: None)): + dom = self._domain(obj) + ids2 = obj.pool.get(self._obj).search(cr, user, dom + [(self._fields_id, 'in', ids)], limit=self._limit, context=context) for r in obj.pool.get(self._obj)._read_flat(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'): if r[self._fields_id] in res: res[r[self._fields_id]].append(r['id']) @@ -556,7 +559,10 @@ class one2many(_column): reverse_rel = obj._all_columns.get(self._fields_id) assert reverse_rel, 'Trying to unlink the content of a o2m but the pointed model does not have a m2o' # if the o2m has a static domain we must respect it when unlinking - extra_domain = self._domain if isinstance(getattr(self, '_domain', None), list) else [] + dom = self._domain + if isinstance(self._domain, type(lambda: None)): + dom = self._domain(obj) + extra_domain = dom or [] ids_to_unlink = obj.search(cr, user, [(self._fields_id,'=',id)] + extra_domain, context=context) # If the model has cascade deletion, we delete the rows because it is the intended behavior, # otherwise we only nullify the reverse foreign key column. @@ -574,7 +580,10 @@ class one2many(_column): return result def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, operator='like', context=None): - return obj.pool.get(self._obj).name_search(cr, uid, value, self._domain, operator, context=context,limit=limit) + dom = self._domain + if isinstance(self._domain, type(lambda: None)): + dom = self._domain(obj) + return obj.pool.get(self._obj).name_search(cr, uid, value, dom, operator, context=context,limit=limit) @classmethod From b9bdf2c29a048116304f18a95eb2e8c912f3100a Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Thu, 16 Aug 2012 18:42:39 +0200 Subject: [PATCH 009/100] [IMP] tools.email_split bzr revid: fp@tinyerp.com-20120816164239-yl1vzp83w6z5xi5i --- openerp/tools/misc.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py index e90fadf0492..7f2dade30d8 100644 --- a/openerp/tools/misc.py +++ b/openerp/tools/misc.py @@ -1113,6 +1113,12 @@ class unquote(str): def __repr__(self): return self +def emails_split(text): + """Return a list of the email addresses found in ``text``""" + if not text: return [] + return re.findall(r'([^ ,<@]+@[^> ,]+)', text) + + class UnquoteEvalContext(defaultdict): """Defaultdict-based evaluation context that returns an ``unquote`` string for any missing name used during From 4e435d335db70863ec732860f4b5009ed13d5279 Mon Sep 17 00:00:00 2001 From: "Mayur Maheshwari (OpenERP)" Date: Fri, 17 Aug 2012 16:17:02 +0530 Subject: [PATCH 010/100] [FIX]hr_timesheet_sheet :fix the issue open timesheet by account from timesheet form view and pass a appropriate ids in name_get lp bug: https://launchpad.net/bugs/1038023 fixed bzr revid: mma@tinyerp.com-20120817104702-qpzqc8w1s9pccr83 --- addons/hr_timesheet_sheet/hr_timesheet_sheet.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py index ca28b5bdb28..b2ef41f3a46 100644 --- a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py +++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py @@ -442,8 +442,10 @@ class hr_timesheet_sheet(osv.osv): return True def name_get(self, cr, uid, ids, context=None): - if not len(ids): + if not ids: return [] + if isinstance(ids, (int)): + ids = [ids] return [(r['id'], r['date_from'] + ' - ' + r['date_to']) \ for r in self.read(cr, uid, ids, ['date_from', 'date_to'], context=context, load='_classic_write')] From 07c5ee86d67a573d220803640c73b273456a233d Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Fri, 17 Aug 2012 16:49:49 +0200 Subject: [PATCH 011/100] fix bzr revid: fp@tinyerp.com-20120817144949-wrqo086h3dx6f3kx --- openerp/addons/base/ir/ir_needaction.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openerp/addons/base/ir/ir_needaction.py b/openerp/addons/base/ir/ir_needaction.py index 9112d60c1f4..e40a3030eb8 100644 --- a/openerp/addons/base/ir/ir_needaction.py +++ b/openerp/addons/base/ir/ir_needaction.py @@ -63,5 +63,6 @@ class ir_needaction_mixin(osv.Model): dom = self._needaction_domain_get(cr, uid, context=context) if dom is False: return 0 - return self.search(cr, uid, domain+dom, context=context, count=True) + print domain, dom + return self.search(cr, uid, (domain or []) +dom, context=context, count=True) From 03f4b992ad57d5a52d4ac8229bab95ba94808969 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Sun, 19 Aug 2012 16:59:28 +0200 Subject: [PATCH 012/100] [IMP] need action & mails bzr revid: fp@openerp.com-20120819145928-5bw5lo6dn4ni4gl7 --- openerp/addons/base/ir/ir.xml | 24 --- openerp/addons/base/ir/ir_needaction.py | 183 +++--------------- openerp/addons/base/ir/ir_ui_menu.py | 19 +- .../addons/base/security/ir.model.access.csv | 1 - openerp/osv/fields.py | 15 +- openerp/osv/orm.py | 33 +--- 6 files changed, 50 insertions(+), 225 deletions(-) diff --git a/openerp/addons/base/ir/ir.xml b/openerp/addons/base/ir/ir.xml index fac2946e204..c554a8896aa 100644 --- a/openerp/addons/base/ir/ir.xml +++ b/openerp/addons/base/ir/ir.xml @@ -556,30 +556,6 @@ - - - ir.needaction_users_rel.tree - ir.needaction_users_rel - 10 - - - - - - - - - - - Need action relationships - ir.needaction_users_rel - form - tree,form - - - - - ir.ui.view diff --git a/openerp/addons/base/ir/ir_needaction.py b/openerp/addons/base/ir/ir_needaction.py index 0f28c33ded9..9112d60c1f4 100644 --- a/openerp/addons/base/ir/ir_needaction.py +++ b/openerp/addons/base/ir/ir_needaction.py @@ -19,180 +19,49 @@ # ############################################################################## -import openerp.pooler as pooler -from operator import itemgetter from osv import osv, fields -from tools.translate import _ - -class ir_needaction_users_rel(osv.Model): - ''' ir_needaction_users_rel holds data related to the needaction - mechanism inside OpenERP. A row in this model is characterized - by: - - res_model: model of the record requiring an action - - res_id: ID of the record requiring an action - - user_id: foreign key to the res.users table, to the user that has to - perform the action - This model can be seen as a many2many, linking (res_model, res_id) to users - (those whose attention is required on the record). ''' - - _name = 'ir.needaction_users_rel' - _description = 'Needaction relationship table' - _rec_name = 'id' - _order = 'id desc' - _columns = { - 'res_model': fields.char('Related Document Model', size=128, - select=1, required=True), - 'res_id': fields.integer('Related Document ID', - select=1, required=True), - 'user_id': fields.many2one('res.users', string='Related User', - ondelete='cascade', select=1, required=True), - } - - def _get_users(self, cr, uid, res_ids, res_model, context=None): - """Given res_ids of res_model, get user_ids present in table""" - rel_ids = self.search(cr, uid, [('res_model', '=', res_model), ('res_id', 'in', res_ids)], context=context) - return list(set(map(itemgetter('user_id'), self.read(cr, uid, rel_ids, ['user_id'], context=context)))) - - def create_users(self, cr, uid, res_ids, res_model, user_ids, context=None): - """Given res_ids of res_model, add user_ids to the relationship table""" - for res_id in res_ids: - for user_id in user_ids: - self.create(cr, uid, {'res_model': res_model, 'res_id': res_id, 'user_id': user_id}, context=context) - return True - - def unlink_users(self, cr, uid, res_ids, res_model, context=None): - """Given res_ids of res_model, delete all entries in the relationship table""" - to_del_ids = self.search(cr, uid, [('res_model', '=', res_model), ('res_id', 'in', res_ids)], context=context) - return self.unlink(cr, uid, to_del_ids, context=context) - - def update_users(self, cr, uid, res_ids, res_model, user_ids, context=None): - """Given res_ids of res_model, update their entries in the relationship table to user_ids""" - # read current records - cur_users = self._get_users(cr, uid, res_ids, res_model, context=context) - if len(cur_users) == len(user_ids) and all(cur_user in user_ids for cur_user in cur_users): - return True - # unlink old records - self.unlink_users(cr, uid, res_ids, res_model, context=context) - # link new records - self.create_users(cr, uid, res_ids, res_model, user_ids, context=context) - return True - class ir_needaction_mixin(osv.Model): '''Mixin class for objects using the need action feature. - - Need action feature can be used by objects having to be able to - signal that an action is required on a particular record. If in - the business logic an action must be performed by somebody, for - instance validation by a manager, this mechanism allows to set a + + Need action feature can be used by objects having to be able to + signal that an action is required on a particular record. If in + the business logic an action must be performed by somebody, for + instance validation by a manager, this mechanism allows to set a list of users asked to perform an action. - - This class wraps a class (ir.ir_needaction_users_rel) that - behaves like a many2many field. This class handles the low-level - considerations of updating relationships. Every change made on - the record calls a method that updates the relationships. - - Objects using the 'need_action' feature should override the - ``get_needaction_user_ids`` method. This methods returns a - dictionary whose keys are record ids, and values a list of user - ids, like in a many2many relationship. Therefore by defining - only one method, you can specify if an action is required by - defining the users that have to do it, in every possible - situation. - - This class also offers several global services: - - ``needaction_get_record_ids``: for the current model and uid, get - all record ids that ask this user to perform an action. This - mechanism is used for instance to display the number of pending - actions in menus, such as Leads (12) + + Objects using the 'need_action' feature should override the + ``needaction_domain_get`` method. This methods returns a + domain to filter records requiring an action for a specific user. + + This class also offers several global services: - ``needaction_get_action_count``: as ``needaction_get_record_ids`` - but returns only the number of action, not the ids (performs a + but returns only the number of action, not the ids (performs a search with count=True) + ''' - The ``ir_needaction_mixin`` class adds a calculated field - ``needaction_pending``. This function field allows to state - whether a given record has a needaction for the current user. - This is usefull if you want to customize views according to the - needaction feature. For example, you may want to set records in - bold in a list view if the current user has an action to perform - on the record. ''' - _name = 'ir.needaction_mixin' - _description = 'Need action mixin' - - def get_needaction_pending(self, cr, uid, ids, name, arg, context=None): - res = {} - needaction_user_ids = self.get_needaction_user_ids(cr, uid, ids, context=context) - for id in ids: - res[id] = uid in needaction_user_ids[id] - return res + _needaction = True - def search_needaction_pending(self, cr, uid, self_again, field_name, criterion, context=None): - ids = self.needaction_get_record_ids( - cr, uid, uid, limit=1024, context=context) - return [('id', 'in', ids)] - - _columns = { - 'needaction_pending': fields.function( - get_needaction_pending, type='boolean', - fnct_search=search_needaction_pending, - string='Need action pending', - help="If True, this field states that users have to perform an " \ - "action This field comes from the ir.needaction_mixin class."), - } - #------------------------------------------------------ # Addon API #------------------------------------------------------ - - def get_needaction_user_ids(self, cr, uid, ids, context=None): - """ Returns the user_ids that have to perform an action - :return: dict { record_id: [user_ids], } + + def _needaction_domain_get(self, cr, uid, context=None): + """ Returns the domain to filter records that require an action + :return: domain or False is no need action """ - return dict((id,list()) for id in ids) - - def create(self, cr, uid, values, context=None): - rel_obj = self.pool.get('ir.needaction_users_rel') - # perform create - obj_id = super(ir_needaction_mixin, self).create(cr, uid, values, context=context) - # link user_ids - needaction_user_ids = self.get_needaction_user_ids(cr, uid, [obj_id], context=context) - rel_obj.create_users(cr, uid, [obj_id], self._name, needaction_user_ids[obj_id], context=context) - return obj_id - - def write(self, cr, uid, ids, values, context=None): - rel_obj = self.pool.get('ir.needaction_users_rel') - # perform write - write_res = super(ir_needaction_mixin, self).write(cr, uid, ids, values, context=context) - # get and update user_ids - needaction_user_ids = self.get_needaction_user_ids(cr, uid, ids, context=context) - for id in ids: - rel_obj.update_users(cr, uid, [id], self._name, needaction_user_ids[id], context=context) - return write_res - - def unlink(self, cr, uid, ids, context=None): - # unlink user_ids - rel_obj = self.pool.get('ir.needaction_users_rel') - rel_obj.unlink_users(cr, uid, ids, self._name, context=context) - # perform unlink - return super(ir_needaction_mixin, self).unlink(cr, uid, ids, context=context) - + return False + #------------------------------------------------------ # "Need action" API #------------------------------------------------------ - - def needaction_get_record_ids(self, cr, uid, user_id, limit=80, context=None): - """Given the current model and a user_id - return the record ids that require the user to perform an - action""" - rel_obj = self.pool.get('ir.needaction_users_rel') - rel_ids = rel_obj.search(cr, uid, [('res_model', '=', self._name), ('user_id', '=', user_id)], limit=limit, context=context) - return map(itemgetter('res_id'), rel_obj.read(cr, uid, rel_ids, ['res_id'], context=context)) - - def needaction_get_action_count(self, cr, uid, user_id, limit=80, context=None): + + def _needaction_count(self, cr, uid, domain=[], context=None): """Given the current model and a user_id get the number of actions it has to perform""" - rel_obj = self.pool.get('ir.needaction_users_rel') - return rel_obj.search(cr, uid, [('res_model', '=', self._name), ('user_id', '=', user_id)], limit=limit, count=True, context=context) + dom = self._needaction_domain_get(cr, uid, context=context) + if dom is False: + return 0 + return self.search(cr, uid, domain+dom, context=context, count=True) -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py index 77c0c4d738a..f5e4ee2ba05 100644 --- a/openerp/addons/base/ir/ir_ui_menu.py +++ b/openerp/addons/base/ir/ir_ui_menu.py @@ -255,23 +255,24 @@ class ir_ui_menu(osv.osv): return res - def _get_needaction_info(self, cr, uid, id, domain=[], context={}): - return [False, 0] - def _get_needaction(self, cr, uid, ids, field_names, args, context=None): if context is None: context = {} res = {} for menu in self.browse(cr, uid, ids, context=context): + res[menu.id] = {} + res[menu.id]['needaction_enabled'] = False + res[menu.id]['needaction_counter'] = False res[menu.id] = {} if menu.action and menu.action.type == 'ir.actions.act_window' and menu.action.res_model: - menu_needaction_res = self.pool.get(menu.action.res_model)._get_needaction_info(cr, uid, uid, domain=menu.action.domain, context=context) - else: - menu_needaction_res = [False, 0] - res[menu.id]['needaction_enabled'] = menu_needaction_res[0] - res[menu.id]['needaction_counter'] = menu_needaction_res[1] + obj = self.pool.get(menu.action.res_model) + if obj._needaction: + res[menu.id]['needaction_enabled'] = obj._needaction + # check domain and context: should we evaluate the domain ? + # and add context of the action ? + res[menu.id]['needaction_counter'] = obj._needaction_count(cr, uid, menu.action.domain, context=context) return res - + _columns = { 'name': fields.char('Menu', size=64, required=True, translate=True), 'sequence': fields.integer('Sequence'), diff --git a/openerp/addons/base/security/ir.model.access.csv b/openerp/addons/base/security/ir.model.access.csv index d49aa18db8c..b0218e977bc 100644 --- a/openerp/addons/base/security/ir.model.access.csv +++ b/openerp/addons/base/security/ir.model.access.csv @@ -118,6 +118,5 @@ "access_ir_config_parameter","ir_config_parameter","model_ir_config_parameter",,1,0,0,0 "access_ir_mail_server_all","ir_mail_server","model_ir_mail_server",,1,0,0,0 "access_ir_actions_client","ir_actions_client all","model_ir_actions_client",,1,0,0,0 -"access_ir_needaction_users_rel","ir_needaction_users_rel","model_ir_needaction_users_rel",,1,1,1,1 "access_ir_needaction_mixin","ir_needaction_mixin","model_ir_needaction_mixin",,1,1,1,1 diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 5a47601f8a5..da025845759 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -514,7 +514,10 @@ class one2many(_column): for id in ids: res[id] = [] - ids2 = obj.pool.get(self._obj).search(cr, user, self._domain + [(self._fields_id, 'in', ids)], limit=self._limit, context=context) + dom = self._domain + if isinstance(self._domain, type(lambda: None)): + dom = self._domain(obj) + ids2 = obj.pool.get(self._obj).search(cr, user, dom + [(self._fields_id, 'in', ids)], limit=self._limit, context=context) for r in obj.pool.get(self._obj)._read_flat(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'): if r[self._fields_id] in res: res[r[self._fields_id]].append(r['id']) @@ -556,7 +559,10 @@ class one2many(_column): reverse_rel = obj._all_columns.get(self._fields_id) assert reverse_rel, 'Trying to unlink the content of a o2m but the pointed model does not have a m2o' # if the o2m has a static domain we must respect it when unlinking - extra_domain = self._domain if isinstance(getattr(self, '_domain', None), list) else [] + dom = self._domain + if isinstance(self._domain, type(lambda: None)): + dom = self._domain(obj) + extra_domain = dom or [] ids_to_unlink = obj.search(cr, user, [(self._fields_id,'=',id)] + extra_domain, context=context) # If the model has cascade deletion, we delete the rows because it is the intended behavior, # otherwise we only nullify the reverse foreign key column. @@ -574,7 +580,10 @@ class one2many(_column): return result def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, operator='like', context=None): - return obj.pool.get(self._obj).name_search(cr, uid, value, self._domain, operator, context=context,limit=limit) + dom = self._domain + if isinstance(self._domain, type(lambda: None)): + dom = self._domain(obj) + return obj.pool.get(self._obj).name_search(cr, uid, value, dom, operator, context=context,limit=limit) @classmethod diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 7c8085ea8ed..368a37f455a 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -666,6 +666,7 @@ class BaseModel(object): _order = 'id' _sequence = None _description = None + _needaction = False # dict of {field:method}, with method returning the name_get of records # to include in the _read_group, if grouped on this field @@ -4960,37 +4961,7 @@ class BaseModel(object): # backwards compatibility get_xml_id = get_external_id _get_xml_ids = _get_external_ids - - def _get_needaction_info(self, cr, uid, user_id, limit=None, order=None, domain=False, context=None): - """Base method for needaction mechanism - - see ir.needaction for actual implementation - - if the model uses the need action mechanism - (hasattr(model_obj, 'needaction_get_record_ids')): - - get the record ids on which the user has actions to perform - - evaluate the menu domain - - compose a new domain: menu domain, limited to ids of - records requesting an action - - count the number of records maching that domain, that - is the number of actions the user has to perform - - this method returns default values - :param: model_name: the name of the model (ex: hr.holidays) - :param: user_id: the id of user - :return: [uses_needaction=True/False, needaction_uid_ctr=%d] - """ - if hasattr(self, 'needaction_get_record_ids'): - # Arbitrary limit, but still much lower thant infinity, to avoid - # getting too much data. - ids = self.needaction_get_record_ids(cr, uid, user_id, limit=8192, context=context) - if not ids: - return [True, 0] - if domain: - new_domain = eval(domain, locals_dict={'uid': user_id}) + [('id', 'in', ids)] - else: - new_domain = [('id', 'in', ids)] - return [True, self.search(cr, uid, new_domain, limit=limit, order=order, count=True, context=context)] - else: - return [False, 0] - + # Transience def is_transient(self): """ Return whether the model is transient. From 6021b4473aa0b5cdf436e61320ffcba503de53f3 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Mon, 20 Aug 2012 12:52:52 +0200 Subject: [PATCH 013/100] [IMP] message_read on mail.message bzr revid: fp@tinyerp.com-20120820105252-o1eqy5yfqb66hga9 --- openerp/osv/fields.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index da025845759..496aab5407b 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -517,6 +517,7 @@ class one2many(_column): dom = self._domain if isinstance(self._domain, type(lambda: None)): dom = self._domain(obj) + print self._obj, user, dom + [(self._fields_id, 'in', ids)] ids2 = obj.pool.get(self._obj).search(cr, user, dom + [(self._fields_id, 'in', ids)], limit=self._limit, context=context) for r in obj.pool.get(self._obj)._read_flat(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'): if r[self._fields_id] in res: From 20981ac1a30cf05f82f2467b65664931b5ebf579 Mon Sep 17 00:00:00 2001 From: "Ajay Chauhan (OpenERP)" Date: Mon, 20 Aug 2012 16:29:42 +0530 Subject: [PATCH 014/100] [IMP] account: make little change in onchange method. bzr revid: cha@tinyerp.com-20120820105942-zkyrqrebn3s3j9nc --- addons/account/wizard/account_report_common.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/account/wizard/account_report_common.py b/addons/account/wizard/account_report_common.py index f84c4e909a2..604806f6e31 100644 --- a/addons/account/wizard/account_report_common.py +++ b/addons/account/wizard/account_report_common.py @@ -30,11 +30,11 @@ class account_common_report(osv.osv_memory): _description = "Account Common Report" def onchange_chart_id(self, cr, uid, ids, chart_account_id=False, context=None): + res = {} if chart_account_id: company_id = self.pool.get('account.account').browse(cr, uid, chart_account_id, context=context).company_id.id - else: - return {'value': {'company_id': False}} - return {'value': {'company_id': company_id}} + res['value'] = {'company_id': company_id} + return res _columns = { 'chart_account_id': fields.many2one('account.account', 'Chart of Account', help='Select Charts of Accounts', required=True, domain = [('parent_id','=',False)]), From a054299277113f1ae09f47b0cd52f9752ef10a82 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Mon, 20 Aug 2012 13:04:55 +0200 Subject: [PATCH 015/100] imp bzr revid: fp@tinyerp.com-20120820110455-jelu0xl7jil36q18 --- openerp/osv/fields.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 496aab5407b..da025845759 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -517,7 +517,6 @@ class one2many(_column): dom = self._domain if isinstance(self._domain, type(lambda: None)): dom = self._domain(obj) - print self._obj, user, dom + [(self._fields_id, 'in', ids)] ids2 = obj.pool.get(self._obj).search(cr, user, dom + [(self._fields_id, 'in', ids)], limit=self._limit, context=context) for r in obj.pool.get(self._obj)._read_flat(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'): if r[self._fields_id] in res: From 25233cd5137255f707f6830f720b2ca76f6567aa Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Mon, 20 Aug 2012 13:32:27 +0200 Subject: [PATCH 016/100] [IMP] add user_ids on partners bzr revid: fp@tinyerp.com-20120820113227-5k9d7m41vjcof26c --- openerp/addons/base/res/res_partner.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 93d12228ebe..d9ae1d8595e 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -215,6 +215,7 @@ class res_partner(osv.osv): "Use this field anywhere a small image is required."), 'company_id': fields.many2one('res.company', 'Company', select=1), 'color': fields.integer('Color Index'), + 'user_ids': fields.one2many('res.users', 'partner_id', 'Users'), 'contact_address': fields.function(_address_display, type='char', string='Complete Address'), } From 0d5a185956cefd92b4b2825d0cb78e27376bd5a2 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Mon, 20 Aug 2012 15:17:26 +0200 Subject: [PATCH 017/100] fix bzr revid: fp@tinyerp.com-20120820131726-7iassml4p93z7qsg --- openerp/osv/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index da025845759..4e5d8e97691 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -1553,7 +1553,7 @@ def field_to_dict(model, cr, user, field, context=None): # when client is started in debug mode. if isinstance(field, function): res['function'] = field._fnct and field._fnct.func_name or False - res['store'] = field.store + # res['store'] = field.store if isinstance(field.store, dict): res['store'] = str(field.store) res['fnct_search'] = field._fnct_search and field._fnct_search.func_name or False From 1bd841d10109ddcaebfde5bbf79a1b24fa6ac82f Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Mon, 20 Aug 2012 15:19:21 +0200 Subject: [PATCH 018/100] fix bzr revid: fp@tinyerp.com-20120820131921-7ydvs9x784t4hn4l --- openerp/osv/fields.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 4e5d8e97691..57c84d6a5a8 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -1554,8 +1554,8 @@ def field_to_dict(model, cr, user, field, context=None): if isinstance(field, function): res['function'] = field._fnct and field._fnct.func_name or False # res['store'] = field.store - if isinstance(field.store, dict): - res['store'] = str(field.store) + # if isinstance(field.store, dict): + # res['store'] = str(field.store) res['fnct_search'] = field._fnct_search and field._fnct_search.func_name or False res['fnct_inv'] = field._fnct_inv and field._fnct_inv.func_name or False res['fnct_inv_arg'] = field._fnct_inv_arg or False From 64dc05afc658e318aaa3724827daca0b6a8d2a14 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Mon, 20 Aug 2012 15:25:01 +0200 Subject: [PATCH 019/100] fix bzr revid: fp@tinyerp.com-20120820132501-7724jwavhzan3xyp --- openerp/osv/fields.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 57c84d6a5a8..b996d66035f 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -1585,6 +1585,9 @@ def field_to_dict(model, cr, user, field, context=None): res['selection'] = field.selection(model, cr, user, context) if res['type'] in ('one2many', 'many2many', 'many2one'): res['relation'] = field._obj + dom = field._domain + if isinstance(field._domain, type(lambda: None)): + dom = field._domain(model) res['domain'] = field._domain res['context'] = field._context From f21f1a68aace85dca8deef197a0d2f46d77d2146 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Mon, 20 Aug 2012 15:29:09 +0200 Subject: [PATCH 020/100] fix bzr revid: fp@tinyerp.com-20120820132909-iw8faaon2z4c5e77 --- openerp/osv/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index b996d66035f..27a3f2d8814 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -1588,7 +1588,7 @@ def field_to_dict(model, cr, user, field, context=None): dom = field._domain if isinstance(field._domain, type(lambda: None)): dom = field._domain(model) - res['domain'] = field._domain + res['domain'] = dom res['context'] = field._context if isinstance(field, one2many): From 1937247840f50a4333c5618c538a27253573b06f Mon Sep 17 00:00:00 2001 From: "Mayur Maheshwari (OpenERP)" Date: Tue, 21 Aug 2012 11:21:50 +0530 Subject: [PATCH 021/100] [IMP]hr_timesheet_sheet :improve name_get method bzr revid: mma@tinyerp.com-20120821055150-60n2k2fva99mqi9m --- addons/hr_timesheet_sheet/hr_timesheet_sheet.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py index b2ef41f3a46..f2a5df1ba0c 100644 --- a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py +++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py @@ -442,9 +442,7 @@ class hr_timesheet_sheet(osv.osv): return True def name_get(self, cr, uid, ids, context=None): - if not ids: - return [] - if isinstance(ids, (int)): + if ids and isinstance(ids, int): ids = [ids] return [(r['id'], r['date_from'] + ' - ' + r['date_to']) \ for r in self.read(cr, uid, ids, ['date_from', 'date_to'], From 6c337bcd64b53f234872d9f7026f342755de9c60 Mon Sep 17 00:00:00 2001 From: "Mayur Maheshwari (OpenERP)" Date: Tue, 21 Aug 2012 14:37:50 +0530 Subject: [PATCH 022/100] [IMP]hr_timesheet_sheet :improved as per ids bzr revid: mma@tinyerp.com-20120821090750-zkr0loqnmslqslcr --- addons/hr_timesheet_sheet/hr_timesheet_sheet.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py index f2a5df1ba0c..7a7e05a80e0 100644 --- a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py +++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py @@ -442,7 +442,9 @@ class hr_timesheet_sheet(osv.osv): return True def name_get(self, cr, uid, ids, context=None): - if ids and isinstance(ids, int): + if not ids: + return [] + if isinstance(ids, int): ids = [ids] return [(r['id'], r['date_from'] + ' - ' + r['date_to']) \ for r in self.read(cr, uid, ids, ['date_from', 'date_to'], From b772da168f7e8e6e6539ac4e867dc1a2e25b7a82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 21 Aug 2012 17:14:13 +0200 Subject: [PATCH 023/100] [FIX] tools: emails_split -> email-split. bzr revid: tde@openerp.com-20120821151413-9hxmsyp51q3ny32f --- openerp/tools/misc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py index 7f2dade30d8..8ca90e32f07 100644 --- a/openerp/tools/misc.py +++ b/openerp/tools/misc.py @@ -1113,7 +1113,7 @@ class unquote(str): def __repr__(self): return self -def emails_split(text): +def email_split(text): """Return a list of the email addresses found in ``text``""" if not text: return [] return re.findall(r'([^ ,<@]+@[^> ,]+)', text) From d876320e12b80a229bc97b3d2df35858f6812521 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Tue, 21 Aug 2012 17:45:55 +0200 Subject: [PATCH 024/100] [FIX] allows using uid in domains of params bzr revid: fp@tinyerp.com-20120821154555-gjsw2pr5ykbl0ed5 --- openerp/addons/base/ir/ir_actions.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/openerp/addons/base/ir/ir_actions.py b/openerp/addons/base/ir/ir_actions.py index a5d04d7f1bc..28a309f427a 100644 --- a/openerp/addons/base/ir/ir_actions.py +++ b/openerp/addons/base/ir/ir_actions.py @@ -860,11 +860,10 @@ class act_client(osv.osv): _order = 'name' def _get_params(self, cr, uid, ids, field_name, arg, context): - return dict([ - ((record.id, ast.literal_eval(record.params_store)) - if record.params_store else (record.id, False)) - for record in self.browse(cr, uid, ids, context=context) - ]) + result = {} + for record in self.browse(cr, uid, ids, context=context): + result[record.id] = record.params_store and eval(record.params_store, {'uid': uid}) or False + return result def _set_params(self, cr, uid, id, field_name, field_value, arg, context): if isinstance(field_value, dict): From e88e21bb569d9ce086bf03285aa4141dc28f0c58 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Tue, 21 Aug 2012 19:24:14 +0200 Subject: [PATCH 025/100] fix bzr revid: fp@tinyerp.com-20120821172414-7kz7qcibjile1dfl --- openerp/addons/base/res/res_partner_view.xml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/openerp/addons/base/res/res_partner_view.xml b/openerp/addons/base/res/res_partner_view.xml index 43a37d1a79c..6e2e8fac178 100644 --- a/openerp/addons/base/res/res_partner_view.xml +++ b/openerp/addons/base/res/res_partner_view.xml @@ -186,13 +186,10 @@

-
- - - - - - + + From 4215827f24fa8909777387b8be55ff90755b5e40 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Tue, 21 Aug 2012 20:04:09 +0200 Subject: [PATCH 026/100] [IMP] better implementation of name_create bzr revid: fp@tinyerp.com-20120821180409-gk2c3odfve53epdp --- openerp/addons/base/res/res_partner.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index d9ae1d8595e..30255d93ec3 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -366,22 +366,14 @@ class res_partner(osv.osv): - ([\w\s.\\-]+)[\<]([a-zA-Z0-9._%-]+@[a-zA-Z0-9_-]+\.[a-zA-Z0-9._]{1,8})[\>]: Raoul Grosbedon, raoul@grosbedon.fr """ - contact_regex = re.compile('([\w\s.\\-]+)[\<]([a-zA-Z0-9._%-]+@[a-zA-Z0-9_-]+\.[a-zA-Z0-9._]{1,8})[\>]') - email_regex = re.compile('([a-zA-Z0-9._%-]+@[a-zA-Z0-9_-]+\.[a-zA-Z0-9._]{1,8})') - contact_regex_res = contact_regex.findall(name) - email_regex_res = email_regex.findall(name) - if contact_regex_res: - name = contact_regex_res[0][0].rstrip(' ') # remove extra spaces on the right - email = contact_regex_res[0][1] - rec_id = self.create(cr, uid, {self._rec_name: name, 'email': email}, context); - return self.name_get(cr, uid, [rec_id], context)[0] - elif email_regex_res: - email = '%s' % (email_regex_res[0]) - rec_id = self.create(cr, uid, {self._rec_name: email, 'email': email}, context); - return self.name_get(cr, uid, [rec_id], context)[0] - else: - rec_id = super(res_partner, self).create(cr, uid, {self._rec_name: name}, context) - return self.name_get(cr, uid, [rec_id], context)[0] + regex = re.compile('^(.*?)(?: ?[\<]?([a-zA-Z0-9._%-]+@[a-zA-Z0-9_-]+\.[a-zA-Z0-9._]{1,8})[\>]?)?$') + result = regex.match(name) + if not result or (context.get('force_create',False) and result.group(2) is None): + raise osv.except_osv(_('Warning'), _("Couldn't create contact without email address !")) + name = result.group(1).strip() + email = result.group(2) + rec_id = self.create(cr, uid, {self._rec_name: name or email, 'email': email or False}, context=context) + return self.name_get(cr, uid, [rec_id], context)[0] def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=100): if not args: From 8bf884d2b698dae61f00814768259d6e6fe6a3c7 Mon Sep 17 00:00:00 2001 From: "Nimesh (Open ERP)" Date: Wed, 22 Aug 2012 11:20:23 +0530 Subject: [PATCH 027/100] [FIX] set the menu for base.menu_definitions bzr revid: nco@tinyerp.com-20120822055023-4y39imx6dhwyjqsi --- addons/crm_claim/crm_claim_menu.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/crm_claim/crm_claim_menu.xml b/addons/crm_claim/crm_claim_menu.xml index 46f8760387a..bb881d62a58 100644 --- a/addons/crm_claim/crm_claim_menu.xml +++ b/addons/crm_claim/crm_claim_menu.xml @@ -50,9 +50,9 @@ parent="base.menu_aftersale" action="crm_case_categ_claim0" sequence="1"/> + - From 4d0937e9a642b31183dfbc0cd963b95411d536cb Mon Sep 17 00:00:00 2001 From: "Jignesh Rathod (Open ERP)" Date: Wed, 22 Aug 2012 12:39:28 +0530 Subject: [PATCH 028/100] [FIX] Fixes the problem of Iteration is not allowed on browse_record lp bug: https://launchpad.net/bugs/1039899 fixed bzr revid: jir@tinyerp.com-20120822070928-hfqz8s9du89ib03d --- addons/event/event.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addons/event/event.py b/addons/event/event.py index 7f0c77661e4..004b370f48e 100644 --- a/addons/event/event.py +++ b/addons/event/event.py @@ -52,10 +52,13 @@ class event_event(osv.osv): _inherit = ['ir.needaction_mixin','mail.thread'] def name_get(self, cr, uid, ids, context=None): + event_obj = self.browse(cr, uid, ids, context=context) if not ids: return [] + if not isinstance(event_obj,list): + event_obj = [event_obj] res = [] - for record in self.browse(cr, uid, ids, context=context): + for record in event_obj: date = record.date_begin.split(" ")[0] date_end = record.date_end.split(" ")[0] if date != date_end: From e46c8e43ff588ba4a7b0d902527cdf3011efed9d Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Wed, 22 Aug 2012 12:37:25 +0200 Subject: [PATCH 029/100] [IMP] Removing a bad practice: - what happens if you overwrite check_read and modules calls check_access_rights ? - 5 methods to learn to understand the API insead of one bzr revid: fp@tinyerp.com-20120822103725-vdubhkzlake2jyvo --- openerp/osv/orm.py | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 368a37f455a..e8f59e50cbd 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -2346,7 +2346,7 @@ class BaseModel(object): def read_string(self, cr, uid, id, langs, fields=None, context=None): res = {} res2 = {} - self.pool.get('ir.translation').check_read(cr, uid) + self.pool.get('ir.translation').check_access_rights(cr, uid, 'read') if not fields: fields = self._columns.keys() + self._inherit_fields.keys() #FIXME: collect all calls to _get_source into one SQL call. @@ -2370,7 +2370,7 @@ class BaseModel(object): return res def write_string(self, cr, uid, id, langs, vals, context=None): - self.pool.get('ir.translation').check_write(cr, uid) + self.pool.get('ir.translation').check_access_rights(cr, uid, 'write') #FIXME: try to only call the translation in one SQL for lang in langs: for field in vals: @@ -2518,7 +2518,7 @@ class BaseModel(object): """ context = context or {} - self.check_read(cr, uid) + self.check_access_rights(cr, uid, 'read') if not fields: fields = self._columns.keys() @@ -3399,8 +3399,7 @@ class BaseModel(object): if context is None: context = {} - write_access = self.check_write(cr, user, False) or \ - self.check_create(cr, user, False) + write_access = self.check_access_rights(cr, user, 'write') or self.check_access_rights(cr, user, 'create') res = {} @@ -3464,7 +3463,7 @@ class BaseModel(object): if not context: context = {} - self.check_read(cr, user) + self.check_access_rights(cr, user, 'read') if not fields: fields = list(set(self._columns.keys() + self._inherit_fields.keys())) if isinstance(ids, (int, long)): @@ -3738,18 +3737,6 @@ class BaseModel(object): according to the access rights.""" return self.pool.get('ir.model.access').check(cr, uid, self._name, operation, raise_exception) - def check_create(self, cr, uid, raise_exception=True): - return self.check_access_rights(cr, uid, 'create', raise_exception) - - def check_read(self, cr, uid, raise_exception=True): - return self.check_access_rights(cr, uid, 'read', raise_exception) - - def check_unlink(self, cr, uid, raise_exception=True): - return self.check_access_rights(cr, uid, 'unlink', raise_exception) - - def check_write(self, cr, uid, raise_exception=True): - return self.check_access_rights(cr, uid, 'write', raise_exception) - def check_access_rule(self, cr, uid, ids, operation, context=None): """Verifies that the operation given by ``operation`` is allowed for the user according to ir.rules. @@ -3813,7 +3800,7 @@ class BaseModel(object): self._check_concurrency(cr, ids, context) - self.check_unlink(cr, uid) + self.check_access_rights(cr, uid, 'unlink') ir_property = self.pool.get('ir.property') @@ -3949,7 +3936,7 @@ class BaseModel(object): ids = [ids] self._check_concurrency(cr, ids, context) - self.check_write(cr, user) + self.check_access_rights(cr, user, 'write') result = self._store_get_values(cr, user, ids, vals.keys(), context) or [] @@ -4169,7 +4156,7 @@ class BaseModel(object): if self.is_transient(): self._transient_vacuum(cr, user) - self.check_create(cr, user) + self.check_access_rights(cr, user, 'create') if self._log_access: for f in LOG_ACCESS_COLUMNS: @@ -4661,7 +4648,7 @@ class BaseModel(object): """ if context is None: context = {} - self.check_read(cr, access_rights_uid or user) + self.check_access_rights(cr, access_rights_uid or user, 'read') # For transient models, restrict acces to the current user, except for the super-user if self.is_transient() and self._log_access and user != SUPERUSER_ID: From 9871b2dd370c61052844ed79bc3de20a12c03adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 22 Aug 2012 13:16:13 +0200 Subject: [PATCH 030/100] [FIX] Fixed last commit, about removing check_read/write/unlink/create: those methods were used, propagated the changes :) . bzr revid: tde@openerp.com-20120822111613-305j77rs4fphkjts --- openerp/addons/base/ir/ir_sequence.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py index e3136b92b6e..8b03cd3f3b3 100644 --- a/openerp/addons/base/ir/ir_sequence.py +++ b/openerp/addons/base/ir/ir_sequence.py @@ -210,7 +210,7 @@ class ir_sequence(openerp.osv.osv.osv): def next_by_id(self, cr, uid, sequence_id, context=None): """ Draw an interpolated string using the specified sequence.""" - self.check_read(cr, uid) + self.check_access_rights(cr, uid, 'read') company_ids = self.pool.get('res.company').search(cr, uid, [], order='company_id', context=context) + [False] ids = self.search(cr, uid, ['&',('id','=', sequence_id),('company_id','in',company_ids)]) return self._next(cr, uid, ids, context) @@ -227,7 +227,7 @@ class ir_sequence(openerp.osv.osv.osv): sequence selection. A matching sequence for that specific company will get higher priority. """ - self.check_read(cr, uid) + self.check_access_rights(cr, uid, 'read') company_ids = self.pool.get('res.company').search(cr, uid, [], order='company_id', context=context) + [False] ids = self.search(cr, uid, ['&',('code','=', sequence_code),('company_id','in',company_ids)]) return self._next(cr, uid, ids, context) From 0f63b4a1fb8a41971d1fd6a9810a75a7af5de759 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Wed, 22 Aug 2012 15:34:06 +0200 Subject: [PATCH 031/100] [IMP] need action bzr revid: fp@tinyerp.com-20120822133406-9ayg228mxfeg16dg --- openerp/addons/base/ir/ir_actions.py | 4 +++- openerp/addons/base/ir/ir_ui_menu.py | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openerp/addons/base/ir/ir_actions.py b/openerp/addons/base/ir/ir_actions.py index 28a309f427a..b70a9d89c06 100644 --- a/openerp/addons/base/ir/ir_actions.py +++ b/openerp/addons/base/ir/ir_actions.py @@ -43,7 +43,6 @@ class actions(osv.osv): _table = 'ir_actions' _order = 'name' _columns = { - 'name': fields.char('Action Name', required=True, size=64), 'type': fields.char('Action Type', required=True, size=32,readonly=True), 'usage': fields.char('Action Usage', size=32), } @@ -872,10 +871,13 @@ class act_client(osv.osv): self.write(cr, uid, id, {'params_store': field_value}, context=context) _columns = { + 'name': fields.char('Action Name', required=True, size=64, translate=True), 'tag': fields.char('Client action tag', size=64, required=True, help="An arbitrary string, interpreted by the client" " according to its own needs and wishes. There " "is no central tag repository across clients."), + 'res_model': fields.char('Destination Model', size=64, + help="Optional model, mostly used for needactions."), 'params': fields.function(_get_params, fnct_inv=_set_params, type='binary', string="Supplementary arguments", diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py index f5e4ee2ba05..bc743d34fc0 100644 --- a/openerp/addons/base/ir/ir_ui_menu.py +++ b/openerp/addons/base/ir/ir_ui_menu.py @@ -264,12 +264,10 @@ class ir_ui_menu(osv.osv): res[menu.id]['needaction_enabled'] = False res[menu.id]['needaction_counter'] = False res[menu.id] = {} - if menu.action and menu.action.type == 'ir.actions.act_window' and menu.action.res_model: + if menu.action and menu.action.type in ('ir.actions.act_window','ir.actions.client') and menu.action.res_model: obj = self.pool.get(menu.action.res_model) if obj._needaction: res[menu.id]['needaction_enabled'] = obj._needaction - # check domain and context: should we evaluate the domain ? - # and add context of the action ? res[menu.id]['needaction_counter'] = obj._needaction_count(cr, uid, menu.action.domain, context=context) return res From 9d6ee746eb4e29ea7dca76ef8c836d71374d6186 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Wed, 22 Aug 2012 15:41:09 +0200 Subject: [PATCH 032/100] fix bzr revid: fp@tinyerp.com-20120822134109-97lbhcllylbe15ce --- openerp/addons/base/ir/ir_actions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openerp/addons/base/ir/ir_actions.py b/openerp/addons/base/ir/ir_actions.py index b70a9d89c06..cf67e6fcf88 100644 --- a/openerp/addons/base/ir/ir_actions.py +++ b/openerp/addons/base/ir/ir_actions.py @@ -43,6 +43,7 @@ class actions(osv.osv): _table = 'ir_actions' _order = 'name' _columns = { + 'name': fields.char('Name', size=64, required=True), 'type': fields.char('Action Type', required=True, size=32,readonly=True), 'usage': fields.char('Action Usage', size=32), } From 552705494c11c53d81671766e608f830e773df96 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Wed, 22 Aug 2012 18:14:07 +0200 Subject: [PATCH 033/100] [IMP] needaction bzr revid: fp@tinyerp.com-20120822161407-aucl1m2jsa3pe6sv --- openerp/addons/base/ir/ir_needaction.py | 3 ++- openerp/addons/base/ir/ir_ui_menu.py | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/ir/ir_needaction.py b/openerp/addons/base/ir/ir_needaction.py index caf099c18cd..1e59a6fbb8e 100644 --- a/openerp/addons/base/ir/ir_needaction.py +++ b/openerp/addons/base/ir/ir_needaction.py @@ -63,5 +63,6 @@ class ir_needaction_mixin(osv.Model): dom = self._needaction_domain_get(cr, uid, context=context) if dom is False: return 0 - return self.search(cr, uid, (domain or []) +dom, context=context, count=True) + result = self.search(cr, uid, (domain or []) +dom, context=context, count=True) + return result diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py index bc743d34fc0..eefa8ea4a50 100644 --- a/openerp/addons/base/ir/ir_ui_menu.py +++ b/openerp/addons/base/ir/ir_ui_menu.py @@ -24,6 +24,8 @@ import base64 import re import threading +from tools.safe_eval import safe_eval as eval + import tools import openerp.modules from osv import fields, osv @@ -268,7 +270,7 @@ class ir_ui_menu(osv.osv): obj = self.pool.get(menu.action.res_model) if obj._needaction: res[menu.id]['needaction_enabled'] = obj._needaction - res[menu.id]['needaction_counter'] = obj._needaction_count(cr, uid, menu.action.domain, context=context) + res[menu.id]['needaction_counter'] = obj._needaction_count(cr, uid, menu.action.domain and eval(menu.action.domain), context=context) return res _columns = { From e7a5fcd896c84d5b93f9ac463335690d75780e2f Mon Sep 17 00:00:00 2001 From: "Turkesh Patel (Open ERP)" Date: Thu, 23 Aug 2012 15:11:11 +0530 Subject: [PATCH 034/100] [FIX] Improved code to encode accented char. bzr revid: tpa@tinyerp.com-20120823094111-vph3jpaxb29hoqqm --- addons/stock/report/stock_graph.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/stock/report/stock_graph.py b/addons/stock/report/stock_graph.py index b5d08f93d3f..d92de2805b5 100644 --- a/addons/stock/report/stock_graph.py +++ b/addons/stock/report/stock_graph.py @@ -22,7 +22,7 @@ from pychart import * import pychart.legend import time from report.misc import choice_colors -import base64 +import tools # # Draw a graph for stocks @@ -42,7 +42,7 @@ class stock_graph(object): product_name=product_name.replace('/', '//') if product_id not in self._datas: self._datas[product_id] = {} - self._names[product_id] = product_name.decode('utf-8') + self._names[product_id] = tools.ustr(product_name) for (dt,stock) in datas: if not dt in self._datas[product_id]: self._datas[product_id][dt]=0 From 84625969c0a724e0374f21f527ce9a04339ebbee Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Thu, 23 Aug 2012 16:35:25 +0200 Subject: [PATCH 035/100] [FIX] needaction on mail.groups bzr revid: fp@tinyerp.com-20120823143525-28mnbgd015jd8yyd --- openerp/addons/base/ir/ir_actions.py | 3 +++ openerp/addons/base/ir/ir_ui_menu.py | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/openerp/addons/base/ir/ir_actions.py b/openerp/addons/base/ir/ir_actions.py index cf67e6fcf88..6f906f5c416 100644 --- a/openerp/addons/base/ir/ir_actions.py +++ b/openerp/addons/base/ir/ir_actions.py @@ -879,6 +879,8 @@ class act_client(osv.osv): "is no central tag repository across clients."), 'res_model': fields.char('Destination Model', size=64, help="Optional model, mostly used for needactions."), + 'context': fields.char('Context Value', size=250, required=True, + help="Context dictionary as Python expression, empty by default (Default: {})"), 'params': fields.function(_get_params, fnct_inv=_set_params, type='binary', string="Supplementary arguments", @@ -888,6 +890,7 @@ class act_client(osv.osv): } _defaults = { 'type': 'ir.actions.client', + 'context': '{}', } act_client() diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py index eefa8ea4a50..05523faa550 100644 --- a/openerp/addons/base/ir/ir_ui_menu.py +++ b/openerp/addons/base/ir/ir_ui_menu.py @@ -269,8 +269,13 @@ class ir_ui_menu(osv.osv): if menu.action and menu.action.type in ('ir.actions.act_window','ir.actions.client') and menu.action.res_model: obj = self.pool.get(menu.action.res_model) if obj._needaction: + dom = [] + if menu.action.type=='ir.actions.act_window': + dom = menu.action.domain and eval(menu.action.domain, {'uid': uid}) or [] + else: + dom = eval(menu.action.params_store or '{}', {'uid': uid}).get('domain') res[menu.id]['needaction_enabled'] = obj._needaction - res[menu.id]['needaction_counter'] = obj._needaction_count(cr, uid, menu.action.domain and eval(menu.action.domain), context=context) + res[menu.id]['needaction_counter'] = obj._needaction_count(cr, uid, dom, context=context) return res _columns = { From f386e2de33edd9571755275208ab640c55e097e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 27 Aug 2012 12:18:07 +0200 Subject: [PATCH 036/100] [IMP] base demo data: added a partner for demo user. bzr revid: tde@openerp.com-20120827101807-wop2m7fdfgkyh0e7 --- openerp/addons/base/base_demo.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/openerp/addons/base/base_demo.xml b/openerp/addons/base/base_demo.xml index 34feb3af990..064b1f49e69 100644 --- a/openerp/addons/base/base_demo.xml +++ b/openerp/addons/base/base_demo.xml @@ -1,10 +1,15 @@ + + Demo User + + + + demo demo - Demo User Mr Demo From bc5da1a02b30f4a89edb988de0d2edb48d183b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 28 Aug 2012 09:34:14 +0200 Subject: [PATCH 037/100] [REVIEW] tools: moved email_split function in emails section, instead of 'somwhere in the file'. bzr revid: tde@openerp.com-20120828073414-lt4bpubxtv3235b6 --- openerp/tools/misc.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py index 024d75fcae0..f609981342e 100644 --- a/openerp/tools/misc.py +++ b/openerp/tools/misc.py @@ -395,6 +395,11 @@ def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=Non cr.close() return res +def email_split(text): + """ Return a list of the email addresses found in ``text`` """ + if not text: return [] + return re.findall(r'([^ ,<@]+@[^> ,]+)', text) + #---------------------------------------------------------- # SMS #---------------------------------------------------------- From 2a916edbade8505201aba8b520981e9ac26873c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 28 Aug 2012 09:53:21 +0200 Subject: [PATCH 038/100] [REVIEW] ir_ui_menu: cleaned _get_needaction code. bzr revid: tde@openerp.com-20120828075321-7emtlqvh5oj6o31r --- openerp/addons/base/ir/ir_ui_menu.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py index 05523faa550..77e923adf48 100644 --- a/openerp/addons/base/ir/ir_ui_menu.py +++ b/openerp/addons/base/ir/ir_ui_menu.py @@ -23,9 +23,7 @@ import base64 import re import threading - from tools.safe_eval import safe_eval as eval - import tools import openerp.modules from osv import fields, osv @@ -258,18 +256,15 @@ class ir_ui_menu(osv.osv): return res def _get_needaction(self, cr, uid, ids, field_names, args, context=None): - if context is None: - context = {} res = {} for menu in self.browse(cr, uid, ids, context=context): - res[menu.id] = {} - res[menu.id]['needaction_enabled'] = False - res[menu.id]['needaction_counter'] = False - res[menu.id] = {} + res[menu.id] = { + 'needaction_enabled': False, + 'needaction_counter': False, + } if menu.action and menu.action.type in ('ir.actions.act_window','ir.actions.client') and menu.action.res_model: obj = self.pool.get(menu.action.res_model) if obj._needaction: - dom = [] if menu.action.type=='ir.actions.act_window': dom = menu.action.domain and eval(menu.action.domain, {'uid': uid}) or [] else: From df47c52bab4ed691519f7173f32ecf11751d19d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 28 Aug 2012 09:53:55 +0200 Subject: [PATCH 039/100] [REVIEW] ir_needaction: cleaned comments, removed unused import. bzr revid: tde@openerp.com-20120828075355-iiblaa6gqio78dcj --- openerp/addons/base/ir/ir_needaction.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/openerp/addons/base/ir/ir_needaction.py b/openerp/addons/base/ir/ir_needaction.py index 1e59a6fbb8e..3bb405fcbfa 100644 --- a/openerp/addons/base/ir/ir_needaction.py +++ b/openerp/addons/base/ir/ir_needaction.py @@ -19,37 +19,35 @@ # ############################################################################## -from osv import osv, fields +from osv import osv class ir_needaction_mixin(osv.Model): '''Mixin class for objects using the need action feature. - Need action feature can be used by objects having to be able to + Need action feature can be used by models that have to be able to signal that an action is required on a particular record. If in the business logic an action must be performed by somebody, for instance validation by a manager, this mechanism allows to set a list of users asked to perform an action. - Objects using the 'need_action' feature should override the - ``needaction_domain_get`` method. This methods returns a + Models using the 'need_action' feature should override the + ``_needaction_domain_get`` method. This method returns a domain to filter records requiring an action for a specific user. This class also offers several global services: - - ``needaction_get_action_count``: as ``needaction_get_record_ids`` - but returns only the number of action, not the ids (performs a - search with count=True) + - ``_needaction_count``: returns the number of actions uid has to perform ''' _name = 'ir.needaction_mixin' _needaction = True #------------------------------------------------------ - # Addon API + # Addons API #------------------------------------------------------ def _needaction_domain_get(self, cr, uid, context=None): """ Returns the domain to filter records that require an action - :return: domain or False is no need action + :return: domain or False is no action """ return False @@ -58,8 +56,7 @@ class ir_needaction_mixin(osv.Model): #------------------------------------------------------ def _needaction_count(self, cr, uid, domain=[], context=None): - """Given the current model and a user_id - get the number of actions it has to perform""" + """ Get the number of actions uid has to perform. """ dom = self._needaction_domain_get(cr, uid, context=context) if dom is False: return 0 From ec85db8e83b01111db0d3e76fc6a815d37702695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 28 Aug 2012 10:09:39 +0200 Subject: [PATCH 040/100] [REVIEW] tools: removed duplicate email_split in tools. bzr revid: tde@openerp.com-20120828080939-5bt3klbep49gjw47 --- openerp/tools/misc.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py index f609981342e..e86f189e9ca 100644 --- a/openerp/tools/misc.py +++ b/openerp/tools/misc.py @@ -1118,12 +1118,6 @@ class unquote(str): def __repr__(self): return self -def email_split(text): - """Return a list of the email addresses found in ``text``""" - if not text: return [] - return re.findall(r'([^ ,<@]+@[^> ,]+)', text) - - class UnquoteEvalContext(defaultdict): """Defaultdict-based evaluation context that returns an ``unquote`` string for any missing name used during From de18f4a401bb8d2d2be2758fdaba3a9dd80184e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 28 Aug 2012 10:50:18 +0200 Subject: [PATCH 041/100] [CLEAN] ir_needaction: cleaned needaction_count. bzr revid: tde@openerp.com-20120828085018-z6uywvk2oeqoog06 --- openerp/addons/base/ir/ir_needaction.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/openerp/addons/base/ir/ir_needaction.py b/openerp/addons/base/ir/ir_needaction.py index 3bb405fcbfa..ba3a5c4a998 100644 --- a/openerp/addons/base/ir/ir_needaction.py +++ b/openerp/addons/base/ir/ir_needaction.py @@ -58,8 +58,6 @@ class ir_needaction_mixin(osv.Model): def _needaction_count(self, cr, uid, domain=[], context=None): """ Get the number of actions uid has to perform. """ dom = self._needaction_domain_get(cr, uid, context=context) - if dom is False: + if not dom: return 0 - result = self.search(cr, uid, (domain or []) +dom, context=context, count=True) - return result - + return self.search(cr, uid, (domain or []) +dom, context=context, count=True) From 3ef83d99e197cbdb12e993b2fbac88b557e4591c Mon Sep 17 00:00:00 2001 From: Minh Tran Date: Tue, 28 Aug 2012 20:04:40 +0200 Subject: [PATCH 042/100] Tweaks to kanban view bzr revid: mit@openerp.com-20120828180440-axp9g1n3y7dayofq --- addons/web_kanban/static/src/css/kanban.css | 7 ++----- addons/web_kanban/static/src/css/kanban.sass | 6 ++---- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/addons/web_kanban/static/src/css/kanban.css b/addons/web_kanban/static/src/css/kanban.css index 345becc7cdd..53cad801b49 100644 --- a/addons/web_kanban/static/src/css/kanban.css +++ b/addons/web_kanban/static/src/css/kanban.css @@ -249,7 +249,7 @@ width: 100%; } .openerp .oe_kanban_view.oe_kanban_ungrouped .oe_kanban_column { - background: white; + background: #eeeeee; } .openerp .oe_kanban_view.oe_kanban_ungrouped .oe_kanban_column .oe_kanban_record { float: left; @@ -340,15 +340,12 @@ background: white; border: 1px solid #d8d8d8; border-bottom-color: #b9b9b9; - padding: 6px; + padding: 8px; display: block; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; } -.openerp .oe_kanban_view .oe_kanban_card:last-child { - margin-bottom: 0; -} .openerp .oe_kanban_view .oe_kanban_card:hover { border: 1px solid #7c7bad; -moz-box-shadow: 0 0 4px #7c7bad; diff --git a/addons/web_kanban/static/src/css/kanban.sass b/addons/web_kanban/static/src/css/kanban.sass index b85d3ebea03..83b17dcfa4d 100644 --- a/addons/web_kanban/static/src/css/kanban.sass +++ b/addons/web_kanban/static/src/css/kanban.sass @@ -234,7 +234,7 @@ &.oe_kanban_grouped .oe_kanban_show_more .oe_button width: 100% &.oe_kanban_ungrouped .oe_kanban_column - background: white + background: #eee .oe_kanban_record float: left padding: 2px @@ -307,11 +307,9 @@ background: white border: 1px solid #d8d8d8 border-bottom-color: #b9b9b9 - padding: 6px + padding: 8px display: block @include radius(4px) - &:last-child - margin-bottom: 0 &:hover border: 1px solid #7C7BAD @include box-shadow(0 0 4px #7C7BAD) From 16773839a48cf3dd9997a1343f789b39e0f37d2f Mon Sep 17 00:00:00 2001 From: Minh Tran Date: Thu, 30 Aug 2012 15:05:24 +0200 Subject: [PATCH 043/100] Styling of group header in listview group by bzr revid: mit@openerp.com-20120830130524-3szsbr80dltbenzm --- addons/web/static/src/css/base.css | 14 +++++++++++--- addons/web/static/src/css/base.sass | 3 +++ addons/web/static/src/js/view_list.js | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index 06a37a54727..c3552811fd4 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -1,4 +1,4 @@ -@charset "utf-8"; +@charset "UTF-8"; @font-face { font-family: "mnmliconsRegular"; src: url("/web/static/src/font/mnmliconsv21-webfont.eot") format("eot"); @@ -69,7 +69,6 @@ display: none !important; } } - .openerp.openerp_webclient_container { height: 100%; position: relative; @@ -85,7 +84,7 @@ text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5); /* http://www.quirksmode.org/dom/inputfile.html * http://stackoverflow.com/questions/2855589/replace-input-type-file-by-an-image - */ */ + */ } .openerp :-moz-placeholder { color: #afafb6 !important; @@ -2523,6 +2522,15 @@ margin: 0 !important; padding: 0; } +.openerp .oe_list .oe_list_content .oe_group_header { + background-color: #fcfcfc; + background-image: -webkit-gradient(linear, left top, left bottom, from(#fcfcfc), to(#dedede)); + background-image: -webkit-linear-gradient(top, #fcfcfc, #dedede); + background-image: -moz-linear-gradient(top, #fcfcfc, #dedede); + background-image: -ms-linear-gradient(top, #fcfcfc, #dedede); + background-image: -o-linear-gradient(top, #fcfcfc, #dedede); + background-image: linear-gradient(to bottom, #fcfcfc, #dedede); +} .openerp .oe_list_content { width: 100%; } diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index c238ef6ee07..0ac0d99def8 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -1970,6 +1970,8 @@ $sheet-max-width: 860px position: absolute margin: 0 !important // dammit padding: 0 + .oe_list_content .oe_group_header + @include vertical-gradient(#fcfcfc, #dedede) .oe_list_content width: 100% @@ -2028,6 +2030,7 @@ $sheet-max-width: 860px > tr:nth-child(odd) background-color: #f0f0fa @include vertical-gradient(#f0f0fa, #eeeef6) + > tfoot border-top: 2px solid #cacaca border-bottom: 1px solid #cacaca diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index a2dccf2ec73..42a808c5e15 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -1259,7 +1259,7 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we self.bind_child_events(child); child.datagroup = group; - var $row = child.$row = $(''); + var $row = child.$row = $(''); if (group.openable && group.length) { $row.click(function (e) { if (!$row.data('open')) { From 6bc116cf6d8d3ff250b24f9d59ccd35df8c92bd2 Mon Sep 17 00:00:00 2001 From: Minh Tran Date: Fri, 31 Aug 2012 15:23:04 +0200 Subject: [PATCH 044/100] fixed avatar hover and shadow in kanban view bzr revid: mit@openerp.com-20120831132304-qzmuvltopy1mdiwa --- addons/web_kanban/static/src/css/kanban.css | 9 ++++++--- addons/web_kanban/static/src/css/kanban.sass | 4 +++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/addons/web_kanban/static/src/css/kanban.css b/addons/web_kanban/static/src/css/kanban.css index 53cad801b49..b2abba2b0ec 100644 --- a/addons/web_kanban/static/src/css/kanban.css +++ b/addons/web_kanban/static/src/css/kanban.css @@ -170,9 +170,9 @@ -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; - -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); - -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); - -box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + -box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); } .openerp .oe_kanban_view .oe_kanban_details { display: inline-block; @@ -265,6 +265,9 @@ .openerp .oe_kanban_view .oe_kanban_action_a { text-decoration: none; } +.openerp .oe_kanban_view .oe_kanban_action_a:hover { + text-decoration: none; +} .openerp .oe_kanban_view .oe_kanban_table { width: 100%; border: none; diff --git a/addons/web_kanban/static/src/css/kanban.sass b/addons/web_kanban/static/src/css/kanban.sass index 83b17dcfa4d..67039ac475b 100644 --- a/addons/web_kanban/static/src/css/kanban.sass +++ b/addons/web_kanban/static/src/css/kanban.sass @@ -178,7 +178,7 @@ text-align: center overflow: hidden @include radius(3px) - @include box-shadow(0 1px 4px rgba(0, 0, 0, 0.4)) + @include box-shadow(0 1px 3px rgba(0, 0, 0, 0.3)) .oe_kanban_details display: inline-block vertical-align: top @@ -246,6 +246,8 @@ margin: 0 .oe_kanban_action_a text-decoration: none + &:hover + text-decoration: none .oe_kanban_table width: 100% border: none From d37745559e951bed047bd293e293ce3087cf8f40 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 31 Aug 2012 15:23:37 +0200 Subject: [PATCH 045/100] [ADD] tools.misc: new function append_to_html, can be used to inject blocks (html or plaintext) to existing HTML snippets bzr revid: odo@openerp.com-20120831132337-of2p1wlh5l4lpvez --- openerp/tests/__init__.py | 3 ++- openerp/tests/test_misc.py | 21 +++++++++++++++++++++ openerp/tools/misc.py | 31 +++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 openerp/tests/test_misc.py diff --git a/openerp/tests/__init__.py b/openerp/tests/__init__.py index d3ab62ebc1c..aa3055f471c 100644 --- a/openerp/tests/__init__.py +++ b/openerp/tests/__init__.py @@ -9,7 +9,7 @@ See the :ref:`test-framework` section in the :ref:`features` list. """ from . import test_expression, test_html_sanitize, test_ir_sequence, test_orm,\ - test_view_validation, test_uninstall + test_view_validation, test_uninstall, test_misc fast_suite = [ test_ir_sequence, @@ -20,6 +20,7 @@ checks = [ test_html_sanitize, test_orm, test_view_validation, + test_misc, ] # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/tests/test_misc.py b/openerp/tests/test_misc.py new file mode 100644 index 00000000000..7661f253b17 --- /dev/null +++ b/openerp/tests/test_misc.py @@ -0,0 +1,21 @@ +# This test can be run stand-alone with something like: +# > PYTHONPATH=. python2 openerp/tests/test_misc.py + +import unittest2 + +class test_misc(unittest2.TestCase): + """ Test some of our generic utility functions """ + + def test_append_to_html(self): + from openerp.tools import append_content_to_html + test_samples = [ + ('some content', '--\nYours truly', True, + 'some content\n
--\nYours truly
\n'), + ('some content', '\n\n

--

\n

Yours truly

\n\n', False, + 'some content\n\n\n

--

\n

Yours truly

\n\n\n'), + ] + for html, content, flag, expected in test_samples: + self.assertEqual(append_content_to_html(html,content,flag), expected, 'append_content_to_html is broken') + +if __name__ == '__main__': + unittest2.main() \ No newline at end of file diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py index e86f189e9ca..39e86b1ec4a 100644 --- a/openerp/tools/misc.py +++ b/openerp/tools/misc.py @@ -400,6 +400,37 @@ def email_split(text): if not text: return [] return re.findall(r'([^ ,<@]+@[^> ,]+)', text) +def append_content_to_html(html, content, plaintext=True): + """Append extra content at the end of an HTML snippet, trying + to locate the end of the HTML document (, , or + EOF), and wrapping the provided content in a
 block
+       unless ``plaintext`` is False. A side-effect of this
+       method is to coerce all HTML tags to lowercase in ``html``,
+       and strips enclosing  or  tags in content if
+       ``plaintext`` is False.
+       
+       :param str html: html tagsoup (doesn't have to be XHTML)
+       :param str content: extra content to append
+       :param bool plaintext: whether content is plaintext and should
+           be wrapped in a 
 tag.
+    """
+    html = ustr(html)
+    if plaintext:
+        content = u'\n
%s
\n' % ustr(content) + else: + content = re.sub(r'(?i)(||)', '', content) + content = u'\n%s\n'% ustr(content) + # Force all tags to lowercase + html = re.sub(r'(])', + lambda m: '%s%s%s' % (m.group(1),m.group(2).lower(),m.group(3)), html) + insert_location = html.find('') + if insert_location == -1: + insert_location = html.find('') + if insert_location == -1: + return '%s%s' % (html, content) + return '%s%s%s' % (html[:insert_location], content, html[insert_location:]) + + #---------------------------------------------------------- # SMS #---------------------------------------------------------- From 723d2ee1daaf2d709926f0ea1bce6c5ba334285d Mon Sep 17 00:00:00 2001 From: Minh Tran Date: Fri, 31 Aug 2012 18:31:53 +0200 Subject: [PATCH 046/100] uniformization of avatar box-shadow bzr revid: mit@openerp.com-20120831163153-8515c0vfr6sw09n1 --- addons/web/static/src/css/base.css | 12 ++++++------ addons/web/static/src/css/base.sass | 4 ++-- addons/web_kanban/static/src/css/kanban.css | 6 +++--- addons/web_kanban/static/src/css/kanban.sass | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index c3552811fd4..dcb3fd958f4 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -498,9 +498,9 @@ -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; - -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); - -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); + -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); border: none; } .openerp .oe_avatar + div { @@ -866,9 +866,9 @@ font-family: "Lucida Grande", Helvetica, Verdana, Arial; border: 1px solid #999999; background: whitesmoke; - -moz-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3); - -webkit-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3); - box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3); + -moz-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.4); + -webkit-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.4); + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.4); -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index 0ac0d99def8..43b8ace724b 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -420,7 +420,7 @@ $sheet-max-width: 860px max-height: 90px max-width: 90px @include radius(3px) - @include box-shadow(0 1px 3px rgba(0, 0, 0, 0.3)) + @include box-shadow(0 1px 4px rgba(0, 0, 0, 0.4)) border: none .oe_avatar + div margin-left: 5px @@ -687,7 +687,7 @@ $sheet-max-width: 860px font-family: "Lucida Grande", Helvetica, Verdana, Arial border: 1px solid #999999 background: whitesmoke - @include box-shadow(inset 0 1px 4px rgba(0, 0, 0, 0.3)) + @include box-shadow(inset 0 1px 4px rgba(0, 0, 0, 0.4)) @include radius(3px) input margin-bottom: 9px diff --git a/addons/web_kanban/static/src/css/kanban.css b/addons/web_kanban/static/src/css/kanban.css index b2abba2b0ec..299aba737e6 100644 --- a/addons/web_kanban/static/src/css/kanban.css +++ b/addons/web_kanban/static/src/css/kanban.css @@ -170,9 +170,9 @@ -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; - -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); - -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); - -box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); + -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); + -box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); } .openerp .oe_kanban_view .oe_kanban_details { display: inline-block; diff --git a/addons/web_kanban/static/src/css/kanban.sass b/addons/web_kanban/static/src/css/kanban.sass index 67039ac475b..30bfe9b364f 100644 --- a/addons/web_kanban/static/src/css/kanban.sass +++ b/addons/web_kanban/static/src/css/kanban.sass @@ -178,7 +178,7 @@ text-align: center overflow: hidden @include radius(3px) - @include box-shadow(0 1px 3px rgba(0, 0, 0, 0.3)) + @include box-shadow(0 1px 4px rgba(0, 0, 0, 0.4)) .oe_kanban_details display: inline-block vertical-align: top From 0de195b893ffca38a8bbe8be015e15147377bfa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 31 Aug 2012 19:12:47 +0200 Subject: [PATCH 047/100] [IMP] res_partner: moved regex of name_create of res.partner into a dedicated method, allowing ot use it outside of the name_create. Cleaned a bit the code, updated comments to the method. bzr revid: tde@openerp.com-20120831171247-uc0babnzfk4logoa --- openerp/addons/base/res/res_partner.py | 32 +++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 30255d93ec3..42ddd1d40cd 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -351,27 +351,27 @@ class res_partner(osv.osv): res.append((record.id, name)) return res + def parse_partner_name(self, cr, uid, name, context=None): + """ Supported syntax: + - 'Raoul ', available with ' ', '<>', '{}', + '()', '[]': will find name and email address + - otherwise: default, everything is set as the name """ + regex = re.compile('^(.*?)(?: ?[\<{(\[]?([a-zA-Z0-9._%-]+@[a-zA-Z0-9_-]+\.[a-zA-Z0-9._]{1,8})[\>})\]]?)?$') + result = regex.match(name) + return (result.group(1).strip(), result.group(2)) + def name_create(self, cr, uid, name, context=None): """ Override of orm's name_create method for partners. The purpose is to handle some basic formats to create partners using the name_create. - Supported syntax: - - 'raoul@grosbedon.fr': create a partner with name raoul@grosbedon.fr - and sets its email to raoul@grosbedon.fr - - 'Raoul Grosbedon ': create a partner with name - Raoul Grosbedon, and set its email to raoul@grosbedon.fr - - anything else: fall back on the default name_create - Regex : - - ([a-zA-Z0-9._%-]+@[a-zA-Z0-9_-]+\.[a-zA-Z0-9._]{1,8}): raoul@grosbedon.fr - - ([\w\s.\\-]+)[\<]([a-zA-Z0-9._%-]+@[a-zA-Z0-9_-]+\.[a-zA-Z0-9._]{1,8})[\>]: - Raoul Grosbedon, raoul@grosbedon.fr - """ - regex = re.compile('^(.*?)(?: ?[\<]?([a-zA-Z0-9._%-]+@[a-zA-Z0-9_-]+\.[a-zA-Z0-9._]{1,8})[\>]?)?$') - result = regex.match(name) - if not result or (context.get('force_create',False) and result.group(2) is None): + If only an email address is received and that the regex cannot find + a name, the name will have the email value. + If 'force_email' key in context: must find the email address. """ + name, email = self.parse_partner_name(cr, uid, name, context=context) + if context.get('force_email') and not email: raise osv.except_osv(_('Warning'), _("Couldn't create contact without email address !")) - name = result.group(1).strip() - email = result.group(2) + if not name and email: + name = email rec_id = self.create(cr, uid, {self._rec_name: name or email, 'email': email or False}, context=context) return self.name_get(cr, uid, [rec_id], context)[0] From 68038627119f4a590f16caa983a0e821198d9361 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Sat, 1 Sep 2012 00:52:05 +0200 Subject: [PATCH 048/100] [IMP] res.partner: simplified+corrected parsing of partner name and email in name_create, added tests, made this internal method private bzr revid: odo@openerp.com-20120831225205-04l4udn95cz3n72o --- openerp/addons/base/res/res_partner.py | 17 ++++++++++------- openerp/addons/base/tests/__init__.py | 4 ++-- openerp/addons/base/tests/test_base.py | 26 ++++++++++++++++++++++++++ openerp/tools/misc.py | 2 +- 4 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 openerp/addons/base/tests/test_base.py diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 42ddd1d40cd..931497004ec 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -351,14 +351,17 @@ class res_partner(osv.osv): res.append((record.id, name)) return res - def parse_partner_name(self, cr, uid, name, context=None): + def _parse_partner_name(self, text, context=None): """ Supported syntax: - - 'Raoul ', available with ' ', '<>', '{}', - '()', '[]': will find name and email address + - 'Raoul ': will find name and email address - otherwise: default, everything is set as the name """ - regex = re.compile('^(.*?)(?: ?[\<{(\[]?([a-zA-Z0-9._%-]+@[a-zA-Z0-9_-]+\.[a-zA-Z0-9._]{1,8})[\>})\]]?)?$') - result = regex.match(name) - return (result.group(1).strip(), result.group(2)) + match = re.search(r'([^\s,<@]+@[^>\s,]+)', text) + if match: + email = match.group(1) + name = text[:text.index(email)].replace('"','').replace('<','').strip() + else: + name, email = text, '' + return name, email def name_create(self, cr, uid, name, context=None): """ Override of orm's name_create method for partners. The purpose is @@ -367,7 +370,7 @@ class res_partner(osv.osv): If only an email address is received and that the regex cannot find a name, the name will have the email value. If 'force_email' key in context: must find the email address. """ - name, email = self.parse_partner_name(cr, uid, name, context=context) + name, email = self._parse_partner_name(name, context=context) if context.get('force_email') and not email: raise osv.except_osv(_('Warning'), _("Couldn't create contact without email address !")) if not name and email: diff --git a/openerp/addons/base/tests/__init__.py b/openerp/addons/base/tests/__init__.py index 5ea7654c008..42fef2eb39d 100644 --- a/openerp/addons/base/tests/__init__.py +++ b/openerp/addons/base/tests/__init__.py @@ -1,5 +1,5 @@ -import test_ir_values +import test_ir_values, test_base checks = [ - test_ir_values, + test_ir_values, test_base ] diff --git a/openerp/addons/base/tests/test_base.py b/openerp/addons/base/tests/test_base.py new file mode 100644 index 00000000000..1ff200a8b68 --- /dev/null +++ b/openerp/addons/base/tests/test_base.py @@ -0,0 +1,26 @@ +import unittest2 + +import openerp.tests.common as common + +class test_base(common.TransactionCase): + + def setUp(self): + super(test_base,self).setUp() + self.res_partner = self.registry('res.partner') + + def test_00_res_partner_name_parse(self): + parse = self.res_partner._parse_partner_name + # samples use effective TLDs from the Mozilla public suffix + # list at http://publicsuffix.org + test_samples = [ + ('"Raoul Grosbedon" ', 'Raoul Grosbedon', 'raoul@chirurgiens-dentistes.fr'), + ('ryu+giga-Sushi@aizubange.fukushima.jp', '', 'ryu+giga-Sushi@aizubange.fukushima.jp'), + ('Raoul chirurgiens-dentistes.fr', 'Raoul chirurgiens-dentistes.fr', ''), + (" Raoul O'hara ", "Raoul O'hara", '!@historicalsociety.museum') + ] + for text, name, mail in test_samples: + self.assertEqual((name,mail), parse(text), 'Partner name parsing failed') + + +if __name__ == '__main__': + unittest2.main() \ No newline at end of file diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py index 39e86b1ec4a..875fa7a9c09 100644 --- a/openerp/tools/misc.py +++ b/openerp/tools/misc.py @@ -406,7 +406,7 @@ def append_content_to_html(html, content, plaintext=True): EOF), and wrapping the provided content in a
 block
        unless ``plaintext`` is False. A side-effect of this
        method is to coerce all HTML tags to lowercase in ``html``,
-       and strips enclosing  or  tags in content if
+       and strip enclosing  or  tags in content if
        ``plaintext`` is False.
        
        :param str html: html tagsoup (doesn't have to be XHTML)

From c895c53341c21a06d6a00bfb7045b1353d708d3d Mon Sep 17 00:00:00 2001
From: "Ajay Chauhan (OpenERP)" 
Date: Mon, 3 Sep 2012 15:01:27 +0530
Subject: [PATCH 049/100] [IMP] crm, project, hr_recruitment: made stages
 accute on view according to state

bzr revid: cha@tinyerp.com-20120903093127-vao5eoi61is1pqfx
---
 addons/crm/crm_lead.py                        | 2 +-
 addons/hr_recruitment/hr_recruitment.py       | 2 +-
 addons/hr_recruitment/hr_recruitment_view.xml | 2 +-
 addons/project/project.py                     | 2 +-
 addons/project/project_view.xml               | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py
index 25a47ecbadc..8f857c28556 100644
--- a/addons/crm/crm_lead.py
+++ b/addons/crm/crm_lead.py
@@ -213,7 +213,7 @@ class crm_lead(base_stage, osv.osv):
         'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority', select=True),
         'date_closed': fields.datetime('Closed', readonly=True),
         'stage_id': fields.many2one('crm.case.stage', 'Stage',
-                        domain="['&', '|', ('section_ids', '=', section_id), ('case_default', '=', True), '|', ('type', '=', type), ('type', '=', 'both')]"),
+                        domain="['&', '|', ('section_ids', '=', section_id), ('case_default', '=', True), '&', ('fold', '=', False), '|', ('type', '=', type), ('type', '=', 'both')]"),
         'user_id': fields.many2one('res.users', 'Salesperson'),
         'referred': fields.char('Referred By', size=64),
         'date_open': fields.datetime('Opened', readonly=True),
diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py
index 6b4839b7b2b..2a3fab58730 100644
--- a/addons/hr_recruitment/hr_recruitment.py
+++ b/addons/hr_recruitment/hr_recruitment.py
@@ -185,7 +185,7 @@ class hr_applicant(base_stage, osv.Model):
         'create_date': fields.datetime('Creation Date', readonly=True, select=True),
         'write_date': fields.datetime('Update Date', readonly=True),
         'stage_id': fields.many2one ('hr.recruitment.stage', 'Stage',
-                        domain="['|', ('department_id', '=', department_id), ('department_id', '=', False)]"),
+                        domain="['&', ('fold', '=', False), '|', ('department_id', '=', department_id), ('department_id', '=', False)]"),
         'state': fields.related('stage_id', 'state', type="selection", store=True,
                 selection=AVAILABLE_STATES, string="State", readonly=True,
                 help='The state is set to \'Draft\', when a case is created.\
diff --git a/addons/hr_recruitment/hr_recruitment_view.xml b/addons/hr_recruitment/hr_recruitment_view.xml
index d1866f124af..8fd2db3425a 100644
--- a/addons/hr_recruitment/hr_recruitment_view.xml
+++ b/addons/hr_recruitment/hr_recruitment_view.xml
@@ -107,7 +107,7 @@