diff options
| author | Denis Ledoux <dle@odoo.com> | 2014-07-23 13:16:59 +0200 |
|---|---|---|
| committer | Denis Ledoux <dle@odoo.com> | 2014-07-23 13:18:30 +0200 |
| commit | a5f7891b689a325dd33e1d0ade0ea003f2785f60 (patch) | |
| tree | b94604a3bf144a33ac623c2552f7af962b383661 | |
| parent | e7780ac97a6a45dcf295d4aa86509b00efdf618d (diff) | |
| parent | 5739aebfb1711bb94c2f94bfb03ec12f17e9430d (diff) | |
[MERGE] forward port of branch saas-4 up to 5739aebfb1711bb94c2f94bfb03ec12f17e9430d
22 files changed, 126 insertions, 56 deletions
diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py index 3d8d8302f32..da39839b214 100644 --- a/addons/account/account_move_line.py +++ b/addons/account/account_move_line.py @@ -1043,6 +1043,8 @@ class account_move_line(osv.osv): all_moves = list(set(all_moves) - set(move_ids)) if unlink_ids: if opening_reconciliation: + raise osv.except_osv(_('Warning!'), + _('Opening Entries have already been generated. Please run "Cancel Closing Entries" wizard to cancel those entries and then run this wizard.')) obj_move_rec.write(cr, uid, unlink_ids, {'opening_reconciliation': False}) obj_move_rec.unlink(cr, uid, unlink_ids) if len(all_moves) >= 2: diff --git a/addons/crm/crm_phonecall.py b/addons/crm/crm_phonecall.py index 89a1f799b2b..28dd1171b0a 100644 --- a/addons/crm/crm_phonecall.py +++ b/addons/crm/crm_phonecall.py @@ -141,6 +141,7 @@ class crm_phonecall(osv.osv): 'partner_phone' : call.partner_phone, 'partner_mobile' : call.partner_mobile, 'priority': call.priority, + 'opportunity_id': call.opportunity_id and call.opportunity_id.id or False, } new_id = self.create(cr, uid, vals, context=context) if action == 'log': diff --git a/addons/hr_payroll/hr_payroll.py b/addons/hr_payroll/hr_payroll.py index 1a34758fb50..3f2a6abb3a9 100644 --- a/addons/hr_payroll/hr_payroll.py +++ b/addons/hr_payroll/hr_payroll.py @@ -385,7 +385,7 @@ class hr_payslip(osv.osv): #OR if it starts between the given dates clause_2 = ['&',('date_start', '<=', date_to),('date_start','>=', date_from)] #OR if it starts before the date_from and finish after the date_end (or never finish) - clause_3 = [('date_start','<=', date_from),'|',('date_end', '=', False),('date_end','>=', date_to)] + clause_3 = ['&',('date_start','<=', date_from),'|',('date_end', '=', False),('date_end','>=', date_to)] clause_final = [('employee_id', '=', employee.id),'|','|'] + clause_1 + clause_2 + clause_3 contract_ids = contract_obj.search(cr, uid, clause_final, context=context) return contract_ids diff --git a/addons/mail/mail_followers.py b/addons/mail/mail_followers.py index e4028111a73..b8a714bf400 100644 --- a/addons/mail/mail_followers.py +++ b/addons/mail/mail_followers.py @@ -131,10 +131,11 @@ class mail_notification(osv.Model): company = "<a style='color:inherit' href='%s'>%s</a>" % (website_url, user.company_id.name) else: company = user.company_id.name - sent_by = _('Sent from %(company)s using %(openerp)s') + sent_by = _('Sent by %(company)s using %(odoo)s.') + signature_company = '<small>%s</small>' % (sent_by % { 'company': company, - 'openerp': "<a style='color:inherit' href='https://www.openerp.com/'>OpenERP</a>" + 'odoo': "<a style='color:inherit' href='https://www.odoo.com/'>Odoo</a>" }) footer = tools.append_content_to_html(footer, signature_company, plaintext=False, container_tag='div') @@ -167,8 +168,9 @@ class mail_notification(osv.Model): # compute email body (signature, company data) body_html = message.body - user_id = message.author_id and message.author_id.user_ids and message.author_id.user_ids[0] and message.author_id.user_ids[0].id or None - if user_signature: + # add user signature except for mail groups, where users are usually adding their own signatures already + if user_signature and message.model != 'mail.group': + user_id = message.author_id and message.author_id.user_ids and message.author_id.user_ids[0] and message.author_id.user_ids[0].id or None signature_company = self.get_signature_footer(cr, uid, user_id, res_model=message.model, res_id=message.res_id, context=context) body_html = tools.append_content_to_html(body_html, signature_company, plaintext=False, container_tag='div') diff --git a/addons/mail/mail_group.py b/addons/mail/mail_group.py index ef4e02b9fc3..777251e434a 100644 --- a/addons/mail/mail_group.py +++ b/addons/mail/mail_group.py @@ -221,12 +221,16 @@ class mail_group(osv.Model): def message_get_email_values(self, cr, uid, id, notif_mail=None, context=None): res = super(mail_group, self).message_get_email_values(cr, uid, id, notif_mail=notif_mail, context=context) group = self.browse(cr, uid, id, context=context) - res.update({ - 'headers': { - 'Precedence': 'list', - } - }) + headers = res.setdefault('headers', {}) + headers['Precedence'] = 'list' + # avoid out-of-office replies from MS Exchange + # http://blogs.technet.com/b/exchange/archive/2006/10/06/3395024.aspx + headers['X-Auto-Response-Suppress'] = 'OOF' if group.alias_domain: - res['headers']['List-Id'] = '%s.%s' % (group.alias_name, group.alias_domain) - res['headers']['List-Post'] = '<mailto:%s@%s>' % (group.alias_name, group.alias_domain) + headers['List-Id'] = '%s.%s' % (group.alias_name, group.alias_domain) + headers['List-Post'] = '<mailto:%s@%s>' % (group.alias_name, group.alias_domain) + # Avoid users thinking it was a personal message + # X-Forge-To: will replace To: after SMTP envelope is determined by ir.mail.server + list_to = '"%s" <%s@%s>' % (group.name, group.alias_name, group.alias_domain) + headers['X-Forge-To'] = list_to return res diff --git a/addons/mail/tests/test_mail_features.py b/addons/mail/tests/test_mail_features.py index 0a481c78eca..aa6692cee04 100644 --- a/addons/mail/tests/test_mail_features.py +++ b/addons/mail/tests/test_mail_features.py @@ -468,14 +468,10 @@ class test_mail(TestMail): 'message_post: notification email subject incorrect') self.assertIn(_body1, sent_email['body'], 'message_post: notification email body incorrect') - self.assertIn(user_raoul.signature, sent_email['body'], - 'message_post: notification email body should contain the sender signature') self.assertIn('Pigs rules', sent_email['body_alternative'], 'message_post: notification email body alternative should contain the body') self.assertNotIn('<p>', sent_email['body_alternative'], 'message_post: notification email body alternative still contains html') - self.assertIn(user_raoul.signature, sent_email['body_alternative'], - 'message_post: notification email body alternative should contain the sender signature') self.assertFalse(sent_email['references'], 'message_post: references should be False when sending a message that is not a reply') @@ -539,14 +535,10 @@ class test_mail(TestMail): 'message_post: notification email subject incorrect') self.assertIn(html_sanitize(_body2), sent_email['body'], 'message_post: notification email does not contain the body') - self.assertIn(user_raoul.signature, sent_email['body'], - 'message_post: notification email body should contain the sender signature') self.assertIn('Pigs rocks', sent_email['body_alternative'], 'message_post: notification email body alternative should contain the body') self.assertNotIn('<p>', sent_email['body_alternative'], 'message_post: notification email body alternative still contains html') - self.assertIn(user_raoul.signature, sent_email['body_alternative'], - 'message_post: notification email body alternative should contain the sender signature') self.assertIn(msg_message_id, sent_email['references'], 'message_post: notification email references lacks parent message message_id') # Test: attachments + download diff --git a/addons/procurement/wizard/schedulers_all.py b/addons/procurement/wizard/schedulers_all.py index 5c712b3af38..fd39a0ab094 100644 --- a/addons/procurement/wizard/schedulers_all.py +++ b/addons/procurement/wizard/schedulers_all.py @@ -19,10 +19,14 @@ # ############################################################################## +import logging import threading +from openerp import pooler, SUPERUSER_ID, tools from openerp.osv import osv +_logger = logging.getLogger(__name__) + class procurement_compute_all(osv.osv_memory): _name = 'procurement.order.compute.all' _description = 'Compute all schedulers' @@ -38,6 +42,16 @@ class procurement_compute_all(osv.osv_memory): proc_obj = self.pool.get('procurement.order') #As this function is in a new thread, i need to open a new cursor, because the old one may be closed new_cr = self.pool.cursor() + scheduler_cron_id = self.pool['ir.model.data'].get_object_reference(new_cr, SUPERUSER_ID, 'procurement', 'ir_cron_scheduler_action')[1] + # Avoid to run the scheduler multiple times in the same time + try: + with tools.mute_logger('openerp.sql_db'): + new_cr.execute("SELECT id FROM ir_cron WHERE id = %s FOR UPDATE NOWAIT", (scheduler_cron_id,)) + except Exception: + _logger.info('Attempt to run procurement scheduler aborted, as already running') + new_cr.rollback() + new_cr.close() + return {} proc_obj.run_scheduler(new_cr, uid, use_new_cursor=new_cr.dbname, context=context) #close the new cursor new_cr.close() diff --git a/addons/product/product.py b/addons/product/product.py index b7090841dde..94b431ec66f 100644 --- a/addons/product/product.py +++ b/addons/product/product.py @@ -389,6 +389,7 @@ class product_attribute_price(osv.osv): class product_attribute_line(osv.osv): _name = "product.attribute.line" + _rec_name = 'attribute_id' _columns = { 'product_tmpl_id': fields.many2one('product.template', 'Product Template', required=True), 'attribute_id': fields.many2one('product.attribute', 'Attribute', required=True), diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index 75e79cfb90c..7054d258782 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -385,7 +385,7 @@ </h1> <group> <group> - <field name="project_id" domain="[('state', '!=', 'close')]" on_change="onchange_project(project_id)" context="{'default_use_tasks':1}"/> + <field name="project_id" domain="[('state','not in', ('close', 'cancelled'))]" on_change="onchange_project(project_id)" context="{'default_use_tasks':1}"/> <field name="user_id" options='{"no_open": True}' context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'project.group_project_user']}"/> diff --git a/addons/sale/sale.py b/addons/sale/sale.py index 397bc0deccc..9ac2124c80c 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -634,7 +634,7 @@ class sale_order(osv.osv): compose_form_id = ir_model_data.get_object_reference(cr, uid, 'mail', 'email_compose_message_wizard_form')[1] except ValueError: compose_form_id = False - ctx = dict(context) + ctx = dict() ctx.update({ 'default_model': 'sale.order', 'default_res_id': ids[0], diff --git a/addons/sale/wizard/sale_make_invoice_advance.py b/addons/sale/wizard/sale_make_invoice_advance.py index c3f1d6cade4..3d8cc3e6997 100644 --- a/addons/sale/wizard/sale_make_invoice_advance.py +++ b/addons/sale/wizard/sale_make_invoice_advance.py @@ -37,6 +37,7 @@ class sale_advance_payment_inv(osv.osv_memory): Use Some Order Lines to invoice a selection of the sales order lines."""), 'qtty': fields.float('Quantity', digits=(16, 2), required=True), 'product_id': fields.many2one('product.product', 'Advance Product', + domain=[('type', '=', 'service')], help="""Select a product of type service which is called 'Advance Product'. You may have to create it and set it as a default value on this field."""), 'amount': fields.float('Advance Amount', digits_compute= dp.get_precision('Account'), diff --git a/addons/website_crm/controllers/main.py b/addons/website_crm/controllers/main.py index 935e1005c6b..5b615c96dad 100644 --- a/addons/website_crm/controllers/main.py +++ b/addons/website_crm/controllers/main.py @@ -26,7 +26,11 @@ class contactus(http.Controller): values.update(kwargs=kwargs.items()) return request.website.render("website.contactus", values) - @http.route(['/crm/contactus'], type='http', auth="public", website=True) + def create_lead(self, request, values): + """ Allow to be overrided """ + return request.registry['crm.lead'].create(request.cr, SUPERUSER_ID, values, request.context) + + @http.route(['/crm/contactus'], type='http', auth="public", website=True, multilang=True) def contactus(self, **kwargs): def dict_to_str(title, dictvar): ret = "\n\n%s" % title @@ -42,12 +46,10 @@ class contactus(http.Controller): post_description = [] # Info to add after the message values = {} - lead_model = request.registry['crm.lead'] - for field_name, field_value in kwargs.items(): if hasattr(field_value, 'filename'): post_file.append(field_value) - elif field_name in lead_model._all_columns and field_name not in _BLACKLIST: + elif field_name in request.registry['crm.lead']._all_columns and field_name not in _BLACKLIST: values[field_name] = field_value elif field_name not in _TECHNICAL: # allow to add some free fields or blacklisted field like ID post_description.append("%s: %s" % (field_name, field_value)) @@ -81,7 +83,7 @@ class contactus(http.Controller): post_description.append("%s: %s" % ("REFERER", environ.get("HTTP_REFERER"))) values['description'] += dict_to_str(_("Environ Fields: "), post_description) - lead_id = lead_model.create(request.cr, SUPERUSER_ID, dict(values, user_id=False), request.context) + lead_id = self.create_lead(request, dict(values, user_id=False)) if lead_id: for field_value in post_file: attachment_value = { diff --git a/addons/website_forum/controllers/main.py b/addons/website_forum/controllers/main.py index b3b0d243de7..efb280fe07a 100644 --- a/addons/website_forum/controllers/main.py +++ b/addons/website_forum/controllers/main.py @@ -79,7 +79,7 @@ class WebsiteForum(http.Controller): forum_id = request.registry['forum.forum'].create(request.cr, request.uid, { 'name': forum_name, }, context=request.context) - return request.redirect("/forum/%s" % slug(forum_id)) + return request.redirect("/forum/%s" % forum_id) @http.route('/forum/notification_read', type='json', auth="user", methods=['POST'], website=True) def notification_read(self, **kwargs): diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py index 4a992006cde..25e2d2548cb 100644 --- a/addons/website_forum/models/forum.py +++ b/addons/website_forum/models/forum.py @@ -254,6 +254,8 @@ class Post(osv.Model): def vote(self, cr, uid, ids, upvote=True, context=None): Vote = self.pool['forum.post.vote'] vote_ids = Vote.search(cr, uid, [('post_id', 'in', ids), ('user_id', '=', uid)], context=context) + new_vote = '1' if upvote else '-1' + voted_forum_ids = set() if vote_ids: for vote in Vote.browse(cr, uid, vote_ids, context=context): if upvote: @@ -261,9 +263,9 @@ class Post(osv.Model): else: new_vote = '0' if vote.vote == '1' else '-1' Vote.write(cr, uid, vote_ids, {'vote': new_vote}, context=context) - else: + voted_forum_ids.add(vote.post_id.id) + for post_id in set(ids) - voted_forum_ids: for post_id in ids: - new_vote = '1' if upvote else '-1' Vote.create(cr, uid, {'post_id': post_id, 'vote': new_vote}, context=context) return {'vote_count': self._get_vote_count(cr, uid, ids, None, None, context=context)[ids[0]]} diff --git a/addons/website_mail/static/src/js/follow.js b/addons/website_mail/static/src/js/follow.js index 18c36378328..a8b351efa6c 100644 --- a/addons/website_mail/static/src/js/follow.js +++ b/addons/website_mail/static/src/js/follow.js @@ -40,17 +40,21 @@ } this.$target.removeClass('has-error'); - openerp.jsonRpc('/website_mail/follow', 'call', { - 'id': +this.$target.data('id'), - 'object': this.$target.data('object'), - 'message_is_follower': this.$target.attr("data-follow") || "off", - 'email': $email.length ? $email.val() : false, - }).then(function (follow) { - self.toggle_subscription(follow, self.email); - }); + var email = $email.length ? $email.val() : false; + if (email) { + openerp.jsonRpc('/website_mail/follow', 'call', { + 'id': +this.$target.data('id'), + 'object': this.$target.data('object'), + 'message_is_follower': this.$target.attr("data-follow") || "off", + 'email': email, + }).then(function (follow) { + self.toggle_subscription(follow, email); + }); + } }, toggle_subscription: function(follow, email) { console.log(follow, email); + follow = follow || (!email && this.$target.attr('data-unsubscribe')); if (follow) { this.$target.find(".js_follow_btn").addClass("hidden"); this.$target.find(".js_unfollow_btn").removeClass("hidden"); @@ -60,8 +64,8 @@ this.$target.find(".js_unfollow_btn").addClass("hidden"); } this.$target.find('input.js_follow_email') - .val(email ? email : "") - .attr("disabled", follow || (email.length && this.is_user) ? "disabled" : false); + .val(email || "") + .attr("disabled", email && (follow || this.is_user) ? "disabled" : false); this.$target.attr("data-follow", follow ? 'on' : 'off'); }, }); diff --git a/addons/website_mail/views/website_mail.xml b/addons/website_mail/views/website_mail.xml index 0ccae00e21d..2b810095231 100644 --- a/addons/website_mail/views/website_mail.xml +++ b/addons/website_mail/views/website_mail.xml @@ -5,7 +5,8 @@ <template id="follow"> <div class="input-group js_follow" t-att-data-id="object.id" t-att-data-object="object._name" - t-att-data-follow="object.id and object.message_is_follower and 'on' or 'off'"> + t-att-data-follow="object.id and object.message_is_follower and 'on' or 'off'" + t-att-data-unsubscribe="'unsubscribe' if 'unsubscribe' in request.params else None"> <input type="email" name="email" class="js_follow_email form-control" diff --git a/addons/website_mail_group/models/mail_group.py b/addons/website_mail_group/models/mail_group.py index 804785b66f9..66fe36aca88 100644 --- a/addons/website_mail_group/models/mail_group.py +++ b/addons/website_mail_group/models/mail_group.py @@ -1,7 +1,9 @@ # -*- coding: utf-8 -*- from openerp.osv import osv - +from openerp import tools +from openerp.tools.translate import _ +from openerp.addons.website.models.website import slug class MailGroup(osv.Model): _inherit = 'mail.group' @@ -11,8 +13,40 @@ class MailGroup(osv.Model): group = self.browse(cr, uid, id, context=context) base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url') res['headers'].update({ - 'List-Archive': '<%s/groups/%s>' % (base_url, group.id), + 'List-Archive': '<%s/groups/%s>' % (base_url, slug(group)), 'List-Subscribe': '<%s/groups>' % (base_url), - 'List-Unsubscribe': '<%s/groups>' % (base_url), + 'List-Unsubscribe': '<%s/groups?unsubscribe>' % (base_url,), }) return res + + +class MailMail(osv.Model): + _inherit = 'mail.mail' + + def send_get_mail_body(self, cr, uid, mail, partner=None, context=None): + """ Short-circuit parent method for mail groups, replace the default + footer with one appropriate for mailing-lists.""" + + if mail.model == 'mail.group' and mail.res_id: + # no super() call on purpose, no private links that could be quoted! + group = self.pool['mail.group'].browse(cr, uid, mail.res_id, context=context) + base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url') + vals = { + 'maillist': _('Mailing-List'), + 'post_to': _('Post to'), + 'unsub': _('Unsubscribe'), + 'mailto': 'mailto:%s@%s' % (group.alias_name, group.alias_domain), + 'group_url': '%s/groups/%s' % (base_url, slug(group)), + 'unsub_url': '%s/groups?unsubscribe' % (base_url,), + } + footer = """_______________________________________________ + %(maillist)s: %(group_url)s + %(post_to)s: %(mailto)s + %(unsub)s: %(unsub_url)s + """ % vals + body = tools.append_content_to_html(mail.body, footer, container_tag='div') + return body + else: + return super(MailMail, self).send_get_mail_body(cr, uid, mail, + partner=partner, + context=context) diff --git a/addons/website_mail_group/views/website_mail_group.xml b/addons/website_mail_group/views/website_mail_group.xml index 332c6e7b576..75e6e7579d8 100644 --- a/addons/website_mail_group/views/website_mail_group.xml +++ b/addons/website_mail_group/views/website_mail_group.xml @@ -31,6 +31,9 @@ </section> </div> <div class="container mt32"> + <div t-if="'unsubscribe' in request.params" class="col-md-offset-9 col-md-3 alert alert-info"> + <h3>Need to unsubscribe? It's right here! <span class="fa fa-2x fa-arrow-down pull-right"></span></h3> + </div> <div class="row mt8" t-foreach="groups" t-as="group"> <div class="col-md-3"> <img t-att-src="'/website/image?model=mail.group&field=image_small&id='+str(group['id'])" class="pull-left"/> diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index bcd86aff7a4..b9738e49c40 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -605,7 +605,7 @@ class website_sale(http.Controller): if not order: return { 'state': 'error', - 'message': '<p>There seems to be an error with your request.</p>', + 'message': '<p>%s</p>' % _('There seems to be an error with your request.'), } tx_ids = request.registry['payment.transaction'].search( @@ -617,7 +617,7 @@ class website_sale(http.Controller): if order.amount_total: return { 'state': 'error', - 'message': '<p>There seems to be an error with your request.</p>', + 'message': '<p>%s</p>' % _('There seems to be an error with your request.'), } else: state = 'done' @@ -627,15 +627,15 @@ class website_sale(http.Controller): tx = request.registry['payment.transaction'].browse(cr, uid, tx_ids[0], context=context) state = tx.state if state == 'done': - message = '<p>Your payment has been received.</p>' + message = '<p>%s</p>' % _('Your payment has been received.') elif state == 'cancel': - message = '<p>The payment seems to have been canceled.</p>' + message = '<p>%s</p>' % _('The payment seems to have been canceled.') elif state == 'pending' and tx.acquirer_id.validation == 'manual': - message = '<p>Your transaction is waiting confirmation.</p>' + message = '<p>%s</p>' % _('Your transaction is waiting confirmation.') if tx.acquirer_id.post_msg: message += tx.acquirer_id.post_msg else: - message = '<p>Your transaction is waiting confirmation.</p>' + message = '<p>%s</p>' % _('Your transaction is waiting confirmation.') validation = tx.acquirer_id.validation return { diff --git a/addons/website_sale/views/templates.xml b/addons/website_sale/views/templates.xml index 9975098072b..9efdb5159b5 100644 --- a/addons/website_sale/views/templates.xml +++ b/addons/website_sale/views/templates.xml @@ -876,14 +876,14 @@ <div class="clearfix"/> - <div class="form-group col-lg-6" groups="sale.group_delivery_invoice_address"> + <div class="form-group col-lg-6"> <label> <input type="checkbox" name="shipping_different" t-att-checked="checkout.get('shipping_different')"/> <span>Ship to a different address</span> </label> </div> </div> - <div class="js_shipping row mb16" t-att-style="not checkout.get('shipping_different') and 'display:none' or ''" groups="sale.group_delivery_invoice_address"> + <div class="js_shipping row mb16" t-att-style="not checkout.get('shipping_different') and 'display:none' or ''"> <h3 class="oe_shipping col-lg-12 mt16">Shipping Information</h3> <div t-attf-class="form-group #{error.get('shipping_name') and 'has-error' or ''} col-lg-6"> @@ -1026,7 +1026,7 @@ <div> <a href="/shop/checkout"><span class="fa fa-arrow-right"/> Change Address</a> </div> - <t groups="sale.group_delivery_invoice_address"> + <t> <h4 class="mt32">Ship To:</h4> <t t-if="website_sale_order.partner_shipping_id and website_sale_order.partner_shipping_id.id != website_sale_order.partner_invoice_id.id"> <div t-field="order.partner_shipping_id" t-field-options='{ @@ -1116,7 +1116,7 @@ "widget": "contact", "fields": ["address", "name", "phone", "email"] }'/> - <t groups="sale.group_delivery_invoice_address"> + <t> <h4 class="mt32">Ship To:</h4> <t t-if="order.partner_shipping_id and order.partner_shipping_id.id != order.partner_invoice_id.id"> <div t-field="order.partner_shipping_id" t-field-options='{ diff --git a/openerp/addons/base/ir/ir_mail_server.py b/openerp/addons/base/ir/ir_mail_server.py index 4af52bdea41..56a51640da7 100644 --- a/openerp/addons/base/ir/ir_mail_server.py +++ b/openerp/addons/base/ir/ir_mail_server.py @@ -415,6 +415,13 @@ class ir_mail_server(osv.osv): smtp_to_list = filter(None, tools.flatten(map(extract_rfc2822_addresses,[email_to, email_cc, email_bcc]))) assert smtp_to_list, "At least one valid recipient address should be specified for outgoing emails (To/Cc/Bcc)" + x_forge_to = message['X-Forge-To'] + if x_forge_to: + # `To:` header forged, e.g. for posting on mail.groups, to avoid confusion + del message['X-Forge-To'] + del message['To'] # avoid multiple To: headers! + message['To'] = x_forge_to + # Do not actually send emails in testing mode! if getattr(threading.currentThread(), 'testing', False): _test_logger.info("skip sending email in test mode") diff --git a/openerp/addons/base/ir/ir_values.py b/openerp/addons/base/ir/ir_values.py index 6af09b7ecbb..9411886a304 100644 --- a/openerp/addons/base/ir/ir_values.py +++ b/openerp/addons/base/ir/ir_values.py @@ -303,10 +303,10 @@ class ir_values(osv.osv): (SELECT company_id from res_users where id = %%s) ) %s - ORDER BY v.user_id, u.company_id""" + ORDER BY v.user_id, u.company_id, v.key2""" params = ('default', model, uid, uid) if condition: - query %= 'AND v.key2 = %s' + query %= 'AND (v.key2 = %s OR v.key2 IS NULL)' params += (condition[:200],) else: query %= 'AND v.key2 is NULL' |
