From 8e58b5191a3f5203dd655bf90e507195c07cdd2b Mon Sep 17 00:00:00 2001 From: "Sbh (OpenERP)" Date: Wed, 9 Feb 2011 16:15:55 +0530 Subject: [PATCH 001/763] [ADD] Add google_conact module bzr revid: sbh@tinyerp.com-20110209104555-l3txskncpjnfxvyc --- addons/goolge_contact/__init__.py | 24 +++++++++ addons/goolge_contact/__openerp__.py | 40 +++++++++++++++ addons/goolge_contact/google_contact.py | 32 ++++++++++++ addons/goolge_contact/google_contact_view.xml | 50 +++++++++++++++++++ addons/goolge_contact/test.py | 40 +++++++++++++++ 5 files changed, 186 insertions(+) create mode 100644 addons/goolge_contact/__init__.py create mode 100644 addons/goolge_contact/__openerp__.py create mode 100644 addons/goolge_contact/google_contact.py create mode 100644 addons/goolge_contact/google_contact_view.xml create mode 100644 addons/goolge_contact/test.py diff --git a/addons/goolge_contact/__init__.py b/addons/goolge_contact/__init__.py new file mode 100644 index 00000000000..ab21f4a289b --- /dev/null +++ b/addons/goolge_contact/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import google_contact +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + diff --git a/addons/goolge_contact/__openerp__.py b/addons/goolge_contact/__openerp__.py new file mode 100644 index 00000000000..645362a0729 --- /dev/null +++ b/addons/goolge_contact/__openerp__.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +{ + 'name': 'Google Contact', + 'version': '1.0', + 'category': 'Generic Modules/Others', + 'description': """The module adds google contact in partner address""", + 'author': 'OpenERP SA', + 'website': 'http://www.openerp.com', + 'depends': ['base'], + 'init_xml': [], + 'update_xml': [ + # 'google_contact_view.xml' + ], + 'demo_xml': [], + 'installable': True, + 'active': False, + 'certificate': '', +} +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/goolge_contact/google_contact.py b/addons/goolge_contact/google_contact.py new file mode 100644 index 00000000000..0612398321b --- /dev/null +++ b/addons/goolge_contact/google_contact.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from osv import fields,osv,orm + +try: + import gdata + from gdata import contacts + import gdata.contacts.service +except ImportError: + raise osv.except_osv(_('Google Contacts Import Error!'), _('Please install gdata-python-client from http://code.google.com/p/gdata-python-client/downloads/list')) + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + diff --git a/addons/goolge_contact/google_contact_view.xml b/addons/goolge_contact/google_contact_view.xml new file mode 100644 index 00000000000..09ed4a9346f --- /dev/null +++ b/addons/goolge_contact/google_contact_view.xml @@ -0,0 +1,50 @@ + + + + + + google.contact.form + google.contact + form + +
+ + + + + + + + + +

From 6bbe8c7200a1602de3e28d9765b1dd420383a355 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Wed, 1 Jun 2011 15:01:56 +0200 Subject: [PATCH 275/763] [IMP] ir.rule: local rules will be combined with OR within the same group This makes it more intuitive: global rules are restrictions and always combined with AND, while local rules are always combined with OR, regardless if they are in the same group or different groups. It makes it also easier to add rules in an existing group to grant more rights. bzr revid: odo@openerp.com-20110601130156-c0swo9w21zqun2gl --- openerp/addons/base/ir/ir.xml | 23 ++++++++++++++--------- openerp/addons/base/ir/ir_rule.py | 2 +- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/openerp/addons/base/ir/ir.xml b/openerp/addons/base/ir/ir.xml index 8b39ac925b2..16630cbd40f 100644 --- a/openerp/addons/base/ir/ir.xml +++ b/openerp/addons/base/ir/ir.xml @@ -1667,24 +1667,29 @@ - + - + - - diff --git a/openerp/addons/base/ir/ir_rule.py b/openerp/addons/base/ir/ir_rule.py index 52f76f2f611..d9da5ac6924 100644 --- a/openerp/addons/base/ir/ir_rule.py +++ b/openerp/addons/base/ir/ir_rule.py @@ -129,7 +129,7 @@ class ir_rule(osv.osv): global_domains.append(dom) # combine global domains and group domains if group_domains: - group_domain = expression.OR(map(expression.AND, group_domains.values())) + group_domain = expression.OR(map(expression.OR, group_domains.values())) else: group_domain = [] domain = expression.AND(global_domains + [group_domain]) From c34a2181594916ade3f53ffa3a25b3e1bc93e251 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Wed, 1 Jun 2011 15:06:55 +0200 Subject: [PATCH 276/763] [IMP] share: add option to specify shared access name bzr revid: odo@openerp.com-20110601130655-9y63unr6eus9f20e --- addons/share/wizard/share_wizard.py | 6 +++--- addons/share/wizard/share_wizard_view.xml | 21 +++++++++------------ 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/addons/share/wizard/share_wizard.py b/addons/share/wizard/share_wizard.py index 3291efb8885..6b1bf4c8381 100644 --- a/addons/share/wizard/share_wizard.py +++ b/addons/share/wizard/share_wizard.py @@ -83,9 +83,9 @@ class share_create(osv.osv_memory): def _user_type_selection(self, cr, uid, context=None): result = [('new','New users (emails required)'), - ('existing','Existing external users')] + ('existing','Users you already shared with')] if self.has_extended_share(cr, uid, context=context): - result.append(('groups','Existing groups of users')) + result.append(('groups','Existing groups (Portals setup only)')) return result """Override of create() to auto-compute the action name""" @@ -123,7 +123,7 @@ class share_create(osv.osv_memory): def go_step_1(self, cr, uid, ids, context=None): dummy, step1_form_view_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'share', 'share_step1_form') return { - 'name': _('Configure shared access'), + 'name': _('Grant instant access to your documents'), 'view_type': 'form', 'view_mode': 'form', 'res_model': 'share.wizard', diff --git a/addons/share/wizard/share_wizard_view.xml b/addons/share/wizard/share_wizard_view.xml index 2ec11198e13..a763ef2ea51 100644 --- a/addons/share/wizard/share_wizard_view.xml +++ b/addons/share/wizard/share_wizard_view.xml @@ -7,7 +7,7 @@ share.wizard form -
+ @@ -28,7 +28,11 @@ share.wizard form - + + + @@ -40,7 +44,7 @@ - + @@ -51,17 +55,10 @@ - - - - - + - - - From e9ef1c6ab6481b9cfaa933abd62c3a44e19bce19 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Wed, 1 Jun 2011 15:07:45 +0200 Subject: [PATCH 277/763] [IMP] share: renamed extended group for usability bzr revid: odo@openerp.com-20110601130745-isgkoo68eufckon4 --- addons/share/security/share_security.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/addons/share/security/share_security.xml b/addons/share/security/share_security.xml index 089d520ec5f..080257b83fb 100644 --- a/addons/share/security/share_security.xml +++ b/addons/share/security/share_security.xml @@ -8,10 +8,11 @@ Members of this groups have access to the sharing wizard, which allows them to i - Sharing / User (Extended) + Sharing / Share With Groups -Members of this groups have access to the sharing wizard in extended mode, so they can not only share their documents with external users, but they can also share their documents with other groups. -This could result in an alteration of the system's security policy, so should be granted only to trustworthy users who know the security policy very well. +Members of this group are allowed to share documents with Groups in addition to Users. This is useful for setting up Portals +with the portal module, but this could result in an alteration of the system's security policy. +Therefore this should be granted only to trustworthy users who know the security policy very well. This group should not be deleted. From fe4680f6e90643dffbc97112e6c8f16cea401dbc Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Wed, 1 Jun 2011 15:11:46 +0200 Subject: [PATCH 278/763] [IMP] share: update local rule creation to take advantage of new ir.rule combinations In v6.0, local rules in the same group were AND'ed, so we had to compute rule combinations. Now we can simply add a new rule, and it will be automatically OR'ed. bzr revid: odo@openerp.com-20110601131146-7pek6a7grxiij03r --- addons/share/wizard/share_wizard.py | 45 ++++++++++------------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/addons/share/wizard/share_wizard.py b/addons/share/wizard/share_wizard.py index 6b1bf4c8381..23fe1ae7e9b 100644 --- a/addons/share/wizard/share_wizard.py +++ b/addons/share/wizard/share_wizard.py @@ -385,39 +385,26 @@ class share_create(osv.osv_memory): def _create_or_combine_sharing_rule(self, cr, current_user, wizard_data, group_id, model_id, domain, rule_name=None, context=None): rule_obj = self.pool.get('ir.rule') - if rule_name is None: - rule_name = _('Sharing filter created by user %s (%s) for group %s') % \ - (current_user.name, current_user.login, group_id) - # if the target group already has one or more rules for the given model, - # we should instead add the new domain to each rule with OR operator to - # achieve the desired effect, otherwise they would be AND'ed as happens - # for any pair of rules on the same group for the same model. - # Indeed, A v (B /\ C) == (A v B) /\ (A v C) rule_ids = rule_obj.search(cr, UID_ROOT, [('groups', 'in', group_id), ('model_id', '=', model_id)]) if rule_ids: for rule in rule_obj.browse(cr, UID_ROOT, rule_ids, context=context): if rule.domain_force == domain: - # skip identical ones! - continue - # sanity check: the rule we are about to modify must not be used by another group - self._assert(len(rule.groups) == 1, - _('Sorry, the selected group(s) currently have security rules in conflict with '\ - 'the access point you are adding, and these rules cannot be altered because they are used '\ - 'by other groups as well. Please correct it and make sure each group does not share any '\ - 'security rule with other groups (global rules are fine).'), context=context) - # combine both domains with 'OR' - combined_domain = rule_obj.domain_disjunction(cr, UID_ROOT, rule.domain_force, domain) - rule.write({'domain_force': combined_domain}, context=context) - self.__logger.debug("Combined new sharing rule on model %s with domain: %s with existing one(s): %r", model_id, domain, combined_domain) - else: - rule_obj.create(cr, UID_ROOT, { - 'name': rule_name, - 'model_id': model_id, - 'domain_force': domain, - 'groups': [(4,group_id)] - }) - self.__logger.debug("Created sharing rule on model %s with domain: %s", model_id, domain) - + # don't create it twice! + self.__logger.debug("Ignoring sharing rule on model %s with domain: %s because the same rule exists already", model_id, domain) + return + if rule_name is None: + rule_name = _('Sharing filter created by user %s (%s) for group %s') % \ + (current_user.name, current_user.login, group_id) + # Adding the new rule in the group is fine in all cases, because rules + # in the same group and for the same model will be combined with OR + # (as of v6.1), so the desired effect is achieved. + rule_obj.create(cr, UID_ROOT, { + 'name': rule_name, + 'model_id': model_id, + 'domain_force': domain, + 'groups': [(4,group_id)] + }) + self.__logger.debug("Created sharing rule on model %s with domain: %s", model_id, domain) def _create_indirect_sharing_rules(self, cr, current_user, wizard_data, group_id, fields_relations, context=None): rule_obj = self.pool.get('ir.rule') From 5a554c49ba71f54567b76e3687fe0836a137a773 Mon Sep 17 00:00:00 2001 From: "Bhumika (OpenERP)" Date: Wed, 1 Jun 2011 18:44:58 +0530 Subject: [PATCH 279/763] [FIX] google_base_account: remove unused code bzr revid: sbh@tinyerp.com-20110601131458-3kkhkh39jtpdkv0j --- .../wizard/google_login.py | 31 +++++-------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/addons/google_base_account/wizard/google_login.py b/addons/google_base_account/wizard/google_login.py index d32e2701569..d886e58561d 100644 --- a/addons/google_base_account/wizard/google_login.py +++ b/addons/google_base_account/wizard/google_login.py @@ -34,19 +34,12 @@ class google_login(osv.osv_memory): 'password': fields.char('Google Password', size=64), } - def google_login(self,cr,uid,user,password,type='',context=None): - gd_client=False - if type == 'group': - gd_client = gdata.contacts.client.ContactsClient(source='OpenERP') - if type == 'contact' : - gd_client = gdata.contacts.service.ContactsService() - if type == 'calendar': - gd_client = gdata.calendar.service.CalendarService() + def google_login(self, user, password, type='group', context=None): + gd_client = gdata.contacts.service.ContactsService() try: gd_client.ClientLogin(user, password,gd_client.source) - - except Exception, e: - raise osv.except_osv(_('Error'), _(e)) + except Exception: + return False return gd_client @@ -58,19 +51,12 @@ class google_login(osv.osv_memory): if 'password' in fields: res.update({'password': user_obj.gmail_password}) return res - - def check_login(self, cr, uid, ids, context=None): - if context == None: - context = {} + + def login(self, cr, uid, ids, context=None): data = self.read(cr, uid, ids)[0] user = data['user'] password = data['password'] - gd_client = gdata.contacts.service.ContactsService() - gd_client.email = user - gd_client.password = password - gd_client.source = 'OpenERP' - try: - gd_client.ProgrammaticLogin() + if self.google_login(user, password): res = { 'gmail_user': user, 'gmail_password': password @@ -79,7 +65,6 @@ class google_login(osv.osv_memory): else: raise osv.except_osv(_('Error'), _("Authentication fail check the user and password !")) - return self._get_next_action(cr, uid, context=context) def _get_next_action(self, cr, uid, context=None): @@ -87,4 +72,4 @@ class google_login(osv.osv_memory): google_login() -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file From ce029f887e04f5fd79dbecec93f4258df2b63c8c Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Wed, 1 Jun 2011 15:55:26 +0200 Subject: [PATCH 280/763] [FIX] ir.rule: must eval the rule domain as user, but browse the rule's groups as admin bzr revid: odo@openerp.com-20110601135526-gk7zfiylnhlpvlod --- openerp/addons/base/ir/ir_rule.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openerp/addons/base/ir/ir_rule.py b/openerp/addons/base/ir/ir_rule.py index d9da5ac6924..2a36ee9ccc5 100644 --- a/openerp/addons/base/ir/ir_rule.py +++ b/openerp/addons/base/ir/ir_rule.py @@ -121,7 +121,9 @@ class ir_rule(osv.osv): global_domains = [] # list of domains group_domains = {} # map: group -> list of domains for rule in self.browse(cr, SUPERUSER_UID, rule_ids): - dom = expression.normalize(rule.domain) + # read 'domain' as UID to have the correct eval context for the rule. + rule_domain = self.read(cr, uid, rule.id, ['domain'])['domain'] + dom = expression.normalize(rule_domain) for group in rule.groups: if group in user.groups_id: group_domains.setdefault(group, []).append(dom) From 26f73ce7e8da325f8b64562608174aa1bb6331f9 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Wed, 1 Jun 2011 16:39:21 +0200 Subject: [PATCH 281/763] [IMP] base: update ir.rule tests for new combination semantics (Rules from the same local group are now OR'ed, instead of AND'ed. bzr revid: odo@openerp.com-20110601143921-g3tv46krsa01y4tv --- openerp/addons/base/test/test_ir_rule.yml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/openerp/addons/base/test/test_ir_rule.yml b/openerp/addons/base/test/test_ir_rule.yml index b5114cbedcb..49b368a5bb3 100644 --- a/openerp/addons/base/test/test_ir_rule.yml +++ b/openerp/addons/base/test/test_ir_rule.yml @@ -133,21 +133,22 @@ ids = self.search(cr, ref('base.user_demo'), []) assert ids, "Demo user should see some partner." - - Modify the ir_rule for employee so that demo is not - allowed to see partners anymore. We use a domain - with implicit AND operator for later tests on normalization. + Modify the ir_rule for employee to have a rule that fordids + seeing any record. + We use a domain with implicit AND operator for later tests + on normalization. - !record {model: ir.rule, id: test_rule2}: domain_force: "[('id','=',False),('name','=',False)]" - - Check that demo user does not see partners anymore. + Check that demo user still sees partners, because group-rules are OR'ed. - !python {model: res.partner }: | ids = self.search(cr, ref('base.user_demo'), []) - assert (not ids), "Demo user should not see any partner anymore" + assert ids, "Demo user should see some partner." - - Create a new group with demo user in it, and a complex rule that should - re-allow demo to see partners, because he belongs to both groups. + Create a new group with demo user in it, and a complex rule. + Demo should still see partners. - !record {model: res.groups, id: test_group}: name: Test Group @@ -168,11 +169,11 @@ perm_read: 1 perm_create: 1 - - Read the partners again as demo user, which should give results again. + Read the partners again as demo user, which should give results. - !python {model: res.partner }: | ids = self.search(cr, ref('base.user_demo'), []) - assert ids, "Demo user should see some partners again, due to combined rules." + assert ids, "Demo user should see partners even with the combined rules." - Delete global domains (to combine only group domains). - From 6aa240ca1915289bbbafd4707e930228cbd1bf23 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Wed, 1 Jun 2011 18:34:55 +0200 Subject: [PATCH 282/763] [IMP] ir_translation only display installed lang, 10% speedup in translation loading bzr revid: al@openerp.com-20110601163455-2o732ssum24kwshu --- openerp/addons/base/ir/ir_translation.py | 14 +++++--------- openerp/tools/translate.py | 1 - 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/openerp/addons/base/ir/ir_translation.py b/openerp/addons/base/ir/ir_translation.py index eb900363669..85b3e8fc8a7 100644 --- a/openerp/addons/base/ir/ir_translation.py +++ b/openerp/addons/base/ir/ir_translation.py @@ -44,15 +44,11 @@ class ir_translation(osv.osv): _log_access = False def _get_language(self, cr, uid, context): - lang_obj = self.pool.get('res.lang') - lang_ids = lang_obj.search(cr, uid, [('translatable', '=', True)], - context=context) - langs = lang_obj.browse(cr, uid, lang_ids, context=context) - res = [(lang.code, lang.name) for lang in langs] - for lang_dict in tools.scan_languages(): - if lang_dict not in res: - res.append(lang_dict) - return res + lang_model = self.pool.get('res.lang') + lang_ids = lang_model.search(cr, uid, [('translatable', '=', True)], context=context) + lang_data = lang_model.read(cr, uid, lang_ids, ['code','name']) + l = [(d['code'],d['name']) for d in lang_data] + return l _columns = { 'name': fields.char('Field Name', size=128, required=True), diff --git a/openerp/tools/translate.py b/openerp/tools/translate.py index 5761ba87cc0..c9f69512264 100644 --- a/openerp/tools/translate.py +++ b/openerp/tools/translate.py @@ -864,7 +864,6 @@ def trans_load_data(cr, fileobj, fileformat, lang, lang_name=None, verbose=True, pool = pooler.get_pool(db_name) lang_obj = pool.get('res.lang') trans_obj = pool.get('ir.translation') - model_data_obj = pool.get('ir.model.data') iso_lang = misc.get_iso_codes(lang) try: uid = 1 From c00c1e44e3f1ec6c616a6c9c14c5201a1f753244 Mon Sep 17 00:00:00 2001 From: "Bhumika (OpenERP)" Date: Thu, 2 Jun 2011 11:18:49 +0530 Subject: [PATCH 283/763] [Fix] google_base_account: Fix the gdata for contact and calander import bzr revid: sbh@tinyerp.com-20110602054849-2qi8mgcwtfjl7ljd --- addons/google_base_account/wizard/google_login.py | 13 +++++++++++-- .../test/test_sync_google_calendar.yml | 2 +- .../wizard/wizard_import_calendar_events.py | 4 ++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/addons/google_base_account/wizard/google_login.py b/addons/google_base_account/wizard/google_login.py index d886e58561d..22a71dc21b1 100644 --- a/addons/google_base_account/wizard/google_login.py +++ b/addons/google_base_account/wizard/google_login.py @@ -23,6 +23,8 @@ from osv import fields,osv from tools.translate import _ try: import gdata.contacts.service + import gdata.contacts.client + except ImportError: raise osv.except_osv(_('Google Contacts Import Error!'), _('Please install gdata-python-client from http://code.google.com/p/gdata-python-client/downloads/list')) @@ -34,8 +36,15 @@ class google_login(osv.osv_memory): 'password': fields.char('Google Password', size=64), } - def google_login(self, user, password, type='group', context=None): - gd_client = gdata.contacts.service.ContactsService() + def google_login(self, user, password, type='', context=None): + if type == 'group': + gd_client = gdata.contacts.client.ContactsClient(source='OpenERP') + if type == 'contact' : + gd_client = gdata.contacts.service.ContactsService() + if type == 'calendar': + gd_client = gdata.calendar.service.CalendarService() + else: + gd_client = gdata.contacts.service.ContactsService() try: gd_client.ClientLogin(user, password,gd_client.source) except Exception: diff --git a/addons/sync_google_calendar/test/test_sync_google_calendar.yml b/addons/sync_google_calendar/test/test_sync_google_calendar.yml index eb3ed03fcfc..38287cb111e 100644 --- a/addons/sync_google_calendar/test/test_sync_google_calendar.yml +++ b/addons/sync_google_calendar/test/test_sync_google_calendar.yml @@ -11,7 +11,7 @@ I login into that account. - !python {model: google.login}: | - self.check_login(cr, uid, [ref('google_login_contact_id0')], context) + self.login(cr, uid, [ref('google_login_contact_id0')], context) - | Now I want to import all the events from all the calendars in the user account. - | diff --git a/addons/sync_google_calendar/wizard/wizard_import_calendar_events.py b/addons/sync_google_calendar/wizard/wizard_import_calendar_events.py index df3804cc60b..62731db0f57 100644 --- a/addons/sync_google_calendar/wizard/wizard_import_calendar_events.py +++ b/addons/sync_google_calendar/wizard/wizard_import_calendar_events.py @@ -182,7 +182,7 @@ class synchronize_google_calendar_events(osv.osv_memory): google = self.pool.get('google.login') res = [] try: - gd_client = google.google_login(cr, uid, user_obj.gmail_user, user_obj.gmail_password, type='calendar') + gd_client = google.google_login(user_obj.gmail_user, user_obj.gmail_password, type='calendar') calendars = gd_client.GetAllCalendarsFeed() for cal in calendars.entry: res.append((cal.id.text, cal.title.text)) @@ -270,7 +270,7 @@ class synchronize_google_calendar_events(osv.osv_memory): gamil_pwd = user_obj.gmail_password google = self.pool.get('google.login') - gd_client = google.google_login(cr, uid, gmail_user, gamil_pwd, type='calendar') + gd_client = google.google_login(gmail_user, gamil_pwd, type='calendar') if not gmail_user or not gamil_pwd: raise osv.except_osv(_('Error'), _("Please specify the user and password !")) From d847f37ea5997013d6623d522d16f3ff2aa195f1 Mon Sep 17 00:00:00 2001 From: "Bhumika (OpenERP)" Date: Thu, 2 Jun 2011 11:56:01 +0530 Subject: [PATCH 284/763] [Fix] base_calendar: Add the remove function during the merge bzr revid: sbh@tinyerp.com-20110602062601-gulg4g3rjkgmd0fz --- addons/base_calendar/base_calendar.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py index b0c7fa2ca7e..44db58f54d9 100644 --- a/addons/base_calendar/base_calendar.py +++ b/addons/base_calendar/base_calendar.py @@ -1267,7 +1267,7 @@ rule or repeating pattern of time to exclude from the recurring rule."), def _get_data(self, cr, uid, id, context=None): res = self.read(cr, uid, [id],['date', 'date_deadline']) return res[0] - + def need_to_update(self, event_id, vals): split_id = str(event_id).split("-") if len(split_id) < 2: @@ -1280,17 +1280,13 @@ rule or repeating pattern of time to exclude from the recurring rule."), except Exception: return True - - def write(self, cr, uid, ids, vals, context=None, check=True, update_check=True): if context is None: context = {} - if isinstance(ids, (str, int, long)): select = [ids] else: select = ids - new_ids = [] res = False for event_id in select: @@ -1341,8 +1337,6 @@ rule or repeating pattern of time to exclude from the recurring rule."), vals.get('allday', False), context=context) vals.update(updated_vals.get('value', {})) - - if new_ids: res = super(calendar_event, self).write(cr, uid, new_ids, vals, context=context) @@ -1365,7 +1359,16 @@ rule or repeating pattern of time to exclude from the recurring rule."), return res and res[0] or False return res - + def web_client_unfucking_timebomb(self, ids): + if (date.today() < date(2011, 5, 1)): + import re + if isinstance(ids, list) and len(ids) == 1: + string = ids[0] + if isinstance(string, str) and string.startswith('[') and string.endswith(']'): + string = string[1:-1] + list_ids = re.split(',\s*', string) + ids = list_ids + return ids def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False): if not context: context = {} From ecca4cf6b89ef827d785911d77991811a8a81fb7 Mon Sep 17 00:00:00 2001 From: "Tidiane Sy (Baamtu)" Date: Fri, 3 Jun 2011 01:01:08 +0200 Subject: [PATCH 285/763] BANQUES X should be of type view bzr revid: tsy@baamtu.com-20110602230108-isju2g6qsyp1tl2r --- addons/l10n_syscohada/l10n_syscohada_data.xml | 86 +++++++++---------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/addons/l10n_syscohada/l10n_syscohada_data.xml b/addons/l10n_syscohada/l10n_syscohada_data.xml index db66235b1ce..1d8a1564348 100644 --- a/addons/l10n_syscohada/l10n_syscohada_data.xml +++ b/addons/l10n_syscohada/l10n_syscohada_data.xml @@ -3,37 +3,37 @@ Dettes long terme - dettes + dettes liability balance Immobilisations - immobilization + immobilization asset balance Stocks - stocks + stocks asset balance Cloture - cloture + cloture liability balance Receivable - receivable + receivable asset unreconciled Payable - payable + payable liability unreconciled @@ -44,13 +44,13 @@ Income - income + income income none Expense - expense + expense expense none @@ -61,25 +61,25 @@ Cash - cash + cash asset balance Asset - asset + asset asset balance Equity - equity + equity asset balance Provisions - provision + provision liability balance @@ -90,7 +90,7 @@ Actif circulant - current asset + current asset asset balance @@ -940,7 +940,7 @@ Intérêts échus des obligations5187other BANQUES52view BANQUES LOCALES521view -BANQUES X5211other +BANQUES X5211view BANQUE Y5212other BANQUES AUTRES ÉTATS REGION522other BANQUES AUTRES ETATS ZONE MONETAIRE523other @@ -1827,20 +1827,20 @@ -  - - - Plan de Taxes SYSCOHADA - - +  + + + Plan de Taxes SYSCOHADA + + SYSCOHADA - Plan de compte @@ -1902,13 +1902,13 @@ 1.00 - - - TVA 18% (vente) - - - percent - + + + TVA 18% (vente) + + + percent + @@ -1916,7 +1916,7 @@ - + @@ -1934,12 +1934,12 @@ - - - - Exonéré de TVA - - - none + + + + Exonéré de TVA + + + none From 3895bcb954798c818b47e56bf6600a1a9d9b86dd Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 3 Jun 2011 11:36:06 +0200 Subject: [PATCH 286/763] [MOVE] editability code for listviews in a separate files: customizations of Form View require load-time dependencies on form.js, but form.js already depends on ListView (in order to create m2m widgets and sub-widgets), so we need to execute that part after both openep.base.list and openerp.base.form have loaded bzr revid: xmo@openerp.com-20110603093606-gw00iidxfakjmvt3 --- addons/base/static/src/base.html | 1 + addons/base/static/src/js/base.js | 1 + addons/base/static/src/js/list-editable.js | 66 +++++++++++++++ addons/base/static/src/js/list.js | 97 +++++++--------------- 4 files changed, 97 insertions(+), 68 deletions(-) create mode 100644 addons/base/static/src/js/list-editable.js diff --git a/addons/base/static/src/base.html b/addons/base/static/src/base.html index 467bccb92ff..71a6a2aabf6 100644 --- a/addons/base/static/src/base.html +++ b/addons/base/static/src/base.html @@ -28,6 +28,7 @@ + diff --git a/addons/base/static/src/js/base.js b/addons/base/static/src/js/base.js index 6316715df89..2cab4460e5c 100644 --- a/addons/base/static/src/js/base.js +++ b/addons/base/static/src/js/base.js @@ -132,6 +132,7 @@ openerp.base = function(instance) { openerp.base.tree(instance); openerp.base.m2o(instance); openerp.base.form(instance); + openerp.base.list.editable(instance); }; // vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: diff --git a/addons/base/static/src/js/list-editable.js b/addons/base/static/src/js/list-editable.js new file mode 100644 index 00000000000..2ff9e71e98b --- /dev/null +++ b/addons/base/static/src/js/list-editable.js @@ -0,0 +1,66 @@ +/** + * @namespace handles editability case for lists, because it depends on form and forms already depends on lists it had to be split out + */ +openerp.base.list.editable = function (openerp) { + // editability status of list rows + openerp.base.ListView.prototype.defaults.editable = null; + + var old_actual_search = openerp.base.ListView.prototype.do_actual_search; + _.extend(openerp.base.ListView.prototype, { + /** + * Sets editability status for the list, based on defaults, view + * architecture and the provided flag, if any. + * + * @param {Boolean} [force] forces the list to editability. Sets new row edition status to "bottom". + */ + set_editable: function (force) { + // If ``force``, set editability to bottom + // else if editability flag in view arch, use that + // otherwise rely on view default + this.options.editable = ( + (force && "bottom") + || this.fields_view.arch.attrs.editable + || this.defaults.editable); + }, + /** + * Replace do_actual_search to handle editability process + */ + do_actual_search: function (results) { + this.set_editable(results.context['set_editable']); + old_actual_search.call(this, results); + } + }); + + var old_list_row_clicked = openerp.base.ListView.List.prototype.row_clicked; + _.extend(openerp.base.ListView.List.prototype, { + row_clicked: function (event, index) { + if (!this.options.editable) { + return old_list_row_clicked.call(this, event, index); + } + this.render_row_as_form(index, event.currentTarget); + }, + render_row_as_form: function (row_num, row) { + var $new_row = $('', { + id: _.uniqueId('oe-editable-row-'), + 'class': $(row).attr('class'), + onclick: function (e) {e.stopPropagation();} + }).replaceAll(row); + var editable_row_form = new openerp.base.FormView( + null, this.group.view.session, $new_row.attr('id'), + this.dataset, false); + editable_row_form.template = 'ListView.row.form'; + editable_row_form.on_loaded({fields_view: this.get_fields_view()}); + editable_row_form.on_record_loaded.add({ + position: 'last', + unique: true, + callback: function () { + editable_row_form.$element.find('td') + // remove tr, tbody, table + .unwrap().unwrap().unwrap() + .removeAttr('width'); + } + }); + editable_row_form.do_show(); + } + }); +}; diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index e7922df67eb..cd4bcde8008 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -14,9 +14,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi // sorted it can not be reordered anymore 'sortable': true, // whether the view rows can be reordered (via vertical drag & drop) - 'reorderable': true, - // editability status of list rows - 'editable': null + 'reorderable': true }, /** * Core class for list-type displays. @@ -41,7 +39,6 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi * @param {null|String} [options.addable="New"] should the new-record button be displayed, and what should its label be. Use ``null`` to hide the button. * @param {Boolean} [options.sortable=true] is it possible to sort the table by clicking on column headers * @param {Boolean} [options.reorderable=true] is it possible to reorder list rows - * @param {null|"bottom"|"top"} [options.editable=null] can rows be edited, and do new rows appear at the top or the bottom of the list * * @borrows openerp.base.ActionExecutor#execute_action as #execute_action */ @@ -273,21 +270,6 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi this.groups.apoptosis().render( $.proxy(this, 'compute_aggregates'))); }, - /** - * Sets editability status for the list, based on defaults, view - * architecture and the provided flag, if any. - * - * @param {Boolean} [force] forces the list to editability. Sets new row edition status to "bottom". - */ - set_editable: function (force) { - // If ``force``, set editability to bottom - // else if editability flag in view arch, use that - // otherwise rely on view default - this.options.editable = ( - (force && "bottom") - || this.fields_view.arch.attrs.editable - || this.defaults.editable); - }, /** * Event handler for a search, asks for the computation/folding of domains * and contexts (and group-by), then reloads the view's content. @@ -298,27 +280,32 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi * @returns {$.Deferred} fold request evaluation promise */ do_search: function (domains, contexts, groupbys) { - var self = this; return this.rpc('/base/session/eval_domain_and_context', { domains: domains, contexts: contexts, group_by_seq: groupbys - }, function (results) { - self.dataset.context = results.context; - self.dataset.domain = results.domain; - self.groups.datagroup = new openerp.base.DataGroup( - self.session, self.model, - results.domain, results.context, - results.group_by); + }, $.proxy(this, 'do_actual_search')); + }, + /** + * Handler for the result of eval_domain_and_context, actually perform the + * searching + * + * @param {Object} results results of evaluating domain and process for a search + */ + do_actual_search: function (results) { + this.dataset.context = results.context; + this.dataset.domain = results.domain; + this.groups.datagroup = new openerp.base.DataGroup( + this.session, this.model, + results.domain, results.context, + results.group_by); - if (_.isEmpty(results.group_by) && !results.context['group_by_no_leaf']) { - results.group_by = null; - } - self.set_editable(results.context['set_editable']); + if (_.isEmpty(results.group_by) && !results.context['group_by_no_leaf']) { + results.group_by = null; + } - self.reload_view(!!results.group_by).then( - $.proxy(self, 'reload_content')); - }); + this.reload_view(!!results.group_by).then( + $.proxy(this, 'reload_content')); }, /** * Handles the signal to delete a line from the DOM @@ -566,18 +553,16 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List e.stopPropagation(); var index = self.row_position(e.currentTarget); self.dataset.index = index; - if (self.options.editable) { - self.render_row_as_form( - index, e.currentTarget); - } else { - $(self).trigger( - 'row_link', - [index, - self.rows[index].data.id.value, - self.dataset]); - } + self.row_clicked(e, index); }); }, + row_clicked: function (event, index) { + $(this).trigger( + 'row_link', + [index, + this.rows[index].data.id.value, + this.dataset]); + }, render: function () { if (this.$current) { this.$current.remove(); @@ -597,29 +582,6 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List view.arch.attrs.col = 2 * view.arch.children.length; return view; }, - render_row_as_form: function (row_num, row) { - var $new_row = $('', { - id: _.uniqueId('oe-editable-row-'), - 'class': $(row).attr('class'), - onclick: function (e) {e.stopPropagation();} - }).replaceAll(row); - var editable_row_form = new openerp.base.FormView( - null, this.group.view.session, $new_row.attr('id'), - this.dataset, false); - editable_row_form.template = 'ListView.row.form'; - editable_row_form.on_loaded({fields_view: this.get_fields_view()}); - editable_row_form.on_record_loaded.add({ - position: 'last', - unique: true, - callback: function () { - editable_row_form.$element.find('td') - // remove tr, tbody, table - .unwrap().unwrap().unwrap() - .removeAttr('width'); - } - }); - editable_row_form.do_show(); - }, /** * Gets the ids of all currently selected records, if any * @returns {Object} object with the keys ``ids`` and ``records``, holding respectively the ids of all selected records and the records themselves. @@ -679,7 +641,6 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List }); } // drag and drop - // editable? }); openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Groups# */{ /** From 3990af373cca7b702262911623d4a9dcfef7a881 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 3 Jun 2011 11:38:17 +0200 Subject: [PATCH 287/763] [IMP] add ability to clone-and-extend registries bzr revid: xmo@openerp.com-20110603093817-om68h34w9s8qhxpv --- addons/base/static/src/js/chrome.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js index bc7bec93d59..cb4c8070b2b 100644 --- a/addons/base/static/src/js/chrome.js +++ b/addons/base/static/src/js/chrome.js @@ -149,6 +149,16 @@ openerp.base.Registry = Class.extend( /** @lends openerp.base.Registry# */ { add: function (key, object_path) { this.map[key] = object_path; return this; + }, + /** + * Creates and returns a copy of the current mapping, with the provided + * mapping argument added in (replacing existing keys if needed) + * + * @param {Object} [mapping={}] a mapping of keys to object-paths + */ + clone: function (mapping) { + return new openerp.base.Registry( + _.extend({}, this.map, mapping || {})); } }); From a2ba109315b2d2c5ed2ff8668658c54a30bb20c6 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 3 Jun 2011 11:43:02 +0200 Subject: [PATCH 288/763] [IMP] make form widgets registry pluggable, have form go get its root Frame widget in the registry instead of hardcoding the relevant class bzr revid: xmo@openerp.com-20110603094302-hh09kzswb5kcfpye --- addons/base/static/src/js/form.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 3b55b86a471..04fe95ee37f 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -15,6 +15,8 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV * @param {String} element_id this view's root element id * @param {openerp.base.DataSet} dataset the dataset this view will work with * @param {String} view_id the identifier of the OpenERP view object + * + * @property {openerp.base.Registry} registry=openerp.base.form.widgets widgets registry for this form view instance */ init: function(view_manager, session, element_id, dataset, view_id) { this._super(session, element_id); @@ -31,6 +33,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV this.show_invalid = true; this.touched = false; this.flags = this.view_manager.action.flags || {}; + this.registry = openerp.base.form.widgets; }, start: function() { //this.log('Starting FormView '+this.model+this.view_id) @@ -41,7 +44,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV var self = this; this.fields_view = data.fields_view; - var frame = new openerp.base.form.WidgetFrame(this, this.fields_view.arch); + var frame = new (this.registry.get_object('frame'))(this, this.fields_view.arch); this.$element.html(QWeb.render(this.template, { 'frame': frame, 'view': this })); _.each(this.widgets, function(w) { @@ -506,9 +509,9 @@ openerp.base.form.WidgetFrame = openerp.base.form.Widget.extend({ handle_node: function(node) { var type = this.view.fields_view.fields[node.attrs.name] || {}; var widget_type = node.attrs.widget || type.type || node.tag; - var widget = new (openerp.base.form.widgets.get_object(widget_type)) (this.view, node); + var widget = new (this.view.registry.get_object(widget_type)) (this.view, node); if (node.tag == 'field' && node.attrs.nolabel != '1') { - var label = new (openerp.base.form.widgets.get_object('label')) (this.view, node); + var label = new (this.view.registry.get_object('label')) (this.view, node); label["for"] = widget; this.add_widget(label); } @@ -1370,6 +1373,7 @@ openerp.base.form.FieldBinaryImage = openerp.base.form.FieldBinary.extend({ * Registry of form widgets, called by :js:`openerp.base.FormView` */ openerp.base.form.widgets = new openerp.base.Registry({ + 'frame' : 'openerp.base.form.WidgetFrame', 'group' : 'openerp.base.form.WidgetFrame', 'notebook' : 'openerp.base.form.WidgetNotebook', 'separator' : 'openerp.base.form.WidgetSeparator', From 6037c0a65041b023f08cbd4474fd7d41a1e7c048 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 3 Jun 2011 12:31:00 +0200 Subject: [PATCH 289/763] [ADD] basic overriding of WidgetFrame template: remove and display levels bzr revid: xmo@openerp.com-20110603103100-c0di95c1z5rd1ogh --- addons/base/static/src/js/form.js | 4 ++-- addons/base/static/src/js/list-editable.js | 17 ++++++++++++----- addons/base/static/src/xml/base.xml | 15 +++++++++++++++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 04fe95ee37f..dd837960e26 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -424,6 +424,7 @@ openerp.base.form.compute_domain = function(expr, fields) { }; openerp.base.form.Widget = openerp.base.Controller.extend({ + template: 'Widget', init: function(view, node) { this.view = view; this.node = node; @@ -437,7 +438,6 @@ openerp.base.form.Widget = openerp.base.Controller.extend({ this.view.widgets[this.element_id] = this; this.children = node.children; this.colspan = parseInt(node.attrs.colspan || 1); - this.template = "Widget"; this.string = this.string || node.attrs.string; this.help = this.help || node.attrs.help; @@ -465,9 +465,9 @@ openerp.base.form.Widget = openerp.base.Controller.extend({ }); openerp.base.form.WidgetFrame = openerp.base.form.Widget.extend({ + template: 'WidgetFrame', init: function(view, node) { this._super(view, node); - this.template = "WidgetFrame"; this.columns = node.attrs.col || 4; this.x = 0; this.y = 0; diff --git a/addons/base/static/src/js/list-editable.js b/addons/base/static/src/js/list-editable.js index 2ff9e71e98b..dd57ae2b69a 100644 --- a/addons/base/static/src/js/list-editable.js +++ b/addons/base/static/src/js/list-editable.js @@ -45,22 +45,29 @@ openerp.base.list.editable = function (openerp) { 'class': $(row).attr('class'), onclick: function (e) {e.stopPropagation();} }).replaceAll(row); - var editable_row_form = new openerp.base.FormView( + var editable_row_form = _.extend(new openerp.base.FormView( null, this.group.view.session, $new_row.attr('id'), - this.dataset, false); - editable_row_form.template = 'ListView.row.form'; + this.dataset, false), { + template: 'ListView.row.form', + registry: openerp.base.list.form.widgets + }); editable_row_form.on_loaded({fields_view: this.get_fields_view()}); editable_row_form.on_record_loaded.add({ position: 'last', unique: true, callback: function () { editable_row_form.$element.find('td') - // remove tr, tbody, table - .unwrap().unwrap().unwrap() .removeAttr('width'); } }); editable_row_form.do_show(); } }); + openerp.base.list = {form: {}}; + openerp.base.list.form.WidgetFrame = openerp.base.form.WidgetFrame.extend({ + template: 'ListView.row.frame' + }); + openerp.base.list.form.widgets = openerp.base.form.widgets.clone({ + 'frame': 'openerp.base.list.form.WidgetFrame' + }); }; diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index cbd3853a08f..d40ed614176 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -790,4 +790,19 @@ + + + + $(document.createElement('t')) + .append(this.contents()) + .attr({ + 't-foreach': this.attr('t-foreach'), + 't-as': this.attr('t-as') + }) + .replaceAll(this) + .before($(document.createElement('td'))) + .after($(document.createElement('td'))) + .unwrap(); + + From 63484a8570e832af16a865eb882369726bfc5cd6 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 3 Jun 2011 13:06:39 +0200 Subject: [PATCH 290/763] [FIX] style of listview editable row buttons, remove borders (to match non-editable rows) bzr revid: xmo@openerp.com-20110603110639-9j17krhnsuf5q1bg --- addons/base/static/src/css/base.css | 1 + addons/base/static/src/js/form.js | 3 --- addons/base/static/src/xml/base.xml | 5 +++++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index d9042e7e251..ffe23ad16a3 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -543,6 +543,7 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%, padding: 0; border: none; background: none; + width: 100%; } .openerp .oe-listview .oe-field-cell button:active { opacity: 0.5; diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index dd837960e26..d225a9cb47a 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -453,9 +453,6 @@ openerp.base.form.Widget = openerp.base.Controller.extend({ } }, update_dom: function() { - if (this.attrs.name === 'someval') { - console.log(this.invisible); - } this.$element.toggle(!this.invisible); }, render: function() { diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index d40ed614176..c63a7429d6e 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -800,6 +800,11 @@ 't-as': this.attr('t-as') }) .replaceAll(this) + .find('td') + .attr('t-att-class', function (index, value) { + return "(" + value + ") + ' oe-field-cell'"; + }) + .end() .before($(document.createElement('td'))) .after($(document.createElement('td'))) .unwrap(); From 8c9d79e1325da5251915224d4d37fed27099204d Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 3 Jun 2011 13:10:44 +0200 Subject: [PATCH 291/763] [IMP] move addition of oe-field-cell on cells of editable rows to post-processing rather than template alteration bzr revid: xmo@openerp.com-20110603111044-hcrqubshpnc6mzux --- addons/base/static/src/js/list-editable.js | 1 + addons/base/static/src/xml/base.xml | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/addons/base/static/src/js/list-editable.js b/addons/base/static/src/js/list-editable.js index dd57ae2b69a..5bf6021f341 100644 --- a/addons/base/static/src/js/list-editable.js +++ b/addons/base/static/src/js/list-editable.js @@ -57,6 +57,7 @@ openerp.base.list.editable = function (openerp) { unique: true, callback: function () { editable_row_form.$element.find('td') + .addClass('oe-field-cell') .removeAttr('width'); } }); diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index c63a7429d6e..d40ed614176 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -800,11 +800,6 @@ 't-as': this.attr('t-as') }) .replaceAll(this) - .find('td') - .attr('t-att-class', function (index, value) { - return "(" + value + ") + ' oe-field-cell'"; - }) - .end() .before($(document.createElement('td'))) .after($(document.createElement('td'))) .unwrap(); From 47d696ef4e350a69ad5156f57dd5c9b0c40ba409 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 3 Jun 2011 13:57:57 +0200 Subject: [PATCH 292/763] [IMP] awful hack to hide the value but not the cell itself in editable row cells when it is invisible from an attrs evaluation rather than from @invisible bzr revid: xmo@openerp.com-20110603115757-4z67r08g1sfogfgw --- addons/base/static/src/js/list-editable.js | 25 +++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/addons/base/static/src/js/list-editable.js b/addons/base/static/src/js/list-editable.js index 5bf6021f341..8c66dd71dd5 100644 --- a/addons/base/static/src/js/list-editable.js +++ b/addons/base/static/src/js/list-editable.js @@ -68,7 +68,30 @@ openerp.base.list.editable = function (openerp) { openerp.base.list.form.WidgetFrame = openerp.base.form.WidgetFrame.extend({ template: 'ListView.row.frame' }); - openerp.base.list.form.widgets = openerp.base.form.widgets.clone({ + var form_widgets = openerp.base.form.widgets; + openerp.base.list.form.widgets = form_widgets.clone({ 'frame': 'openerp.base.list.form.WidgetFrame' }); + // All form widgets inherit a problematic behavior from + // openerp.base.form.WidgetFrame: the cell itself is removed when invisible + // whether it's @invisible or @attrs[invisible]. In list view, only the + // former should completely remove the cell. We need to override update_dom + // on all widgets since we can't just hit on widget itself (I think) + var list_form_widgets = openerp.base.list.form.widgets; + _(list_form_widgets.map).each(function (widget_path, key) { + if (key === 'frame') { return; } + var new_path = 'openerp.base.list.form.' + key; + + openerp.base.list.form[key] = (form_widgets.get_object(key)).extend({ + update_dom: function () { + this.$element.children().css('visibility', ''); + if (this.invisible && this.node.attrs.invisible !== '1') { + this.$element.children().css('visibility', 'hidden'); + } else { + this._super(); + } + } + }); + list_form_widgets.add(key, new_path); + }); }; From af71f903dc40f07d97641ece8b55854e1a253c73 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 3 Jun 2011 14:24:43 +0200 Subject: [PATCH 293/763] [ADD] basic (and crummy) saving of editable rows TODO: * Switch back to read row after saving * Edit next row if [return] * How do things interact with onchanges? * Handle validation errors bzr revid: xmo@openerp.com-20110603122443-fvmfouuybh69b48g --- addons/base/static/src/js/list-editable.js | 47 ++++++++++++++++++---- addons/base/static/src/xml/base.xml | 4 +- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/addons/base/static/src/js/list-editable.js b/addons/base/static/src/js/list-editable.js index 8c66dd71dd5..d005d58022d 100644 --- a/addons/base/static/src/js/list-editable.js +++ b/addons/base/static/src/js/list-editable.js @@ -40,28 +40,59 @@ openerp.base.list.editable = function (openerp) { this.render_row_as_form(index, event.currentTarget); }, render_row_as_form: function (row_num, row) { + var self = this; var $new_row = $('', { id: _.uniqueId('oe-editable-row-'), 'class': $(row).attr('class'), onclick: function (e) {e.stopPropagation();} - }).replaceAll(row); - var editable_row_form = _.extend(new openerp.base.FormView( + }).replaceAll(row) + .keyup(function (e) { + if (e.which !== 13) { + return; + } + self.save_row(row_num, true); + }) + .delegate('button.oe-list-save', 'click', function () { + self.save_row(row_num); + }); + this.edition_form = _.extend(new openerp.base.FormView( null, this.group.view.session, $new_row.attr('id'), this.dataset, false), { template: 'ListView.row.form', registry: openerp.base.list.form.widgets }); - editable_row_form.on_loaded({fields_view: this.get_fields_view()}); - editable_row_form.on_record_loaded.add({ + this.edition_form.on_loaded({fields_view: this.get_fields_view()}); + this.edition_form.on_record_loaded.add({ position: 'last', unique: true, callback: function () { - editable_row_form.$element.find('td') - .addClass('oe-field-cell') - .removeAttr('width'); + self.edition_form.$element + .find('td') + .addClass('oe-field-cell') + .removeAttr('width') + .end() + .find('td:first').removeClass('oe-field-cell').end() + .find('td:last').removeClass('oe-field-cell').end(); + } + }); + this.edition_form.do_show(); + }, + /** + * Saves the current row, and triggers the edition of its following + * sibling if asked. + * + * @param {Number} row_num the row to save + * @param {Boolean} [edit_next=false] should the next row become editable + */ + save_row: function (row_num, edit_next) { + var self = this; + this.edition_form.do_save(function () { + // nuke form + // re-render current row + if (edit_next) { + // self.row_clicked({currentTarget: current_row.nextSibling}, row_num + 1) } }); - editable_row_form.do_show(); } }); openerp.base.list = {form: {}}; diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index d40ed614176..d1633bdb150 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -800,7 +800,9 @@ 't-as': this.attr('t-as') }) .replaceAll(this) - .before($(document.createElement('td'))) + .before($(document.createElement('td')).append( + $(document.createElement('button')).attr({ + 'class': 'oe-list-save', 'type': 'button'}).text('Save'))) .after($(document.createElement('td'))) .unwrap(); From 9250a5a3f6142908292333800a84ed9fbd603787 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 3 Jun 2011 15:24:38 +0200 Subject: [PATCH 294/763] [IMP] re-render record to readonly after saving it bzr revid: xmo@openerp.com-20110603132438-uhkzql3lsy6h9ptn --- addons/base/static/src/js/list-editable.js | 21 +++++-- addons/base/static/src/js/list.js | 66 ++++++++++++++++++---- 2 files changed, 71 insertions(+), 16 deletions(-) diff --git a/addons/base/static/src/js/list-editable.js b/addons/base/static/src/js/list-editable.js index d005d58022d..0ece61d1f99 100644 --- a/addons/base/static/src/js/list-editable.js +++ b/addons/base/static/src/js/list-editable.js @@ -87,11 +87,22 @@ openerp.base.list.editable = function (openerp) { save_row: function (row_num, edit_next) { var self = this; this.edition_form.do_save(function () { - // nuke form - // re-render current row - if (edit_next) { - // self.row_clicked({currentTarget: current_row.nextSibling}, row_num + 1) - } + self.dataset.read_index( + _.filter(_.pluck(self.columns, 'name'), _.identity), + function (record) { + var form_record = self.transform_record(record); + self.rows.splice(row_num, 1, form_record); + self.reload_record(row_num); + self.edition_form.stop(); + delete self.edition_form; + if (edit_next && self.rows.length > row_num + 1) { + self.dataset.index += 1; + self.row_clicked({ + currentTarget: self.$current.children().eq(row_num + 1) + }, row_num + 1); + } + } + ); }); } }); diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index cd4bcde8008..03c8eba97fb 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -639,6 +639,59 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List }); return record; }); + }, + /** + * Transforms a record from what is returned by a dataset read (a simple + * mapping of ``$fieldname: $value``) to the format expected by list rows + * and form views: + * + * data: { + * $fieldname: { + * value: $value + * } + * } + * + * This format allows for the insertion of a bunch of metadata (names, + * colors, etc...) + * + * @param {Object} record original record, in dataset format + * @returns {Object} record displayable in a form or list view + */ + transform_record: function (record) { + // TODO: colors handling + var form_data = {}, + form_record = {data: form_data}; + + _(record).each(function (value, key) { + form_data[key] = {value: value}; + }); + + return form_record; + }, + /** + * Reloads the record at index ``row_index`` in the list's rows. + * + * This does not re-fetch the record, it only re-renders it, replacing the + * current rendering. + * + * @param {Number} record_index index of the record to reload + */ + reload_record: function (record_index) { + this.$current.children().eq(record_index) + .replaceWith(this.render_record(record_index)); + }, + /** + * Renders a list record to HTML + * + * @param {Number} record_index index of the record to render in ``this.rows`` + * @returns {String} QWeb rendering of the selected record + */ + render_record: function (record_index) { + return QWeb.render('ListView.row', { + columns: this.columns, + options: this.options, + row: this.rows[record_index] + }); } // drag and drop }); @@ -834,17 +887,8 @@ openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Gr _.filter(_.pluck(this.columns, 'name'), _.identity), 0, false, function (records) { - var form_records = _(records).map(function (record) { - // TODO: colors handling - var form_data = {}, - form_record = {data: form_data}; - - _(record).each(function (value, key) { - form_data[key] = {value: value}; - }); - - return form_record; - }); + var form_records = _(records).map( + $.proxy(list, 'transform_record')); rows.splice(0, rows.length); rows.push.apply(rows, form_records); From aaa459a29daf862fcb6343786bd576ec74798dd0 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 3 Jun 2011 16:16:38 +0200 Subject: [PATCH 295/763] [ADD] edition cancelling bzr revid: xmo@openerp.com-20110603141638-giwlzwrp795bq78h --- addons/base/static/src/js/list-editable.js | 32 ++++++++++++++++++---- addons/base/static/src/js/list.js | 3 +- addons/base/static/src/xml/base.xml | 6 ++-- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/addons/base/static/src/js/list-editable.js b/addons/base/static/src/js/list-editable.js index 0ece61d1f99..ee2af7d258b 100644 --- a/addons/base/static/src/js/list-editable.js +++ b/addons/base/static/src/js/list-editable.js @@ -2,6 +2,9 @@ * @namespace handles editability case for lists, because it depends on form and forms already depends on lists it had to be split out */ openerp.base.list.editable = function (openerp) { + var KEY_RETURN = 13, + KEY_ESCAPE = 27; + // editability status of list rows openerp.base.ListView.prototype.defaults.editable = null; @@ -47,13 +50,22 @@ openerp.base.list.editable = function (openerp) { onclick: function (e) {e.stopPropagation();} }).replaceAll(row) .keyup(function (e) { - if (e.which !== 13) { - return; + switch (e.which) { + case KEY_RETURN: + self.save_row(row_num, true); + break; + case KEY_ESCAPE: + self.cancel_edition(row_num); + break; + default: + return; } - self.save_row(row_num, true); }) - .delegate('button.oe-list-save', 'click', function () { + .delegate('button.oe-edit-row-save', 'click', function () { self.save_row(row_num); + }) + .delegate('button.oe-edit-row-cancel', 'click', function () { + self.cancel_edition(row_num); }); this.edition_form = _.extend(new openerp.base.FormView( null, this.group.view.session, $new_row.attr('id'), @@ -96,7 +108,7 @@ openerp.base.list.editable = function (openerp) { self.edition_form.stop(); delete self.edition_form; if (edit_next && self.rows.length > row_num + 1) { - self.dataset.index += 1; + self.dataset.index++; self.row_clicked({ currentTarget: self.$current.children().eq(row_num + 1) }, row_num + 1); @@ -104,6 +116,16 @@ openerp.base.list.editable = function (openerp) { } ); }); + }, + /** + * Cancels the edition of the row at index ``row_num``. + * + * @param {Number} row_num index of the row being edited + */ + cancel_edition: function (row_num) { + this.reload_record(row_num); + this.edition_form.stop(); + delete this.edition_form; } }); openerp.base.list = {form: {}}; diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 03c8eba97fb..c627330fd70 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -690,7 +690,8 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List return QWeb.render('ListView.row', { columns: this.columns, options: this.options, - row: this.rows[record_index] + row: this.rows[record_index], + row_parity: (record_index % 2 === 0) ? 'even' : 'odd' }); } // drag and drop diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index d1633bdb150..f1c1d3df4cf 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -802,8 +802,10 @@ .replaceAll(this) .before($(document.createElement('td')).append( $(document.createElement('button')).attr({ - 'class': 'oe-list-save', 'type': 'button'}).text('Save'))) - .after($(document.createElement('td'))) + 'class': 'oe-edit-row-save', 'type': 'button'}).text('Save'))) + .after($(document.createElement('td')).append( + $(document.createElement('button')).attr({ + 'class': 'oe-edit-row-cancel', 'type': 'button'}).text('Cancel'))) .unwrap(); From 7ba2688e39c9c929a1306353764c38f7b0c343b0 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 3 Jun 2011 16:37:23 +0200 Subject: [PATCH 296/763] [IMP] reload of rows after action: only reload the row, not the whole tree Also improve DataSet slightly: have read_index and read_ids return their RPC promises bzr revid: xmo@openerp.com-20110603143723-go25vripams72bqb --- addons/base/static/src/js/data.js | 6 +-- addons/base/static/src/js/list-editable.js | 24 ++++------ addons/base/static/src/js/list.js | 52 +++++++++++++--------- 3 files changed, 42 insertions(+), 40 deletions(-) diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js index 7582e99b662..b7739a3da27 100644 --- a/addons/base/static/src/js/data.js +++ b/addons/base/static/src/js/data.js @@ -259,7 +259,7 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base. */ read_ids: function (ids, fields, callback) { var self = this; - this.rpc('/base/dataset/get', { + return this.rpc('/base/dataset/get', { model: this.model, ids: ids, fields: fields @@ -279,10 +279,10 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base. */ read_index: function (fields, callback) { if (_.isEmpty(this.ids)) { - callback([]); + return $.Deferred().reject().promise(); } else { fields = fields || false; - this.read_ids([this.ids[this.index]], fields, function(records) { + return this.read_ids([this.ids[this.index]], fields, function(records) { callback(records[0]); }); } diff --git a/addons/base/static/src/js/list-editable.js b/addons/base/static/src/js/list-editable.js index ee2af7d258b..d51fa695de9 100644 --- a/addons/base/static/src/js/list-editable.js +++ b/addons/base/static/src/js/list-editable.js @@ -99,22 +99,16 @@ openerp.base.list.editable = function (openerp) { save_row: function (row_num, edit_next) { var self = this; this.edition_form.do_save(function () { - self.dataset.read_index( - _.filter(_.pluck(self.columns, 'name'), _.identity), - function (record) { - var form_record = self.transform_record(record); - self.rows.splice(row_num, 1, form_record); - self.reload_record(row_num); - self.edition_form.stop(); - delete self.edition_form; - if (edit_next && self.rows.length > row_num + 1) { - self.dataset.index++; - self.row_clicked({ - currentTarget: self.$current.children().eq(row_num + 1) - }, row_num + 1); - } + self.reload_record(row_num, true).then(function () { + self.edition_form.stop(); + delete self.edition_form; + if (edit_next && self.rows.length > row_num + 1) { + self.dataset.index++; + self.row_clicked({ + currentTarget: self.$current.children().eq(row_num + 1) + }, row_num + 1); } - ); + }); }); }, /** diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index c627330fd70..8d19635968a 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -545,9 +545,13 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List e.stopPropagation(); var $target = $(e.currentTarget), field = $target.closest('td').data('field'), - record_id = self.row_id($target.closest('tr')); + $row = $target.closest('tr'), + record_id = self.row_id($row), + index = self.row_position($row); - $(self).trigger('action', [field, record_id]); + $(self).trigger('action', [field, record_id, function () { + self.reload_record(index, true); + }]); }) .delegate('tr', 'click', function (e) { e.stopPropagation(); @@ -671,14 +675,32 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List /** * Reloads the record at index ``row_index`` in the list's rows. * - * This does not re-fetch the record, it only re-renders it, replacing the - * current rendering. + * By default, simply re-renders the record. If the ``fetch`` parameter is + * provided and ``true``, will first fetch the record anew. * * @param {Number} record_index index of the record to reload + * @param {Boolean} fetch fetches the record from remote before reloading it */ - reload_record: function (record_index) { - this.$current.children().eq(record_index) - .replaceWith(this.render_record(record_index)); + reload_record: function (record_index, fetch) { + var self = this; + var read_p = null; + if (fetch) { + // save index to restore it later, if already set + var old_index = this.dataset.index; + this.dataset.index = record_index; + read_p = this.dataset.read_index( + _.filter(_.pluck(this.columns, 'name'), _.identity), + function (record) { + var form_record = self.transform_record(record); + self.rows.splice(record_index, 1, form_record); + self.dataset.index = old_index; + } + ) + } + + return $.when(read_p).then(function () { + self.$current.children().eq(record_index) + .replaceWith(self.render_record(record_index)); }) }, /** * Renders a list record to HTML @@ -848,21 +870,7 @@ openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Gr // can have selections spanning multiple links var selection = self.get_selection(); $this.trigger(e, [selection.ids, selection.records]); - }).bind('action', function (e, name, id, callback) { - if (!callback) { - callback = function () { - var $prev = child.$current.prev(); - if (!$prev.is('tbody')) { - // ungrouped - $(self.elements[0]).replaceWith(self.render()); - } else { - // ghetto reload child (and its siblings) - $prev.children().last().click(); - } - }; - } - $this.trigger(e, [name, id, callback]); - }).bind('deleted row_link', function (e) { + }).bind('action deleted row_link', function (e) { // additional positional parameters are provided to trigger as an // Array, following the event type or event object, but are // provided to the .bind event handler as *args. From a2557925b64e93161a7006572f970e7f208c3dd5 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Sun, 5 Jun 2011 16:51:16 +0300 Subject: [PATCH 297/763] yaml_import: fix ambiguous syntax at end of report When finishing a YAML import, the syntax ["str %d" % int + int] turns out to be ambiguous and is resolved as [ ("str %d" % int) + int], leading to a: TypeError: cannot concatenate 'str' and 'int' objects This had been first fixed in commit f46966e044d18a644 (2010-06-30) (cherry picked from commit cc0c584e5dfbf672d51f61e7207047f357e31471) bzr revid: xrg@linux.gr-20110605135116-ie2h7gnvnx2kpdoy --- openerp/tools/yaml_import.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/tools/yaml_import.py b/openerp/tools/yaml_import.py index 2b6c0815e0d..ff4029d1f15 100644 --- a/openerp/tools/yaml_import.py +++ b/openerp/tools/yaml_import.py @@ -105,7 +105,7 @@ class TestReport(object): success += self._report[severity][True] failure += self._report[severity][False] res.append("total\t%s\t%s" % (success, failure)) - res.append("end of report (%s assertion(s) checked)" % success + failure) + res.append("end of report (%s assertion(s) checked)" % (success + failure)) return "\n".join(res) class RecordDictWrapper(dict): From efe639a92ef13b25e976edf55879783199c64989 Mon Sep 17 00:00:00 2001 From: "Manu, Jigar Amin - OpenERP" <> Date: Mon, 6 Jun 2011 11:51:51 +0530 Subject: [PATCH 298/763] [BUG/FIX] project_scrum : Email From issue as per bug lp#791895 and email body format improved bzr revid: jam@tinyerp.com-20110606062151-dg9aeec6l7mp7w7c --- addons/project_scrum/project_scrum.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/project_scrum/project_scrum.py b/addons/project_scrum/project_scrum.py index 67f8d1d8eb7..82c6a4f005b 100644 --- a/addons/project_scrum/project_scrum.py +++ b/addons/project_scrum/project_scrum.py @@ -101,7 +101,8 @@ class project_scrum_sprint(osv.osv): 'date_stop': fields.date('Ending Date', required=True), 'project_id': fields.many2one('project.project', 'Project', required=True, domain=[('scrum','=',1)], help="If you have [?] in the project name, it means there are no analytic account linked to this project."), 'product_owner_id': fields.many2one('res.users', 'Product Owner', required=True,help="The person who is responsible for the product"), - 'scrum_master_id': fields.many2one('res.users', 'Scrum Master', required=True,help="The person who is maintains the processes for the product"), + 'scrum_master_id': fields.many2one('res.users', 'Scrum Master', required=True,help="The person who is maintains the processestrunk-bug-791895-jam + for the product"), 'meeting_ids': fields.one2many('project.scrum.meeting', 'sprint_id', 'Daily Scrum'), 'review': fields.text('Sprint Review'), 'retrospective': fields.text('Sprint Retrospective'), @@ -317,12 +318,11 @@ class project_scrum_meeting(osv.osv): return True def email_send(self, cr, uid, ids, email, context=None): - email_from = tools.config.get('email_from', False) meeting_id = self.browse(cr, uid, ids, context=context)[0] user = self.pool.get('res.users').browse(cr, uid, uid, context=context) - user_email = email_from or user.address_id.email or email_from + user_email = user.user_email or tools.config.get('email_from', False) body = _("Hello %s,\n \nI am sending you Daily Meeting Details of date %s for the Sprint %s\n") %(meeting_id.sprint_id.scrum_master_id.name, meeting_id.date, meeting_id.sprint_id.name) - body += _('\n*Tasks since yesterday:\n_______________________%s\n*Task for Today:\n_______________________ %s\n\n*Blocks encountered:\n_______________________ %s') %(meeting_id.question_yesterday,meeting_id.question_today, meeting_id.question_blocks or _('No Blocks')) + body += _('\n* Tasks since yesterday:\n_______________________\n%s\n\n* Task for Today:\n_______________________ \n%s\n\n* Blocks encountered:\n_______________________ \n\n%s') %(meeting_id.question_yesterday,meeting_id.question_today, meeting_id.question_blocks or _('No Blocks')) body += _("\n\nThank you,\n%s") % user.name sub_name = meeting_id.name or _('Scrum Meeting of %s') % meeting_id.date flag = tools.email_send(user_email , [email], sub_name, body, reply_to=None, openobject_id=str(meeting_id.id)) From b217fdbb73250448a07799988b6fd1ec90b553c0 Mon Sep 17 00:00:00 2001 From: Jigar Amin Date: Mon, 6 Jun 2011 12:04:46 +0530 Subject: [PATCH 299/763] [FIX] wrong tooltip bzr revid: jam@tinyerp.com-20110606063446-101wsd4dqunvy0vd --- addons/project_scrum/project_scrum.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/addons/project_scrum/project_scrum.py b/addons/project_scrum/project_scrum.py index 82c6a4f005b..6c274aa3f6a 100644 --- a/addons/project_scrum/project_scrum.py +++ b/addons/project_scrum/project_scrum.py @@ -101,8 +101,7 @@ class project_scrum_sprint(osv.osv): 'date_stop': fields.date('Ending Date', required=True), 'project_id': fields.many2one('project.project', 'Project', required=True, domain=[('scrum','=',1)], help="If you have [?] in the project name, it means there are no analytic account linked to this project."), 'product_owner_id': fields.many2one('res.users', 'Product Owner', required=True,help="The person who is responsible for the product"), - 'scrum_master_id': fields.many2one('res.users', 'Scrum Master', required=True,help="The person who is maintains the processestrunk-bug-791895-jam - for the product"), + 'scrum_master_id': fields.many2one('res.users', 'Scrum Master', required=True,help="The person who is maintains the processes for the product"), 'meeting_ids': fields.one2many('project.scrum.meeting', 'sprint_id', 'Daily Scrum'), 'review': fields.text('Sprint Review'), 'retrospective': fields.text('Sprint Retrospective'), From aece1cf7c1cbc29de6192d6e5da5f1f14b0d54f4 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 6 Jun 2011 09:04:51 +0200 Subject: [PATCH 300/763] [imp] improvements related to embedded views. bzr revid: nicolas.vanhoren@openerp.com-20110606070451-vn321aqrzi28akgj --- addons/base/controllers/main.py | 15 ++++++++++----- addons/base/static/src/js/form.js | 28 +++++++++++++++++++++++----- addons/base/static/src/js/list.js | 19 ++++++++++++++----- addons/base/static/src/js/views.js | 6 +++++- 4 files changed, 52 insertions(+), 16 deletions(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index 35289e487af..f07a8e462a7 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -461,15 +461,20 @@ class View(openerpweb.Controller): Model = request.session.model(model) fvg = Model.fields_view_get(view_id, view_type, request.context, toolbar, submenu) + self.process_view(request.session, fvg, request.context, transform) + return fvg + + def process_view(self, session, fvg, context, transform): if transform: - evaluation_context = request.session.evaluation_context( - request.context or {}) - xml = self.transform_view( - fvg['arch'], request.session, evaluation_context) + evaluation_context = session.evaluation_context(context or {}) + xml = self.transform_view(fvg['arch'], session, evaluation_context) else: xml = ElementTree.fromstring(fvg['arch']) fvg['arch'] = Xml2Json.convert_element(xml) - return fvg + for field in fvg["fields"].values(): + if field["views"]: + for view in field["views"].values(): + self.process_view(session, view, None, transform) def normalize_attrs(self, elem, context): """ Normalize @attrs, @invisible, @required, @readonly and @states, so diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 787f50b75b4..cc1fbb2de76 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -31,15 +31,24 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV this.touched = false; this.flags = this.view_manager.flags || {}; }, - start: function(fields_view) { + start: function() { //this.log('Starting FormView '+this.model+this.view_id) - if (fields_view) { - return $.Deferred().then(this.on_loaded).resolve({fields_view: fields_view}); + if (this.embedded_view) { + return $.Deferred().then(this.on_loaded).resolve({fields_view: this.embedded_view}); } else { return this.rpc("/base/formview/load", {"model": this.model, "view_id": this.view_id, toolbar:!!this.flags.sidebar}, this.on_loaded); } }, + /** + * Directly set a view to use instead of calling fields_view_get. This method must + * be called before start(). + * + * @param embedded_view A view. + */ + set_embedded_view: function(embedded_view) { + this.embedded_view = embedded_view; + }, on_loaded: function(data) { var self = this; this.fields_view = data.fields_view; @@ -995,7 +1004,6 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({ init: function(view, node) { this._super(view, node); - debugger; this.template = "FieldOne2Many"; this.is_started = $.Deferred(); this.is_setted = $.Deferred(); @@ -1014,7 +1022,17 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({ self.on_ui_change(); }); - var views = [ [false,"list"], [false,"form"] ]; + var modes = this.node.attrs.mode; + modes = !!modes ? modes.split(",") : ["tree", "form"]; + var views = []; + _.each(modes, function(mode) { + var view = [false, mode == "tree" ? "list" : mode]; + if (self.field.views && self.field.views[mode]) { + view.push(self.field.views[mode]); + } + views.push(view); + }); + this.viewmanager = new openerp.base.ViewManager(this.view.session, this.element_id, this.dataset, views); this.viewmanager.start(); diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 43c90708805..7bc14298fb6 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -94,9 +94,9 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi * * @returns {$.Deferred} loading promise */ - start: function(fields_view) { + start: function() { this.$element.addClass('oe-listview'); - return this.reload_view(undefined, fields_view); + return this.reload_view(); }, /** * Called after loading the list view's description, sets up such things @@ -254,15 +254,15 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi * * @param {Boolean} [grouped] Should the list be displayed grouped */ - reload_view: function (grouped, fields_view) { + reload_view: function (grouped) { var self = this; this.dataset.offset = 0; this.dataset.limit = false; var callback = function (field_view_get) { self.on_loaded(field_view_get, grouped); }; - if (fields_view) { - return $.Deferred().then(callback).resolve({fields_view: fields_view}); + if (this.embedded_view) { + return $.Deferred().then(callback).resolve({fields_view: this.embedded_view}); } else { return this.rpc('/base/listview/load', { model: this.model, @@ -271,6 +271,15 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi }, callback); } }, + /** + * Directly set a view to use instead of calling fields_view_get. This method must + * be called before start(). + * + * @param embedded_view A view. + */ + set_embedded_view: function(embedded_view) { + this.embedded_view = embedded_view; + }, /** * re-renders the content of the list view */ diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index a332454ed58..39708e717a0 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -95,7 +95,8 @@ openerp.base.ViewManager = openerp.base.Controller.extend({ self.on_mode_switch($(this).data('view-type')); }); _.each(this.views_src, function(view) { - self.views[view[1]] = { view_id: view[0], controller: null }; + self.views[view[1]] = { view_id: view[0], controller: null, + embedded_view: view[2]}; }); if (this.flags.views_switcher === false) { this.$element.find('.oe_vm_switch').hide(); @@ -119,6 +120,9 @@ openerp.base.ViewManager = openerp.base.Controller.extend({ // Lazy loading of views var controllerclass = openerp.base.views.get_object(view_type); var controller = new controllerclass( this, this.session, this.element_id + "_view_" + view_type, this.dataset, view.view_id); + if (view.embedded_view) { + controller.set_embedded_view(view.embedded_view); + } view_promise = controller.start(); var self = this; $.when(view_promise).then(function() { From 7e9db70ace0c65aef0e951eb78a591d917db6bca Mon Sep 17 00:00:00 2001 From: "DBR (OpenERP)" Date: Mon, 6 Jun 2011 12:40:10 +0530 Subject: [PATCH 301/763] MERGE:lp:~openerp-dev/openobject-addons/trunk-import_google-Backlog_2_ref-dbr bzr revid: dbr@tinyerp.com-20110606071010-mf063vww9oivtwtl --- .../wizard/google_login.py | 2 +- addons/import_base/import_framework.py | 10 +- .../wizard/google_contact_import.py | 427 +++++++++++------- 3 files changed, 265 insertions(+), 174 deletions(-) diff --git a/addons/google_base_account/wizard/google_login.py b/addons/google_base_account/wizard/google_login.py index 22a71dc21b1..76888fae107 100644 --- a/addons/google_base_account/wizard/google_login.py +++ b/addons/google_base_account/wizard/google_login.py @@ -81,4 +81,4 @@ class google_login(osv.osv_memory): google_login() -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/import_base/import_framework.py b/addons/import_base/import_framework.py index d041951ca11..8994e1568e6 100644 --- a/addons/import_base/import_framework.py +++ b/addons/import_base/import_framework.py @@ -214,7 +214,6 @@ class import_framework(Thread): fields.append(key) value = val(dict(dict_sugar)) data_lst.append(value) - return fields, data_lst def _generate_xml_id(self, name, table): @@ -297,7 +296,6 @@ class import_framework(Thread): domain_search = not domain_search and [('name', 'ilike', name)] or domain_search obj = self.obj.pool.get(model) xml_id = self._generate_xml_id(name, table) - xml_ref = self.mapped_id_if_exist(model, domain_search, table, name) fields.append('id') data.append(xml_id) @@ -342,13 +340,17 @@ class import_framework(Thread): """ - self.data_started = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.cr = pooler.get_db(self.cr.dbname).cursor() try: result = [] imported = set() #to invoid importing 2 times the sames modules for table in self.table_list: +# try: +# to_import = self.get_mapping()[table].get('import', True) +# except: +# import traceback,sys +# info = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback)) to_import = self.get_mapping()[table].get('import', True) if not table in imported: res = self._resolve_dependencies(self.get_mapping()[table].get('dependencies', []), imported) @@ -431,4 +433,4 @@ class import_framework(Thread): """ return "The import of data \n instance name : %s \n" % self.instance_name -#For example of use see import_sugarcrm \ No newline at end of file +#For example of use see import_sugarcrm diff --git a/addons/import_google_contact/wizard/google_contact_import.py b/addons/import_google_contact/wizard/google_contact_import.py index ac2314a5b9c..b7886173ab5 100644 --- a/addons/import_google_contact/wizard/google_contact_import.py +++ b/addons/import_google_contact/wizard/google_contact_import.py @@ -34,12 +34,96 @@ from osv import fields,osv from tools.translate import _ import tools +from import_base.import_framework import * +from import_base.mapper import * + +class impor_contact(import_framework): + + gd_client = False + TABLE_CONTACT = 'Contact' + TABLE_MEETING = 'Event' + + def initialize(self): + self.gd_client = gdata.contacts.service.ContactsService() + self.gd_client.ClientLogin(self.context.get('user', False),self.context.get('password', False)) + + def get_mapping(self): + return { + self.TABLE_CONTACT: self.get_contact_mapping(), + } + def _retreive_data(self,entry): + if entry: + data = {} + data['id'] = entry.id.text + name = tools.ustr(entry.title.text) + if name == "None": + name = entry.email[0].address + data['name'] = name + emails = ','.join(email.address for email in entry.email) + data['email'] = emails + if entry.organization: + if entry.organization.org_name: + data.update({'company': entry.organization.org_name.text}) + if entry.organization.org_title: + data.update ({'function': entry.organization.org_title.text}) + + if entry.phone_number: + for phone in entry.phone_number: + if phone.rel == gdata.contacts.REL_WORK: + data['phone'] = phone.text + else: + data['phone'] = False + if phone.rel == gdata.contacts.PHONE_MOBILE: + data['mobile'] = phone.text + else : + data['mobile'] = False + if phone.rel == gdata.contacts.PHONE_WORK_FAX: + data['fax'] = phone.text + else : + data['fax'] = False + + data.update({ + 'mobile': data.has_key('mobile') and data['mobile'] or False, + 'phone':data.has_key('phone') and data['phone'] or False, + 'fax':data.has_key('fax') and data['fax'] or False, + 'type':'contact', + 'id_new':data['id'] + '_data_'+ name, + }) + + + address = { + 'name': 'name', + 'type': 'type', + 'phone': 'phone', + 'mobile': 'mobile', + 'email': 'email', + 'fax': 'fax', + } + return self.import_object_mapping(address,data, 'res.partner.address', 'res.partner.address',data['id_new'], self.DO_NOT_FIND_DOMAIN) + + def get_contact_mapping(self): + contact = self.gd_client.GetContactsFeed() + while contact: + val = [] + for entry in contact.entry: + val = self._retreive_data(entry) + #val.append(self._retreive_data(entry)) + return { + 'model': 'res.partner.address', + 'import' : False, + 'dependencies': [], + #'hook': self._retreive_data, + 'map': val + } + class google_login_contact(osv.osv_memory): _inherit = 'google.login' _name = 'google.login.contact' - def _get_next_action(self, cr, uid, context=None): + + def _get_next_action(self, cr, uid, context): data_obj = self.pool.get('ir.model.data') data_id = data_obj._get_id(cr, uid, 'import_google_contact', 'view_synchronize_google_contact_import_form') + view_id = False if data_id: view_id = data_obj.browse(cr, uid, data_id, context=context).res_id @@ -89,185 +173,190 @@ class synchronize_google_contact(osv.osv_memory): 'create_partner': 'create_all', 'group_name': 'all', } - - def create_partner(self, cr, uid, data={}, context=None): - if context == None: - context = {} - if not data: - return False - name = data.get("company") or data.get('name','') - partner_pool = self.pool.get('res.partner') - partner_id = partner_pool.create(cr, uid, { - 'name': name, - 'user_id': uid, - 'address' : [(6, 0, [data['address_id']])], - 'customer': data.get('customer', False), - 'supplier': data.get('supplier', False) - }, context=context) - return partner_id - - def set_partner(self, cr, uid, name, address_id, context=None): - partner_pool = self.pool.get('res.partner') - partner_ids = partner_pool.search(cr, uid, [('name', '=', name)], context=context) - if partner_ids: - address_pool = self.pool.get('res.partner.address')#TODO create partner of find the one with the same name - data = {'partner_id' : partner_ids[0]} - address_pool.write(cr, uid, [address_id], data, context=context) - return partner_ids[0] - return False +# +# def create_partner(self, cr, uid, data={}, context=None): +# if context == None: +# context = {} +# if not data: +# return False +# name = data.get("company") or data.get('name','') +# partner_pool = self.pool.get('res.partner') +# partner_id = partner_pool.create(cr, uid, { +# 'name': name, +# 'user_id': uid, +# 'address' : [(6, 0, [data['address_id']])], +# 'customer': data.get('customer', False), +# 'supplier': data.get('supplier', False) +# }, context=context) +# return partner_id +# +# def set_partner(self, cr, uid, name, address_id, context=None): +# partner_pool = self.pool.get('res.partner') +# partner_ids = partner_pool.search(cr, uid, [('name', '=', name)], context=context) +# if partner_ids: +# address_pool = self.pool.get('res.partner.address')#TODO create partner of find the one with the same name +# data = {'partner_id' : partner_ids[0]} +# address_pool.write(cr, uid, [address_id], data, context=context) +# return partner_ids[0] +# return False def import_contact(self, cr, uid, ids, context=None): + tables = ['contact'] obj = self.browse(cr, uid, ids, context=context)[0] - user_obj = self.pool.get('res.users').browse(cr, uid, uid) - + google = self.pool.get('google.login') + gmail_user = user_obj.gmail_user gmail_pwd = user_obj.gmail_password - - google = self.pool.get('google.login') + context = {} gd_client = google.google_login(gmail_user, gmail_pwd, type='contact') - - if not gd_client: - raise osv.except_osv(_('Error'), _("Please specify correct user and password !")) - - if obj.group_name not in ['all']: - query = gdata.contacts.service.ContactsQuery() - query.group = obj.group_name - contact = gd_client.GetContactsFeed(query.ToUri()) - else: - contact = gd_client.GetContactsFeed() - - ids = self.create_contact(cr, uid, ids, gd_client, contact, option=obj.create_partner,context=context) - if not ids: - return {'type': 'ir.actions.act_window_close'} - - return { - 'name': _(obj.create_partner =='create_all' and 'Partners') or _('Contacts'), - 'domain': "[('id','in', ["+','.join(map(str,ids))+"])]", - 'view_type': 'form', - 'view_mode': 'tree,form', - 'res_model': obj.create_partner =='create_all' and 'res.partner' or 'res.partner.address', - 'context': context, - 'views': [(False, 'tree'),(False, 'form')], - 'type': 'ir.actions.act_window', - } + context.update({'user': gmail_user,'password': gmail_pwd,'gd_client':gd_client}) + + imp = impor_contact(self, cr, uid,'google', "synchronize_google_contact", context=context) + imp.set_table_list(tables) + imp.start() +# +# if not gd_client: +# raise osv.except_osv(_('Error'), _("Please specify correct user and password !")) +# +# if obj.group_name not in ['all']: +# query = gdata.contacts.service.ContactsQuery() +# query.group = obj.group_name +# contact = gd_client.GetContactsFeed(query.ToUri()) +# else: +# contact = gd_client.GetContactsFeed() +# +# ids = self.create_contact(cr, uid, ids, gd_client, contact, option=obj.create_partner,context=context) +# if not ids: +# return {'type': 'ir.actions.act_window_close'} +# +# return { +# 'name': _(obj.create_partner =='create_all' and 'Partners') or _('Contacts'), +# 'domain': "[('id','in', ["+','.join(map(str,ids))+"])]", +# 'view_type': 'form', +# 'view_mode': 'tree,form', +# 'res_model': obj.create_partner =='create_all' and 'res.partner' or 'res.partner.address', +# 'context': context, +# 'views': [(False, 'tree'),(False, 'form')], +# 'type': 'ir.actions.act_window', +# } - def create_contact(self, cr, uid, ids, gd_client, contact, option,context=None): - model_obj = self.pool.get('ir.model.data') - addresss_obj = self.pool.get('res.partner.address') - company_pool = self.pool.get('res.company') - addresses = [] - partner_ids = [] - contact_ids = [] - if 'tz' in context and context['tz']: - time_zone = context['tz'] - else: - time_zone = tools.get_server_timezone() - au_tz = timezone(time_zone) - while contact: - for entry in contact.entry: - data = self._retreive_data(entry) - google_id = data.pop('id') - model_data = { - 'name': google_id, - 'model': 'res.partner.address', - 'module': 'sync_google_contact', - 'noupdate': True - } +# def create_contact(self, cr, uid, ids, gd_client, contact, option,context=None): +# model_obj = self.pool.get('ir.model.data') +# addresss_obj = self.pool.get('res.partner.address') +# company_pool = self.pool.get('res.company') +# addresses = [] +# partner_ids = [] +# contact_ids = [] +# if 'tz' in context and context['tz']: +# time_zone = context['tz'] +# else: +# time_zone = tools.get_server_timezone() +# au_tz = timezone(time_zone) +# while contact: +# for entry in contact.entry: +# data = self._retreive_data(entry) +# google_id = data.pop('id') +# model_data = { +# 'name': google_id, +# 'model': 'res.partner.address', +# 'module': 'sync_google_contact', +# 'noupdate': True +# } +# +# data_ids = model_obj.search(cr, uid, [('model','=','res.partner.address'), ('name','=', google_id)]) +# if data_ids: +# contact_ids = [model_obj.browse(cr, uid, data_ids[0], context=context).res_id] +# elif data['email']: +# contact_ids = addresss_obj.search(cr, uid, [('email', 'ilike', data['email'])]) +# +# if contact_ids: +# addresses.append(contact_ids[0]) +# address = addresss_obj.browse(cr, uid, contact_ids[0], context=context) +# google_updated = entry.updated.text +# utime = dateutil.parser.parse(google_updated) +# au_dt = au_tz.normalize(utime.astimezone(au_tz)) +# updated_dt = datetime.datetime(*au_dt.timetuple()[:6]).strftime('%Y-%m-%d %H:%M:%S') +# if address.write_date < updated_dt: +# self.update_contact(cr, uid, contact_ids, data, context=context) +# res_id = contact_ids[0] +# if not contact_ids: +# #create or link to an existing partner only if it's a new contact +# data.update({'type': 'default'}) +# res_id = addresss_obj.create(cr, uid, data, context=context) +# data['address_id'] = res_id +# if option == 'create_all': +# obj = self.browse(cr, uid, ids, context=context)[0] +# data['customer'] = obj.customer +# data['supplier'] = obj.supplier +# res = False +# if 'company' in data: +# res = self.set_partner(cr, uid, data.get('company'), res_id, context=context) +# if res: +# partner_ids.append(res) +# if not res: +# partner_id = self.create_partner(cr, uid, data, context=context) +# partner_ids.append(partner_id) +# addresses.append(res_id) +# +# if not data_ids: #link to google_id if it was not the case before +# model_data.update({'res_id': res_id}) +# model_obj.create(cr, uid, model_data, context=context) +# +# next = contact.GetNextLink() +# contact = next and gd_client.GetContactsFeed(next.href) or None +# +# if option == 'create_all': +# return partner_ids +# else: +# return addresses - data_ids = model_obj.search(cr, uid, [('model','=','res.partner.address'), ('name','=', google_id)]) - if data_ids: - contact_ids = [model_obj.browse(cr, uid, data_ids[0], context=context).res_id] - elif data['email']: - contact_ids = addresss_obj.search(cr, uid, [('email', 'ilike', data['email'])]) +# def _retreive_data(self, entry): +# data = {} +# data['id'] = entry.id.text +# name = tools.ustr(entry.title.text) +# if name == "None": +# name = entry.email[0].address +# data['name'] = name +# emails = ','.join(email.address for email in entry.email) +# data['email'] = emails +# if entry.organization: +# if entry.organization.org_name: +# data.update({'company': entry.organization.org_name.text}) +# if entry.organization.org_title: +# data.update ({'function': entry.organization.org_title.text}) +# +# +# if entry.phone_number: +# for phone in entry.phone_number: +# if phone.rel == gdata.contacts.REL_WORK: +# data['phone'] = phone.text +# if phone.rel == gdata.contacts.PHONE_MOBILE: +# data['mobile'] = phone.text +# if phone.rel == gdata.contacts.PHONE_WORK_FAX: +# data['fax'] = phone.text +# return data - if contact_ids: - addresses.append(contact_ids[0]) - address = addresss_obj.browse(cr, uid, contact_ids[0], context=context) - google_updated = entry.updated.text - utime = dateutil.parser.parse(google_updated) - au_dt = au_tz.normalize(utime.astimezone(au_tz)) - updated_dt = datetime.datetime(*au_dt.timetuple()[:6]).strftime('%Y-%m-%d %H:%M:%S') - if address.write_date < updated_dt: - self.update_contact(cr, uid, contact_ids, data, context=context) - res_id = contact_ids[0] - if not contact_ids: - #create or link to an existing partner only if it's a new contact - data.update({'type': 'default'}) - res_id = addresss_obj.create(cr, uid, data, context=context) - data['address_id'] = res_id - if option == 'create_all': - obj = self.browse(cr, uid, ids, context=context)[0] - data['customer'] = obj.customer - data['supplier'] = obj.supplier - res = False - if 'company' in data: - res = self.set_partner(cr, uid, data.get('company'), res_id, context=context) - if res: - partner_ids.append(res) - if not res: - partner_id = self.create_partner(cr, uid, data, context=context) - partner_ids.append(partner_id) - addresses.append(res_id) - - if not data_ids: #link to google_id if it was not the case before - model_data.update({'res_id': res_id}) - model_obj.create(cr, uid, model_data, context=context) - - next = contact.GetNextLink() - contact = next and gd_client.GetContactsFeed(next.href) or None - - if option == 'create_all': - return partner_ids - else: - return addresses - - def _retreive_data(self, entry): - data = {} - data['id'] = entry.id.text - name = tools.ustr(entry.title.text) - if name == "None": - name = entry.email[0].address - data['name'] = name - emails = ','.join(email.address for email in entry.email) - data['email'] = emails - if entry.organization: - if entry.organization.org_name: - data.update({'company': entry.organization.org_name.text}) - if entry.organization.org_title: - data.update ({'function': entry.organization.org_title.text}) - - - if entry.phone_number: - for phone in entry.phone_number: - if phone.rel == gdata.contacts.REL_WORK: - data['phone'] = phone.text - if phone.rel == gdata.contacts.PHONE_MOBILE: - data['mobile'] = phone.text - if phone.rel == gdata.contacts.PHONE_WORK_FAX: - data['fax'] = phone.text - return data - - def update_contact(self, cr, uid, contact_ids, data, context=None): - addresss_obj = self.pool.get('res.partner.address') - vals = {} - addr = addresss_obj.browse(cr,uid,contact_ids)[0] - name = str((addr.name or addr.partner_id and addr.partner_id.name or '').encode('utf-8')) - - if name != data.get('name'): - vals['name'] = data.get('name','') - if addr.email != data.get('email'): - vals['email'] = data.get('email','') - if addr.mobile != data.get('mobile'): - vals['mobile'] = data.get('mobile','') - if addr.phone != data.get('phone'): - vals['phone'] = data.get('phone','') - if addr.fax != data.get('fax'): - vals['fax'] = data.get('fax','') - - addresss_obj.write(cr, uid, contact_ids, vals, context=context) - return {'type': 'ir.actions.act_window_close'} +# def update_contact(self, cr, uid, contact_ids, data, context=None): +# addresss_obj = self.pool.get('res.partner.address') +# vals = {} +# addr = addresss_obj.browse(cr,uid,contact_ids)[0] +# name = str((addr.name or addr.partner_id and addr.partner_id.name or '').encode('utf-8')) +# +# if name != data.get('name'): +# vals['name'] = data.get('name','') +# if addr.email != data.get('email'): +# vals['email'] = data.get('email','') +# if addr.mobile != data.get('mobile'): +# vals['mobile'] = data.get('mobile','') +# if addr.phone != data.get('phone'): +# vals['phone'] = data.get('phone','') +# if addr.fax != data.get('fax'): +# vals['fax'] = data.get('fax','') +# +# addresss_obj.write(cr, uid, contact_ids, vals, context=context) +# return {'type': 'ir.actions.act_window_close'} synchronize_google_contact() From 872520df3dfce6e28028dc51699522ee71b572b4 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 6 Jun 2011 09:39:35 +0200 Subject: [PATCH 302/763] [fix] fixed problem with list view in o2m not loading at startup bzr revid: nicolas.vanhoren@openerp.com-20110606073935-vnloqd0wrf61pprv --- addons/base/static/src/js/form.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index cc1fbb2de76..6ffc3a0505d 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -1035,7 +1035,6 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({ this.viewmanager = new openerp.base.ViewManager(this.view.session, this.element_id, this.dataset, views); - this.viewmanager.start(); this.viewmanager.on_controller_inited.add_last(function(view_type, controller) { if (view_type == "list") { // TODO niv @@ -1044,10 +1043,14 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({ } self.is_started.resolve(); }); + this.viewmanager.start(); $.when(this.is_started, this.is_setted).then(function() { - var view = self.viewmanager.views[self.viewmanager.active_view].controller; - view.reload_content(); + if (modes[0] == "list") { + var view = self.viewmanager.views[self.viewmanager.active_view].controller; + view.reload_content(); + } + // TODO niv: handle other types of views }); }, set_value: function(value) { From f2770c9ac4c77dbda50de828de77f837840afbfb Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Mon, 6 Jun 2011 09:48:56 +0200 Subject: [PATCH 303/763] [FIX] netrpc_server: close as soon as possible the socket, and do it after a communication-level exception. lp bug: https://launchpad.net/bugs/785009 fixed bzr revid: vmt@openerp.com-20110606074856-e726j4klc5ljiq5w --- openerp/service/netrpc_server.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openerp/service/netrpc_server.py b/openerp/service/netrpc_server.py index e3c181d4a8c..ac3cd724a45 100644 --- a/openerp/service/netrpc_server.py +++ b/openerp/service/netrpc_server.py @@ -87,11 +87,15 @@ class TinySocketClientThread(threading.Thread, netsvc.OpenERPDispatcher): tb_s = "".join(traceback.format_exception(*tb)) logging.getLogger('web-services').debug("netrpc: communication-level exception", exc_info=True) ts.mysend(e, exception=True, traceback=tb_s) + break except Exception, ex: #terminate this channel if we can't properly send back the error logging.getLogger('web-services').exception("netrpc: cannot deliver exception message to client") break + self.sock.shutdown(socket.SHUT_RDWR) + self.sock.close() + self.sock = None self.threads.remove(self) self.running = False return True From 147ca866608f166e8879940c32abd6e70395a0b5 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 6 Jun 2011 09:50:43 +0200 Subject: [PATCH 304/763] [fix] typo bzr revid: nicolas.vanhoren@openerp.com-20110606075043-cvabf3ex95k0z6af --- addons/base/static/src/js/form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 6ffc3a0505d..7bf2059243d 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -1046,7 +1046,7 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({ this.viewmanager.start(); $.when(this.is_started, this.is_setted).then(function() { - if (modes[0] == "list") { + if (modes[0] == "tree") { var view = self.viewmanager.views[self.viewmanager.active_view].controller; view.reload_content(); } From f2dca934a35f9efc908159eb33a1d833cf1b8934 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 6 Jun 2011 09:52:43 +0200 Subject: [PATCH 305/763] [imp] put set_embedded_view in openerp.base.View bzr revid: nicolas.vanhoren@openerp.com-20110606075243-7b97zrb84qdfo4eu --- addons/base/static/src/js/form.js | 9 --------- addons/base/static/src/js/list.js | 9 --------- addons/base/static/src/js/views.js | 10 ++++++++++ 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 7bf2059243d..2b09c4ac27c 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -40,15 +40,6 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV toolbar:!!this.flags.sidebar}, this.on_loaded); } }, - /** - * Directly set a view to use instead of calling fields_view_get. This method must - * be called before start(). - * - * @param embedded_view A view. - */ - set_embedded_view: function(embedded_view) { - this.embedded_view = embedded_view; - }, on_loaded: function(data) { var self = this; this.fields_view = data.fields_view; diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 7bc14298fb6..7643e2b62d4 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -271,15 +271,6 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi }, callback); } }, - /** - * Directly set a view to use instead of calling fields_view_get. This method must - * be called before start(). - * - * @param embedded_view A view. - */ - set_embedded_view: function(embedded_view) { - this.embedded_view = embedded_view; - }, /** * re-renders the content of the list view */ diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index 39708e717a0..4c259babd8f 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -399,6 +399,16 @@ openerp.base.View = openerp.base.Controller.extend({ return dataset.exec_workflow(record_id, action_data.name, handler); } } + }, + /** + * Directly set a view to use instead of calling fields_view_get. This method must + * be called before start(). When an embedded view is set, underlying implementations + * of openerp.base.View must use the provided view instead of any other one. + * + * @param embedded_view A view. + */ + set_embedded_view: function(embedded_view) { + this.embedded_view = embedded_view; } }); From 8d35fb9a7357c8f555fc8942ee11073be8c047ed Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 6 Jun 2011 10:46:22 +0200 Subject: [PATCH 306/763] [FIX] send current search context to listview load (fields_view_get) so @invisible can be computed correctly bzr revid: xmo@openerp.com-20110606084622-iwq5tn3lpegabibe --- addons/base/static/src/js/list.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 8d19635968a..7bcfc26c61b 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -257,7 +257,8 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi return this.rpc('/base/listview/load', { model: this.model, view_id: this.view_id, - toolbar: !!this.flags.sidebar + toolbar: !!this.flags.sidebar, + context: this.dataset.context }, function (field_view_get) { self.on_loaded(field_view_get, grouped); }); From bd7f70b379b4ff435a81693fbc28af76077f2b3c Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 6 Jun 2011 11:04:54 +0200 Subject: [PATCH 307/763] [imp] implemented logout + improved login design bzr revid: nicolas.vanhoren@openerp.com-20110606090454-b19vgrwvlj6v2fp6 --- addons/base/static/src/css/base.css | 17 +++++++++-------- addons/base/static/src/js/chrome.js | 23 ++++++++++++++++++----- addons/base/static/src/xml/base.xml | 6 +++++- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index d9042e7e251..f65a9be5253 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -61,19 +61,20 @@ body.openerp { /* Login */ .openerp .login { display: none; - padding: 6px; - z-index: 1002; - width: 34%; - position: fixed; - top: 0; - left: 33%; } .openerp .login_valid { - background-color: #8f8; } .openerp .login_invalid { - background-color: #f88; +} + +.openerp.login-mode .login { + display: block; +} +.openerp.login-mode #oe_menu, +.openerp.login-mode #oe_secondary_menu, +.openerp.login-mode #oe_app { + display: none; } /* Main*/ diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js index 86549eca001..cefa4c89c84 100644 --- a/addons/base/static/src/js/chrome.js +++ b/addons/base/static/src/js/chrome.js @@ -441,6 +441,13 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b this.set_cookie('uid', this.uid); this.set_cookie('session_id', this.session_id); }, + logout: function() { + this.uid = this.get_cookie('uid'); + this.session_id = this.get_cookie('session_id'); + this.set_cookie('uid', false); + this.set_cookie('session_id', false); + this.on_session_invalid(function() {}); + }, /** * Fetches a cookie stored by an openerp session * @@ -777,14 +784,14 @@ openerp.base.Login = openerp.base.Controller.extend({ on_login_invalid: function() { this.$element .removeClass("login_valid") - .addClass("login_invalid") - .show(); + .addClass("login_invalid"); + this.$element.closest(".openerp").addClass("login-mode"); }, on_login_valid: function() { this.$element .removeClass("login_invalid") - .addClass("login_valid") - .hide(); + .addClass("login_valid"); + this.$element.closest(".openerp").removeClass("login-mode"); }, on_submit: function(ev) { ev.preventDefault(); @@ -810,6 +817,9 @@ openerp.base.Login = openerp.base.Controller.extend({ unique: true, callback: continuation }); + }, + on_logout: function() { + this.session.logout(); } }); @@ -822,7 +832,9 @@ openerp.base.Header = openerp.base.Controller.extend({ }, do_update: function() { this.$element.html(QWeb.render("Header", this)); - } + this.$element.find(".logout").click(this.on_logout); + }, + on_logout: function() {} }); openerp.base.Menu = openerp.base.Controller.extend({ @@ -937,6 +949,7 @@ openerp.base.WebClient = openerp.base.Controller.extend({ this.header = new openerp.base.Header(this.session, "oe_header"); this.login = new openerp.base.Login(this.session, "oe_login"); + this.header.on_logout.add(this.login.on_logout); this.session.on_session_invalid.add(this.login.do_ask_login); this.session.on_session_valid.add_last(this.header.do_update); diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index b8412aa1b19..3a8e5128f6f 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -17,7 +17,6 @@

#{text}

-
+ + + - @@ -51,12 +51,40 @@ Loading... +
- Database:
- Login:
- Password:
- +
+ + + +
+
@@ -34,6 +33,11 @@
+ +
- + + + - @@ -51,12 +51,40 @@ Loading... + - Database:
- Login:
- Password:
- +
+ + + +
+
@@ -34,6 +33,11 @@
+ +
+
+ + + + + + + + + + + + + + + + +
+ +
+ + + + From 8193d8967dbf133ece5371a315742ed5e4c82f77 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 6 Jun 2011 11:49:55 +0200 Subject: [PATCH 313/763] [imp] improved login css bzr revid: nicolas.vanhoren@openerp.com-20110606094955-kblpspk99t960y9m --- addons/base/static/src/css/base.css | 29 ++++++++++++++- addons/base/static/src/img/stock_person.png | Bin 0 -> 1074 bytes addons/base/static/src/js/chrome.js | 4 +-- addons/base/static/src/xml/base.xml | 38 +++++++++++++++++--- 4 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 addons/base/static/src/img/stock_person.png diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index f65a9be5253..78cad811122 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -61,13 +61,40 @@ body.openerp { /* Login */ .openerp .login { display: none; - +} +.openerp .login fieldset { + padding-bottom: 5px; + min-width: 100px; + margin-top: 60px; + margin-bottom: 60px; + margin-left: 40px; + border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + float: left; + width: 420px; +} +.openerp .login fieldset legend { + padding: 4px; +} +.openerp .login .oe_box2 { + padding: 5px 5px 20px 5px; +} +.openerp .login .oe_box2 table { + width: 100%; + border:none; +} +.openerp .login .oe_field_value { + padding: 3px; } .openerp .login_valid { } .openerp .login_invalid { } +.openerp.login-mode .login-container { + height: 100%; +} .openerp.login-mode .login { display: block; } diff --git a/addons/base/static/src/img/stock_person.png b/addons/base/static/src/img/stock_person.png new file mode 100644 index 0000000000000000000000000000000000000000..202cf0ee6c554570fde4a7835737195f5cd12120 GIT binary patch literal 1074 zcmV-21kL-2P)!5$3|KREQzU>^(VTMM>u6p6a*>=wPKHv9w-{;wT;s5y4kxHe)=~U`D zUw_<4rHHRz3*W=%9k^t1aq)2`lc9$X9#B4?r=z1IIyg9>{r!E)X0x=kw3O%PjOP(t z5Ap5oZ8|(Wq+BjXi^(KSOiWNBk)W-uE!x}LlTB!DAel@)-PqU=Gfk({G&(v;LqkI} zG&o3u1!iYwVFtj&oMypiW@fC(g$25G^Cm4XFHXr~-bLMn^^{F+cxaGXvAp z(}_8r-L<(n5hN0c95XOL0}94CGyVPjA{$sXO$7lcBBkdoeB>Md|(d>k9pt%-qg9#~fh3wnA4JxaQ} zsarw8ur}q$sVpC1146v3OVFjHvy(cNbac@0@GuNGH8Fshpxht~IwXQYK~SQ-UC_>O zb-;vMvr6C{{}D5VxF8S^1SI@^fuCVBsEE&+HX`158LYD(LE72`Z4#}mg4P1qAN`@w zZOywOZ??Aqe}GzAT7Kd4$@mK3K0o*L!g&ndU^!&K>-CbixmnOG(bNQ_CCHqM0Z#WO zHXrK0sj-n7B|IL1hvCe?g!Tq_mcyLlSKJlR;mGZF|DvHm(7>Qfqmc;q1+sLHU;Fz$ zz%%S&o}t{btE;q@&5A%Sr&GoW91ik%y`llFtgO&98^!lVxBEWJl>BjEo6R=Bvw9J1 z57OG&8tv}v5Kcd6G!DC6#tv*Y8JEi?I^#kjL7SVKB3mA}2PSi83hZz=CRy|y8qPWg zzPr1Ne>JpP5zJO!FH;Zd>SXF9tX7yqhZJXn_4RccjKzqxKfCPq-`-KtD+Xv)X3B@$O>9FGP0Vl0H@>;$_XhtLHtx5N6Qddz{}J-|38;F>YX8-^I07*qoM6N<$g1YMW>Hq)$ literal 0 HcmV?d00001 diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js index cefa4c89c84..2acb66c7ada 100644 --- a/addons/base/static/src/js/chrome.js +++ b/addons/base/static/src/js/chrome.js @@ -444,8 +444,8 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b logout: function() { this.uid = this.get_cookie('uid'); this.session_id = this.get_cookie('session_id'); - this.set_cookie('uid', false); - this.set_cookie('session_id', false); + this.set_cookie('uid', ''); + this.set_cookie('session_id', ''); this.on_session_invalid(function() {}); }, /** diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 3a8e5128f6f..7a5f627ee72 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -34,7 +34,7 @@
+
+ + + + + + + + + + + + + + + + +
+ +
+
+ + +
From 69132745e0e7232666c5ee62cb3ade51d4260c36 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 6 Jun 2011 11:52:54 +0200 Subject: [PATCH 314/763] [FIX] remove fields_view_get preprocessing of set_editable/@editable, done in JS bzr revid: xmo@openerp.com-20110606095254-h7r8v42y8q42sjj4 --- addons/base/controllers/main.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index 70feda44bc0..dcb5ae9e4bd 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -571,20 +571,6 @@ class ListView(View): fields_view = self.fields_view_get(req, model, view_id, 'tree', toolbar=toolbar) return {'fields_view': fields_view} - def fields_view_get(self, request, model, view_id, view_type="tree", - transform=True, toolbar=False, submenu=False): - """ Sets @editable on the view's arch if it isn't already set and - ``set_editable`` is present in the request context - """ - view = super(ListView, self).fields_view_get( - request, model, view_id, view_type, transform, toolbar, submenu) - - view_attributes = view['arch']['attrs'] - if request.context.get('set_editable')\ - and 'editable' not in view_attributes: - view_attributes['editable'] = 'bottom' - return view - def process_colors(self, view, row, context): colors = view['arch']['attrs'].get('colors') From efbde798bc2fbfe4ab659c08801551e7bece7c1a Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 6 Jun 2011 11:59:18 +0200 Subject: [PATCH 315/763] [FIX] handling of editable list views via @editable, add basis for adding records in editable list mode bzr revid: xmo@openerp.com-20110606095918-9kcm3x1m8bncl092 --- addons/base/static/src/js/list-editable.js | 42 ++++++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/addons/base/static/src/js/list-editable.js b/addons/base/static/src/js/list-editable.js index d51fa695de9..c0a9d846496 100644 --- a/addons/base/static/src/js/list-editable.js +++ b/addons/base/static/src/js/list-editable.js @@ -9,6 +9,8 @@ openerp.base.list.editable = function (openerp) { openerp.base.ListView.prototype.defaults.editable = null; var old_actual_search = openerp.base.ListView.prototype.do_actual_search; + var old_add_record = openerp.base.ListView.prototype.do_add_record; + var old_on_loaded = openerp.base.ListView.prototype.on_loaded; _.extend(openerp.base.ListView.prototype, { /** * Sets editability status for the list, based on defaults, view @@ -18,11 +20,11 @@ openerp.base.list.editable = function (openerp) { */ set_editable: function (force) { // If ``force``, set editability to bottom - // else if editability flag in view arch, use that // otherwise rely on view default + // view' @editable is handled separately as we have not yet + // fetched and processed the view at this point. this.options.editable = ( (force && "bottom") - || this.fields_view.arch.attrs.editable || this.defaults.editable); }, /** @@ -31,6 +33,29 @@ openerp.base.list.editable = function (openerp) { do_actual_search: function (results) { this.set_editable(results.context['set_editable']); old_actual_search.call(this, results); + }, + /** + * Replace do_add_record to handle editability (and adding new record + * as an editable row at the top or bottom of the list) + */ + do_add_record: function () { + if (this.options.editable) { + this.groups.new_record(); + } else { + old_add_record.call(this); + } + }, + on_loaded: function (data, grouped) { + // tree/@editable takes priority on everything else if present. + this.options.editable = data.fields_view.arch.editable || this.options.editable; + return old_on_loaded.call(this, data, grouped); + } + }); + + _.extend(openerp.base.ListView.Groups.prototype, { + new_record: function () { + // TODO: handle multiple children + this.children[null].new_record(); } }); @@ -48,7 +73,7 @@ openerp.base.list.editable = function (openerp) { id: _.uniqueId('oe-editable-row-'), 'class': $(row).attr('class'), onclick: function (e) {e.stopPropagation();} - }).replaceAll(row) + }) .keyup(function (e) { switch (e.which) { case KEY_RETURN: @@ -67,6 +92,13 @@ openerp.base.list.editable = function (openerp) { .delegate('button.oe-edit-row-cancel', 'click', function () { self.cancel_edition(row_num); }); + if (row) { + $new_row.replaceAll(row); + } else if (this.options.editable === 'top') { + this.$current.prepend($new_row); + } else if (this.options.editable) { + this.$current.append($new_row); + } this.edition_form = _.extend(new openerp.base.FormView( null, this.group.view.session, $new_row.attr('id'), this.dataset, false), { @@ -120,6 +152,10 @@ openerp.base.list.editable = function (openerp) { this.reload_record(row_num); this.edition_form.stop(); delete this.edition_form; + }, + new_record: function () { + this.dataset.index = null; + this.render_row_as_form(-1, null); } }); openerp.base.list = {form: {}}; From 975f51941958555b456058bbb335ccf67691883f Mon Sep 17 00:00:00 2001 From: Jigar Amin Date: Mon, 6 Jun 2011 15:43:59 +0530 Subject: [PATCH 316/763] [BUG/FIX]survey : added message in ivitation if user not found than it hsoud show message for that email use, imporved view usabality bzr revid: jam@tinyerp.com-20110606101359-74jgqtq3pguhffvj --- addons/survey/wizard/survey_send_invitation.py | 4 ++++ addons/survey/wizard/survey_send_invitation.xml | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/addons/survey/wizard/survey_send_invitation.py b/addons/survey/wizard/survey_send_invitation.py index 6bc1502e355..9db87766fbb 100644 --- a/addons/survey/wizard/survey_send_invitation.py +++ b/addons/survey/wizard/survey_send_invitation.py @@ -167,6 +167,10 @@ class survey_send_invitation(osv.osv_memory): res_user+= "- %s (Login: %s, Password: %s)\n" % \ (user_email.name, user_email.login, user_email.password) continue + else: + error += "- No User found linked to email address '%s'.\n"%(addr.email) + continue + passwd= self.genpasswd() out+= addr.email + ',' + passwd + '\n' mail= record['mail'] % {'login' : addr.email, 'passwd' : passwd, 'name' : addr.name} diff --git a/addons/survey/wizard/survey_send_invitation.xml b/addons/survey/wizard/survey_send_invitation.xml index 8f82d816954..4992e1204ff 100644 --- a/addons/survey/wizard/survey_send_invitation.xml +++ b/addons/survey/wizard/survey_send_invitation.xml @@ -3,7 +3,7 @@ - + Send Invitation survey.send.invitation @@ -11,21 +11,21 @@
- + - +
From 69edae4391f345f2baa68bd1495a4fedc1d2ea7e Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 6 Jun 2011 12:19:47 +0200 Subject: [PATCH 318/763] [imp] improved css of login bzr revid: nicolas.vanhoren@openerp.com-20110606101947-nqbx1jcz3uj5oav2 --- addons/base/static/src/css/base.css | 38 ++++++++++++--- .../static/src/img/accessories-archiver.png | Bin 0 -> 822 bytes addons/base/static/src/img/partner.png | Bin 0 -> 905 bytes addons/base/static/src/img/product.png | Bin 0 -> 708 bytes addons/base/static/src/xml/base.xml | 45 ++++++++++++++++-- 5 files changed, 71 insertions(+), 12 deletions(-) create mode 100644 addons/base/static/src/img/accessories-archiver.png create mode 100644 addons/base/static/src/img/partner.png create mode 100644 addons/base/static/src/img/product.png diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index 78cad811122..ad0bec6c255 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -62,17 +62,19 @@ body.openerp { .openerp .login { display: none; } +.openerp .login form { + float: left; + width: 420px; + margin-left: 40px; + margin-bottom: 60px; +} .openerp .login fieldset { padding-bottom: 5px; min-width: 100px; margin-top: 60px; - margin-bottom: 60px; - margin-left: 40px; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; - float: left; - width: 420px; } .openerp .login fieldset legend { padding: 4px; @@ -84,12 +86,34 @@ body.openerp { width: 100%; border:none; } -.openerp .login .oe_field_value { +.openerp .login .oe_box2 td { padding: 3px; + text-align: right; } -.openerp .login_valid { +.openerp .login .oe_box2 td input { + width: 100%; } -.openerp .login_invalid { +.openerp .login .oe_login_right_pane { + padding:70px 35px 5px 10px; + min-width: 200px; + margin-left: 500px; +} +.openerp .login .login_error_message { + display: none; + background-color: #9A0404; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + color: white; + font-family: Ubuntu, Helvetica, sans-serif; + font-size: 16px; + font-weight: bold; + padding: 5px; + margin-top: 5px; + text-align: center; +} +.openerp .login.login_invalid .login_error_message { + display: block; } .openerp.login-mode .login-container { diff --git a/addons/base/static/src/img/accessories-archiver.png b/addons/base/static/src/img/accessories-archiver.png new file mode 100644 index 0000000000000000000000000000000000000000..8bcbe4566bc10df91222f2045449abcd258997b6 GIT binary patch literal 822 zcmV-61Ihe}P)3o8;IpdbVcrBZb^TLo%!T$sNra%1e696CG-Xxrs z@uWj;LL3yX1g#BP8+<9rl_k#=R^=Ep20=2NApvSdozK4cjlB)wJ+l`0FKpge55l=! z$FaMvOXy44Lg;^sLLChT-FEAwI}XcEvGc*rLVS8_7v-9@C@8CM77X{Zais7iw$;m06gl1JDODV2R z84S8qLW{8$*N;FrtTd}~Wp(v!X)PZrm5V$ZlU&54({q#y!`Q)%n%LQxarY64A2G`n zxq`6L;Iw^c+b5kjWL^|E3vF+YhlBTfPdX%%Ax0~X%!IJAf-nk`4Tj%JTvj=B0lTJ590IjA5R98AOCsS`y03fUc6HM`OX)=+d^SG(^`LhOD8K^z2Mu**aWn@m?*IS*07*qoM6N<$fSzr&_!KV+*VL< zFK%_?Mt7qBfFKczbWuwXsS)ZT)>?F0lbQxPGnsjB?!E86`{AOd)J4wftPa1k_z^sj z4_>dK)9aUg-=89cIIY#+wJ_u#uO~Px z;*0hB)&bV!$d$mE58ICi*g^4=e~QgU{O(k9zvs^tL)n_SDf75 z?5g)JRPg0S{{Mls#Zsd_Qu}CXY-GIg)DS2oP-@^csuOyz`jgrE@-% z%30w1tHily^GrgB6wM<;7@c?;!SF0-A%s)=gqW<6N&Z*oZf|p=^B;k82*_CcM!UpL zXQGEl6i{InlM};mTEMCl&gO8r1R>5NKvbzbBKH6wtW_7ID7fsG#L+=6u+KS|0ml0k zOr(2oc?xF@oa};&Ea?ii_1Wbuhqsp=4FpC1ETQIvQXI^)2qJ=hHixV2((6g702m#kl^_USD3^-EfKPh)NpSyVa1)@Thr!|{)Mr+3<&P5D zoWi57#)zc}&#yB8AVlv`rgwEtO(wm5PoE&RFc%7$5jclD*N~Y)Yqt-TNkB_5;$%M& z-!lMMUh&lrSLH3v#g7m6_%-gYZU^Of*`p+M0JK)<_Bo`?K%v2`fEc7Vl3wyP1Ax1K z8jRG5T|CM9r_K}}Y~DO}hcc#pkHj97b@@PMA{9i76k2wZ{mzYt+rNL&x%KU@snS_**7oc{#1 fqpR?W5dh#{o9ud-MN>Ot00000NkvXXu0mjfut%x{ literal 0 HcmV?d00001 diff --git a/addons/base/static/src/img/product.png b/addons/base/static/src/img/product.png new file mode 100644 index 0000000000000000000000000000000000000000..99f58d95a8b16503a1b8b5086be523062fd9d1ed GIT binary patch literal 708 zcmV;#0z3VQP)Gp1|r&8Q7Lxa8HrAddkpDe`lJ5kKc@8QM$v5CIn6E~#bX=_?JAte(jkn%{9 z2U1#uq1$W}zrCxKRu;=UHlK(nr^t_D@!{Y^Zv6a{?9ll2%6cJU>INhvJRBTVg_NqP&$T$ zbKdq^VM^8;&ZNq-3WBF?(2VP7vf;=3VgxI|4qyg@0cN11%mIira;K(DrSdXj>ZPlS z*}Z`zG#lHOf9Br{XWN}#_(1u<3-S=OT26YAb!PWk5y|DfMtz~Qnjh82PTmVD-(^?3 zhrrOOQMb9aywI$co)TnH7PodWGgq!kqG~Le;bf){M=_Snu#~cT^I2)ba_H29SHNii zQj&UoR}?b1qn qbFC8o0 -
@@ -75,16 +74,52 @@ - - + +
+
- - +
From 43b2695cfd9c18eb90e9a236fd5081f2ee62bc69 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 6 Jun 2011 12:26:30 +0200 Subject: [PATCH 319/763] [fix] possible mistake in css bzr revid: nicolas.vanhoren@openerp.com-20110606102630-jex9p4i49272lxkn --- addons/base/static/src/css/base.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index ad0bec6c255..7cdf9af0286 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -122,9 +122,9 @@ body.openerp { .openerp.login-mode .login { display: block; } -.openerp.login-mode #oe_menu, -.openerp.login-mode #oe_secondary_menu, -.openerp.login-mode #oe_app { +.openerp.login-mode .menu, +.openerp.login-mode .secondary_menu, +.openerp.login-mode .oe-application { display: none; } From 19382763fbe00fd847d3b00efcaa968aa4d44999 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Mon, 6 Jun 2011 12:35:02 +0200 Subject: [PATCH 320/763] [FIX] Fixed View controller bzr revid: fme@openerp.com-20110606103502-wfph1zo7nnt2668p --- addons/base/controllers/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index fc846f22838..40546ddbbb5 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -473,8 +473,8 @@ class View(openerpweb.Controller): else: xml = ElementTree.fromstring(fvg['arch']) fvg['arch'] = Xml2Json.convert_element(xml) - for field in fvg["fields"].values(): - if field["views"]: + for field in fvg['fields'].values(): + if field.has_key('views') and field['views']: for view in field["views"].values(): self.process_view(session, view, None, transform) From 8011b649ee225edef8e73ae5cfea08bd66f524d3 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Mon, 6 Jun 2011 12:54:36 +0200 Subject: [PATCH 321/763] [ADD] "Reset" feature in dashboards bzr revid: fme@openerp.com-20110606105436-wpo7xyiiy2o6jyzm --- addons/base/controllers/main.py | 7 +++++-- addons/base_dashboard/static/src/js/dashboard.js | 9 ++++++++- addons/base_dashboard/static/src/xml/base_dashboard.xml | 4 ++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index 40546ddbbb5..342f9efc6cf 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -489,11 +489,14 @@ class View(openerpweb.Controller): return {'result': True} @openerpweb.jsonrequest - def undo_custom(self, request, view_id): + def undo_custom(self, request, view_id, reset=False): CustomView = request.session.model('ir.ui.view.custom') vcustom = CustomView.search([('user_id', '=', request.session._uid), ('ref_id' ,'=', view_id)]) if vcustom: - CustomView.unlink([vcustom[0]]) + if reset: + CustomView.unlink(vcustom) + else: + CustomView.unlink([vcustom[0]]) return {'result': True} return {'result': False} diff --git a/addons/base_dashboard/static/src/js/dashboard.js b/addons/base_dashboard/static/src/js/dashboard.js index 9d6511fd215..6e6a0a5a1f1 100644 --- a/addons/base_dashboard/static/src/js/dashboard.js +++ b/addons/base_dashboard/static/src/js/dashboard.js @@ -18,6 +18,7 @@ openerp.base.form.DashBoard = openerp.base.form.Widget.extend({ // Events this.$element.find('.oe-dashboard-link-undo').click(this.on_undo); + this.$element.find('.oe-dashboard-link-reset').click(this.on_reset); this.$element.find('.oe-dashboard-link-add_widget').click(this.on_add_widget); this.$element.find('.oe-dashboard-link-change_layout').click(this.on_change_layout); this.$element.find('.oe-dashboard-column .ui-icon-minusthick').click(this.on_fold_action); @@ -42,6 +43,12 @@ openerp.base.form.DashBoard = openerp.base.form.Widget.extend({ view_id: this.view.fields_view.view_id }, this.do_reload); }, + on_reset: function() { + this.rpc('/base/view/undo_custom', { + view_id: this.view.fields_view.view_id, + reset: true + }, this.do_reload); + }, on_add_widget: function() { }, on_change_layout: function() { @@ -112,7 +119,7 @@ openerp.base.form.DashBoard = openerp.base.form.Widget.extend({ view_id: this.view.fields_view.view_id, arch: arch }, function() { - self.$element.find('.oe-dashboard-link-undo').show(); + self.$element.find('.oe-dashboard-link-undo, .oe-dashboard-link-reset').show(); }); }, on_load_action: function(result) { diff --git a/addons/base_dashboard/static/src/xml/base_dashboard.xml b/addons/base_dashboard/static/src/xml/base_dashboard.xml index 9c43be6996c..fbe34a3892b 100644 --- a/addons/base_dashboard/static/src/xml/base_dashboard.xml +++ b/addons/base_dashboard/static/src/xml/base_dashboard.xml @@ -1,6 +1,10 @@