From bd31b7c55354d4a3aa9b8eba95a80844449fdfe6 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Wed, 26 Sep 2012 15:09:42 +0200 Subject: [PATCH 1/8] [API/IMP] fields: cleanup field_to_dict + make @deprecated available in fields_get() Renamed the m2m extra info keys, as their names were quite confusing (third_table?), + removed the "func_obj" key for function fields, as it was a duplicate of the "relation" kay that is already present for all relationship fields. These renames should not break anything, as this info should only be used for debug, but they still constitute an API backwards-incompatible change. bzr revid: odo@openerp.com-20120926130942-doauqgh6v35vhi29 --- openerp/osv/fields.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 037d2a90986..82fb2e9e185 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -1552,24 +1552,16 @@ def field_to_dict(model, cr, user, field, context=None): res['fnct_search'] = field._fnct_search and field._fnct_search.func_name or False res['fnct_inv'] = field._fnct_inv and field._fnct_inv.func_name or False res['fnct_inv_arg'] = field._fnct_inv_arg or False - res['func_obj'] = field._obj or False if isinstance(field, many2many): (table, col1, col2) = field._sql_names(model) - res['related_columns'] = [col1, col2] - res['third_table'] = table - for arg in ('string', 'readonly', 'states', 'size', 'required', 'group_operator', - 'change_default', 'translate', 'help', 'select', 'selectable', 'groups'): - if getattr(field, arg): - res[arg] = getattr(field, arg) - for arg in ('digits', 'invisible', 'filters'): + res['m2m_join_columns'] = [col1, col2] + res['m2m_join_table'] = table + for arg in ('string', 'readonly', 'states', 'size', 'group_operator', 'required', + 'change_default', 'translate', 'help', 'select', 'selectable', 'groups', + 'deprecated', 'digits', 'invisible', 'filters'): if getattr(field, arg, None): res[arg] = getattr(field, arg) - if field.string: - res['string'] = field.string - if field.help: - res['help'] = field.help - if hasattr(field, 'selection'): if isinstance(field.selection, (tuple, list)): res['selection'] = field.selection From add6b7b08a3d47d0b369cbcaa83e610a1f8d66e1 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Wed, 26 Sep 2012 15:10:06 +0200 Subject: [PATCH 2/8] [IMP] res.partner: explicitly deprecate `address` and `country` columns bzr revid: odo@openerp.com-20120926131006-b3mzn9y38rkg7e1s --- openerp/addons/base/res/res_partner.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 008e8048a5d..fe749c6013b 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -199,7 +199,10 @@ class res_partner(osv.osv, format_address): 'bank_ids': fields.one2many('res.partner.bank', 'partner_id', 'Banks'), 'website': fields.char('Website', size=64, help="Website of Partner or Company"), 'comment': fields.text('Notes'), - 'address': fields.one2many('res.partner.address', 'partner_id', 'Contacts'), # should be removed in version 7, but kept until then for backward compatibility + 'address': fields.one2many('res.partner.address', 'partner_id', 'Addresses', + deprecated="The address information is now directly stored on each Partner record. "\ + "Multiple contacts with their own address can be added via the child_ids relationship. "\ + "This field will be removed as of OpenERP 7.1."), 'category_id': fields.many2many('res.partner.category', id1='partner_id', id2='category_id', string='Tags'), 'credit_limit': fields.float(string='Credit Limit'), 'ean13': fields.char('EAN13', size=13), @@ -218,7 +221,8 @@ class res_partner(osv.osv, format_address): 'city': fields.char('City', size=128), 'state_id': fields.many2one("res.country.state", 'State'), 'country_id': fields.many2one('res.country', 'Country'), - 'country': fields.related('country_id', type='many2one', relation='res.country', string='Country'), # for backward compatibility + 'country': fields.related('country_id', type='many2one', relation='res.country', string='Country', + deprecated="This field will be removed as of OpenERP 7.1, use country_id instead"), 'email': fields.char('Email', size=240), 'phone': fields.char('Phone', size=64), 'fax': fields.char('Fax', size=64), From 6eb82789d60e2200aa075b6c18a2a1d2bc6b34b8 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Wed, 26 Sep 2012 16:08:02 +0200 Subject: [PATCH 3/8] [IMP] google_docusability improvements bzr revid: qdp-launchpad@openerp.com-20120926140802-b0r0ktkomj6sjchy --- addons/google_docs/google_docs.py | 6 +++--- addons/google_docs/static/src/js/gdocs.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/google_docs/google_docs.py b/addons/google_docs/google_docs.py index 270c105daab..f1477f9c7f2 100644 --- a/addons/google_docs/google_docs.py +++ b/addons/google_docs/google_docs.py @@ -134,8 +134,8 @@ class config(osv.osv): _description = "Google Docs templates config" _columns = { - 'model_id': fields.many2one('ir.model', 'Model'), - 'gdocs_resource_id': fields.char('Google resource ID', size=64,help=''' + 'model_id': fields.many2one('ir.model', 'Model', required=True), + 'gdocs_resource_id': fields.char('Google Resource ID to Use as Template', size=64,help=''' This is the id of the template document, on google side. You can find it thanks to its URL: *for a text document with url like `https://docs.google.com/a/openerp.com/document/d/123456789/edit`, the ID is `document:123456789` *for a spreadsheet document with url like `https://docs.google.com/a/openerp.com/spreadsheet/ccc?key=123456789#gid=0`, the ID is `spreadsheet:123456789` @@ -143,7 +143,7 @@ This is the id of the template document, on google side. You can find it thanks *for a drawing document with url like `https://docs.google.com/a/openerp.com/drawings/d/123456789/edit`, the ID is `drawings:123456789` ... '''), - 'name_template': fields.char('GDoc name template ', size=64, help='This is the name which appears on google side'), + 'name_template': fields.char('Google Doc Name Pattern', size=64, help='Choose how the new google docs will be named, on google side'), } _defaults = { diff --git a/addons/google_docs/static/src/js/gdocs.js b/addons/google_docs/static/src/js/gdocs.js index 694f5736c72..bcfd24f8c0d 100644 --- a/addons/google_docs/static/src/js/gdocs.js +++ b/addons/google_docs/static/src/js/gdocs.js @@ -13,7 +13,7 @@ var _t = instance.web._t; }); if (! flag) { this.add_items('files', [ - { label: _t('Google Doc'), callback: self.on_google_doc }, + { label: _t('Add Google Doc...'), callback: self.on_google_doc }, ]); } }, From 3cf8404b9b9243a501ef33e7c5aaa68e13d4ad79 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Wed, 26 Sep 2012 18:40:59 +0200 Subject: [PATCH 4/8] [REVERT] mail: undo apparently incorrect test change bzr revid: odo@openerp.com-20120926164059-11wuh2z5ix7ugqej --- addons/mail/tests/test_mail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mail/tests/test_mail.py b/addons/mail/tests/test_mail.py index bc7cff5c422..57a59e2595f 100644 --- a/addons/mail/tests/test_mail.py +++ b/addons/mail/tests/test_mail.py @@ -320,7 +320,7 @@ class test_mail(TestMailMockups): for sent_email in sent_emails: self.assertEqual(sent_email['subject'], _subject, 'sent_email subject incorrect') self.assertEqual(sent_email['body'], _mail_body1 + '\n
Bert Tartopoils
\n', 'sent_email body incorrect') - self.assertEqual(sent_email['body_alternative'], _mail_bodyalt1 + '\nBert Tartopoils\n', 'sent_email body_alternative is incorrect') + self.assertEqual(sent_email['body_alternative'], _mail_bodyalt1 + '\nBert Tartopoils', 'sent_email body_alternative is incorrect') # Test: mail_message: partner_ids = group followers message_pids = set([partner.id for partner in message.partner_ids]) test_pids = set([p_a_id, p_b_id, p_c_id]) From 92ea964019a350fc1c2fac173bbc33aecee11bd3 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Wed, 26 Sep 2012 22:51:05 +0200 Subject: [PATCH 5/8] [FIX] invitation on meetings bzr revid: fp@openerp.com-20120926205105-6638lw5v70leui34 --- addons/base_calendar/base_calendar.py | 42 ++++++++++++++++++----- addons/base_calendar/crm_meeting.py | 30 +++++++++++++++- addons/base_calendar/crm_meeting_view.xml | 18 +++++----- 3 files changed, 73 insertions(+), 17 deletions(-) diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py index 73811d5ba71..6176b2804f3 100644 --- a/addons/base_calendar/base_calendar.py +++ b/addons/base_calendar/base_calendar.py @@ -1060,6 +1060,37 @@ rule or repeating pattern of time to exclude from the recurring rule."), 'recurrency': fields.boolean('Recurrent', help="Recurrent Meeting"), } + def create_attendees(self, cr, uid, ids, context): + att_obj = self.pool.get('calendar.attendee') + user_obj = self.pool.get('res.users') + current_user = user_obj.browse(cr, uid, uid, context=context) + for event in self.browse(cr, uid, ids, context): + attendees = {} + for att in event.attendee_ids: + attendees[att.partner_id.id] = True + new_attendees = [] + mail_to = [] + for partner in event.partner_ids: + if partner.id in attendees: + continue + att_id = self.pool.get('calendar.attendee').create(cr, uid, { + 'partner_id': partner.id, + 'user_id': partner.user_ids and partner.user_ids[0].id or False, + 'ref': self._name+','+str(event.id), + 'email': partner.email + }, context=context) + if partner.email: + mail_to.append(partner.email) + self.write(cr, uid, [event.id], { + 'attendee_ids': [(4, att_id)] + }, context=context) + new_attendees.append(att_id) + + if mail_to and current_user.email: + att_obj._send_mail(cr, uid, new_attendees, mail_to, + email_from = current_user.email) + return True + def default_organizer(self, cr, uid, context=None): user_pool = self.pool.get('res.users') user = user_pool.browse(cr, uid, uid, context=context) @@ -1366,6 +1397,8 @@ rule or repeating pattern of time to exclude from the recurring rule."), vals['vtimezone'] = vals['vtimezone'][40:] res = super(calendar_event, self).write(cr, uid, ids, vals, context=context) + if vals.get('partner_ids', False): + self.create_attendees(cr, uid, ids, context) if ('alarm_id' in vals or 'base_calendar_alarm_id' in vals)\ or ('date' in vals or 'duration' in vals or 'date_deadline' in vals): @@ -1489,17 +1522,10 @@ rule or repeating pattern of time to exclude from the recurring rule."), if vals.get('vtimezone', '') and vals.get('vtimezone', '').startswith('/freeassociation.sourceforge.net/tzfile/'): vals['vtimezone'] = vals['vtimezone'][40:] - #updated_vals = self.onchange_dates(cr, uid, [], - # vals.get('date', False), - # vals.get('duration', False), - # vals.get('date_deadline', False), - # vals.get('allday', False), - # context=context) - #vals.update(updated_vals.get('value', {})) - res = super(calendar_event, self).create(cr, uid, vals, context) alarm_obj = self.pool.get('res.alarm') alarm_obj.do_alarm_create(cr, uid, [res], self._name, 'date', context=context) + self.create_attendees(cr, uid, [res], context) return res def do_tentative(self, cr, uid, ids, context=None, *args): diff --git a/addons/base_calendar/crm_meeting.py b/addons/base_calendar/crm_meeting.py index 0ee23ed1d0f..b87114f3a66 100644 --- a/addons/base_calendar/crm_meeting.py +++ b/addons/base_calendar/crm_meeting.py @@ -71,6 +71,34 @@ class crm_meeting(base_state, osv.Model): default['attendee_ids'] = False return super(crm_meeting, self).copy(cr, uid, id, default, context) + def onchange_partner_ids(self, cr, uid, ids, value, context=None): + """ The basic purpose of this method is to check that destination partners + effectively have email addresses. Otherwise a warning is thrown. + :param value: value format: [[6, 0, [3, 4]]] + """ + res = {'value': {}} + if not value or not value[0] or not value[0][0] == 6: + return + res.update(self.check_partners_email(cr, uid, value[0][2], context=context)) + return res + + def check_partners_email(self, cr, uid, partner_ids, context=None): + """ Verify that selected partner_ids have an email_address defined. + Otherwise throw a warning. """ + partner_wo_email_lst = [] + for partner in self.pool.get('res.partner').browse(cr, uid, partner_ids, context=context): + if not partner.email: + partner_wo_email_lst.append(partner) + if not partner_wo_email_lst: + return {} + warning_msg = _('The following contacts have no email address :') + for partner in partner_wo_email_lst: + warning_msg += '\n- %s' % (partner.name) + return {'warning': { + 'title': _('Email addresses not found'), + 'message': warning_msg, + } + } # ---------------------------------------- # OpenChatter # ---------------------------------------- @@ -80,7 +108,7 @@ class crm_meeting(base_state, osv.Model): return [('date','<=',time.strftime('%Y-%M-%D 23:59:59')), ('date_deadline','>=', time.strftime('%Y-%M-%D 00:00:00')), ('user_id','=',uid)] def case_get_note_msg_prefix(self, cr, uid, id, context=None): - return 'Meeting' + return _('Meeting') def case_open_send_note(self, cr, uid, ids, context=None): return self.message_post(cr, uid, ids, body=_("Meeting confirmed."), context=context) diff --git a/addons/base_calendar/crm_meeting_view.xml b/addons/base_calendar/crm_meeting_view.xml index 4b165c1d495..2da18447820 100644 --- a/addons/base_calendar/crm_meeting_view.xml +++ b/addons/base_calendar/crm_meeting_view.xml @@ -80,7 +80,9 @@