From 9fc4ad99f0736b31ac58e25d7eb7a70c7d3ec7f9 Mon Sep 17 00:00:00 2001 From: Anthony Muschang Date: Wed, 11 Jun 2014 11:36:11 +0200 Subject: [PATCH 01/20] [FIX]mass mailing: performance issue on stats #469 --- addons/mass_mailing/mass_mailing.py | 91 +++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 24 deletions(-) diff --git a/addons/mass_mailing/mass_mailing.py b/addons/mass_mailing/mass_mailing.py index e7583d8e739..68edcde9390 100644 --- a/addons/mass_mailing/mass_mailing.py +++ b/addons/mass_mailing/mass_mailing.py @@ -37,15 +37,36 @@ class MassMailingCampaign(osv.Model): def _get_statistics(self, cr, uid, ids, name, arg, context=None): """ Compute statistics of the mass mailing campaign """ - results = dict.fromkeys(ids, False) - for campaign in self.browse(cr, uid, ids, context=context): - results[campaign.id] = { - 'sent': len(campaign.statistics_ids), + results = dict.fromkeys(ids, { + 'sent': 0, + 'delivered': 0, + 'opened': 0, + 'replied': 0, + 'bounced': 0, + }) + cr.execute(""" + SELECT + mass_mailing_id, + COUNT(id) AS sent, + COUNT(CASE WHEN bounced is null THEN 1 ELSE null END) AS delivered, + COUNT(CASE WHEN opened is not null THEN 1 ELSE null END) AS opened, + COUNT(CASE WHEN replied is not null THEN 1 ELSE null END) AS replied , + COUNT(CASE WHEN bounced is not null THEN 1 ELSE null END) AS bounced + FROM + mail_mail_statistics + WHERE + mass_mailing_id IN %s + GROUP BY + mass_mailing_id + """, (tuple(ids), )) + for (campaign_id, sent, delivered, opened, replied, bounced) in cr.fetchall(): + results[campaign_id] = { + 'sent': sent, # delivered: shouldn't be: all mails - (failed + bounced) ? - 'delivered': len([stat for stat in campaign.statistics_ids if not stat.bounced]), # stat.state == 'sent' and - 'opened': len([stat for stat in campaign.statistics_ids if stat.opened]), - 'replied': len([stat for stat in campaign.statistics_ids if stat.replied]), - 'bounced': len([stat for stat in campaign.statistics_ids if stat.bounced]), + 'delivered': delivered, + 'opened': opened, + 'replied': replied, + 'bounced': bounced, } return results @@ -53,14 +74,14 @@ class MassMailingCampaign(osv.Model): """ Gather data about mass mailings to display them in kanban view as nested kanban views is not possible currently. """ results = dict.fromkeys(ids, '') - for campaign in self.browse(cr, uid, ids, context=context): + for campaign_id in ids: mass_mailing_results = [] - for mass_mailing in campaign.mass_mailing_ids[:self._kanban_mailing_nbr]: - mass_mailing_object = {} - for attr in ['name', 'sent', 'delivered', 'opened', 'replied', 'bounced']: - mass_mailing_object[attr] = getattr(mass_mailing, attr) - mass_mailing_results.append(mass_mailing_object) - results[campaign.id] = mass_mailing_results + mass_mailing_results = self.pool['mail.mass_mailing'].search_read(cr, uid, + domain=[('mass_mailing_campaign_id', '=', campaign_id)], + fields=['name', 'sent', 'delivered', 'opened', 'replied', 'bounced'], + limit=self._kanban_mailing_nbr, + context=context) + results[campaign_id] = mass_mailing_results return results _columns = { @@ -195,15 +216,37 @@ class MassMailing(osv.Model): return res def _get_statistics(self, cr, uid, ids, name, arg, context=None): - """ Compute statistics of the mass mailing campaign """ - results = dict.fromkeys(ids, False) - for mass_mailing in self.browse(cr, uid, ids, context=context): - results[mass_mailing.id] = { - 'sent': len(mass_mailing.statistics_ids), - 'delivered': len([stat for stat in mass_mailing.statistics_ids if not stat.bounced]), # mail.state == 'sent' and - 'opened': len([stat for stat in mass_mailing.statistics_ids if stat.opened]), - 'replied': len([stat for stat in mass_mailing.statistics_ids if stat.replied]), - 'bounced': len([stat for stat in mass_mailing.statistics_ids if stat.bounced]), + """ Compute statistics of the mass mailing """ + results = dict.fromkeys(ids, { + 'sent': 0, + 'delivered': 0, + 'opened': 0, + 'replied': 0, + 'bounced': 0, + }) + cr.execute(""" + SELECT + mass_mailing_id, + COUNT(id) AS sent, + COUNT(CASE WHEN bounced is null THEN 1 ELSE null END) AS delivered, + COUNT(CASE WHEN opened is not null THEN 1 ELSE null END) AS opened, + COUNT(CASE WHEN replied is not null THEN 1 ELSE null END) AS replied , + COUNT(CASE WHEN bounced is not null THEN 1 ELSE null END) AS bounced + FROM + mail_mail_statistics + WHERE + mass_mailing_id IN %s + GROUP BY + mass_mailing_id + """, (tuple(ids), )) + for (campaign_id, sent, delivered, opened, replied, bounced) in cr.fetchall(): + results[campaign_id] = { + 'sent': sent, + # delivered: shouldn't be: all mails - (failed + bounced) ? + 'delivered': delivered, + 'opened': opened, + 'replied': replied, + 'bounced': bounced, } return results From d8a0e3d29a6d64822f703027e34238cdd8e0ea2e Mon Sep 17 00:00:00 2001 From: Nicolas Bessi Date: Fri, 27 Jun 2014 14:19:34 +0200 Subject: [PATCH 02/20] Fix wrong relative import of hr_payroll --- addons/l10n_in_hr_payroll/report/report_payslip_details.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/l10n_in_hr_payroll/report/report_payslip_details.py b/addons/l10n_in_hr_payroll/report/report_payslip_details.py index 462bb374287..37cb7c2a0b7 100644 --- a/addons/l10n_in_hr_payroll/report/report_payslip_details.py +++ b/addons/l10n_in_hr_payroll/report/report_payslip_details.py @@ -20,7 +20,7 @@ ############################################################################## from openerp.report import report_sxw -from hr_payroll import report +from openerp.addons.hr_payroll import report class payslip_details_report_in(report.report_payslip_details.payslip_details_report): @@ -32,4 +32,4 @@ class payslip_details_report_in(report.report_payslip_details.payslip_details_re report_sxw.report_sxw('report.paylip.details.in', 'hr.payslip', 'l10n_in_hr_payroll/report/report_payslip_details.rml', parser=payslip_details_report_in) -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From df40926d2a57c101a3e2d221ecfd08fbb4fea30e Mon Sep 17 00:00:00 2001 From: Jacques-Etienne Baudoux Date: Fri, 27 Jun 2014 16:47:20 +0200 Subject: [PATCH 03/20] [IMP] res_partner: more fault tolerant name_create In case of invalid format such as 'name email@server' (missing chevrons), the parsing would be failing due to a strict behaviour of getaddresses (returns nameemail@server). With the patch this format is accepted. opw 607312 --- openerp/addons/base/res/res_partner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index d43028d68ef..30d79bd7da1 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -559,7 +559,7 @@ class res_partner(osv.osv, format_address): """ Supported syntax: - 'Raoul ': will find name and email address - otherwise: default, everything is set as the name """ - emails = tools.email_split(text) + emails = tools.email_split(text.replace(' ',',')) if emails: email = emails[0] name = text[:text.index(email)].replace('"', '').replace('<', '').strip() From f825b6043bd138049ee2a107e44596ceba8ef954 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Tue, 1 Jul 2014 11:29:22 +0200 Subject: [PATCH 04/20] [FIX] rml: avoid reports ending by zero (opw 608073) Commit b6a7402 (reverted at f8671cb) was almost correct, the PageReset should be added at the end of each stories but only if we have one more stories. The PageReset will force the page count to be reseted at zero which means that last page of report would have been at zero. --- openerp/report/render/rml2pdf/trml2pdf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/report/render/rml2pdf/trml2pdf.py b/openerp/report/render/rml2pdf/trml2pdf.py index 70965d2c0cd..9ed1a14a21b 100644 --- a/openerp/report/render/rml2pdf/trml2pdf.py +++ b/openerp/report/render/rml2pdf/trml2pdf.py @@ -999,10 +999,10 @@ class _rml_template(object): story_cnt = 0 for node_story in node_stories: if story_cnt > 0: + # Reset Page Number with new story tag + fis.append(PageReset()) fis.append(platypus.PageBreak()) fis += r.render(node_story) - # Reset Page Number with new story tag - fis.append(PageReset()) story_cnt += 1 try: if self.localcontext and self.localcontext.get('internal_header',False): From 3d3134108d51462474a9323903fe5b549aac0119 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 1 Jul 2014 12:22:28 +0200 Subject: [PATCH 05/20] [FIX] web_linkedin: update master img CDN domain, recently changed --- addons/web_linkedin/web_linkedin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web_linkedin/web_linkedin.py b/addons/web_linkedin/web_linkedin.py index 62883840f2d..5a27993bfbd 100644 --- a/addons/web_linkedin/web_linkedin.py +++ b/addons/web_linkedin/web_linkedin.py @@ -36,7 +36,7 @@ class Binary(openerp.addons.web.http.Controller): _scheme, _netloc, path, params, query, fragment = urlparse(url) # media.linkedin.com is the master domain for LinkedIn media (replicated to CDNs), # so forcing it should always work and prevents abusing this method to load arbitrary URLs - url = urlunparse(('http', 'media.linkedin.com', path, params, query, fragment)) + url = urlunparse(('http', 'media.licdn.com', path, params, query, fragment)) bfile = urllib2.urlopen(url) return base64.b64encode(bfile.read()) From 451b6b9f3a5987778227c3eafd1e0d64833e56b4 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Tue, 1 Jul 2014 15:48:53 +0200 Subject: [PATCH 06/20] [FIX] project_issue_sheet: make invoiceable field autofield for worklogs When setting a worklog on a project_issue, the field to_invoice is prefilled with on_change_account_id based on the contract settings. As the field was not present on the list view, the information was lost and every worklog was not written as invoiceable, even if enabled on the contract. opw 609082. --- addons/project_issue_sheet/project_issue_sheet_view.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/project_issue_sheet/project_issue_sheet_view.xml b/addons/project_issue_sheet/project_issue_sheet_view.xml index fb245a0510a..80304deaab1 100644 --- a/addons/project_issue_sheet/project_issue_sheet_view.xml +++ b/addons/project_issue_sheet/project_issue_sheet_view.xml @@ -31,6 +31,7 @@ + From 581341ce3f91f997a7543fa9385a1764c0c53134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 2 Jul 2014 10:25:53 +0200 Subject: [PATCH 07/20] [FIX] mail: fixed display issue with the like button --- addons/mail/static/src/css/mail.css | 8 +------- addons/mail/static/src/xml/mail.xml | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index 50e190c846d..e55948634c5 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -164,15 +164,9 @@ border-radius: 3px; margin: 0px; padding-left: 3px; - padding-right: 15px; + padding-right: 5px; margin-right: 5px; } -.openerp .oe_mail .oe_mail_vote_count .oe_e{ - position: absolute; - bottom: 1px; - right: 2px; - font-size: 26px; -} /* c) Message action icons */ diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index 2a4ac8d1bf9..5d3175b40d7 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -355,7 +355,7 @@ - 8 + like From 376cdf36b43381c06066cb0b6e5d0ef4b0c45c3b Mon Sep 17 00:00:00 2001 From: Richard Mathot Date: Wed, 2 Jul 2014 13:56:11 +0200 Subject: [PATCH 08/20] [FIX] auth_oauth: prevent crash on login screen Empty URLs for OAuth providers do not crash anymore the login screen --- addons/auth_oauth/controllers/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/auth_oauth/controllers/main.py b/addons/auth_oauth/controllers/main.py index 214fdefe1fb..fe3c8bef905 100644 --- a/addons/auth_oauth/controllers/main.py +++ b/addons/auth_oauth/controllers/main.py @@ -48,7 +48,8 @@ class OAuthLogin(openerp.addons.web.controllers.main.Home): def list_providers(self): try: provider_obj = request.registry.get('auth.oauth.provider') - providers = provider_obj.search_read(request.cr, SUPERUSER_ID, [('enabled', '=', True)]) + providers = provider_obj.search_read(request.cr, SUPERUSER_ID, [('enabled', '=', True), ('auth_endpoint', '!=', False), ('validation_endpoint', '!=', False)]) + # TODO in forwardport: remove conditions on 'auth_endpoint' and 'validation_endpoint' when these fields will be 'required' in model except Exception: providers = [] for provider in providers: From 1c5058c931a6ef55f013ec0c0ca2578ddf75f4a4 Mon Sep 17 00:00:00 2001 From: Richard Mathot Date: Wed, 2 Jul 2014 14:07:52 +0200 Subject: [PATCH 09/20] [FIX] auth_oauth: hide invalid providers from login screen --- addons/auth_oauth/controllers/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/auth_oauth/controllers/main.py b/addons/auth_oauth/controllers/main.py index 62eb2e812cc..8fb7ce92607 100644 --- a/addons/auth_oauth/controllers/main.py +++ b/addons/auth_oauth/controllers/main.py @@ -46,7 +46,7 @@ class OAuthController(oeweb.Controller): registry = RegistryManager.get(dbname) with registry.cursor() as cr: providers = registry.get('auth.oauth.provider') - l = providers.read(cr, SUPERUSER_ID, providers.search(cr, SUPERUSER_ID, [('enabled', '=', True)])) + l = providers.read(cr, SUPERUSER_ID, providers.search(cr, SUPERUSER_ID, [('enabled', '=', True), ('auth_endpoint', '!=', False), ('validation_endpoint', '!=', False)])) except Exception: l = [] return l From e80014eae3a622c1491d3f2905b3b6b9e12c6be8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lionel=20Sausin=20=28Num=C3=A9rigraphe=29?= Date: Sat, 31 May 2014 19:00:34 +0200 Subject: [PATCH 10/20] [FIX] Fixes #273: avoid double-warning when changing the quantity of a stock move --- addons/stock/stock.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 981b6f749c0..3b1e70646f1 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -1901,7 +1901,6 @@ class stock_move(osv.osv): result = { 'product_qty': 0.00 } - warning = {} if (not product_id) or (product_uos_qty <=0.0): result['product_uos_qty'] = 0.0 @@ -1909,22 +1908,15 @@ class stock_move(osv.osv): product_obj = self.pool.get('product.product') uos_coeff = product_obj.read(cr, uid, product_id, ['uos_coeff']) - - # Warn if the quantity was decreased - for move in self.read(cr, uid, ids, ['product_uos_qty']): - if product_uos_qty < move['product_uos_qty']: - warning.update({ - 'title': _('Warning: No Back Order'), - 'message': _("By changing the quantity here, you accept the " - "new quantity as complete: OpenERP will not " - "automatically generate a Back Order.") }) - break + + # No warning if the quantity was decreased to avoid double warnings: + # The clients should call onchange_quantity too anyway if product_uos and product_uom and (product_uom != product_uos): result['product_qty'] = product_uos_qty / uos_coeff['uos_coeff'] else: result['product_qty'] = product_uos_qty - return {'value': result, 'warning': warning} + return {'value': result} def onchange_product_id(self, cr, uid, ids, prod_id=False, loc_id=False, loc_dest_id=False, partner_id=False): From a6bf8cd07bc0712d7466b51f4f346ac91a61d7ea Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Wed, 2 Jul 2014 16:25:24 +0200 Subject: [PATCH 11/20] [FIX] website: avoid divisions by zero when no record to display --- addons/website/views/website_templates.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/website/views/website_templates.xml b/addons/website/views/website_templates.xml index de4eb4fb94b..5932931688a 100644 --- a/addons/website/views/website_templates.xml +++ b/addons/website/views/website_templates.xml @@ -411,7 +411,7 @@ - +
From fbbc3a54e91e7768ecf33038154a2bdbd87505ba Mon Sep 17 00:00:00 2001 From: Richard Mathot Date: Wed, 2 Jul 2014 17:29:13 +0200 Subject: [PATCH 12/20] [FIX] RML reporting: understandable crash message When tag is misused in an RML report, logs a more explicit error --- openerp/report/render/rml2pdf/trml2pdf.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openerp/report/render/rml2pdf/trml2pdf.py b/openerp/report/render/rml2pdf/trml2pdf.py index 9ed1a14a21b..ec5e9484805 100644 --- a/openerp/report/render/rml2pdf/trml2pdf.py +++ b/openerp/report/render/rml2pdf/trml2pdf.py @@ -373,7 +373,11 @@ class _rml_canvas(object): v = utils.attr_get(node, ['x','y']) text=self._textual(node, **v) text = utils.xml2str(text) - self.canvas.drawString(text=text, **v) + try: + self.canvas.drawString(text=text, **v) + except TypeError as e: + _logger.error("Bad RML: tag requires attributes 'x' and 'y'!") + raise e def _drawCenteredString(self, node): v = utils.attr_get(node, ['x','y']) From 04eff4fe3d157774a1529c743f24b00cb2e28d93 Mon Sep 17 00:00:00 2001 From: Richard Mathot Date: Thu, 3 Jul 2014 09:36:46 +0200 Subject: [PATCH 13/20] [TYPO] Stupid typo... --- openerp/report/render/rml2pdf/trml2pdf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/report/render/rml2pdf/trml2pdf.py b/openerp/report/render/rml2pdf/trml2pdf.py index ec5e9484805..75bc30d4a19 100644 --- a/openerp/report/render/rml2pdf/trml2pdf.py +++ b/openerp/report/render/rml2pdf/trml2pdf.py @@ -376,7 +376,7 @@ class _rml_canvas(object): try: self.canvas.drawString(text=text, **v) except TypeError as e: - _logger.error("Bad RML: tag requires attributes 'x' and 'y'!") + _logger.error("Bad RML: tag requires attributes 'x' and 'y'!") raise e def _drawCenteredString(self, node): From bf353998f20c27eed3494a172c7afa174c20865a Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 3 Jul 2014 12:30:48 +0200 Subject: [PATCH 14/20] [FIX] res_partner: backport of rev 37bf72a Correctly take the 'use parent address' into account in the onchange. Slightly updated the view that was weird with this parameter. opw 609344 --- openerp/addons/base/res/res_partner.py | 8 +++++--- openerp/addons/base/res/res_partner_view.xml | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 30d79bd7da1..4d86c1cbf3f 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -344,6 +344,7 @@ class res_partner(osv.osv, format_address): value = {} value['title'] = False if is_company: + value['use_parent_address'] = False domain = {'title': [('domain', '=', 'partner')]} else: domain = {'title': [('domain', '=', 'contact')]} @@ -363,9 +364,10 @@ class res_partner(osv.osv, format_address): 'was never correctly set. If an existing contact starts working for a new ' 'company then a new contact should be created under that new ' 'company. You can use the "Discard" button to abandon this change.')} - parent = self.browse(cr, uid, parent_id, context=context) - address_fields = self._address_fields(cr, uid, context=context) - result['value'] = dict((key, value_or_id(parent[key])) for key in address_fields) + if use_parent_address: + parent = self.browse(cr, uid, parent_id, context=context) + address_fields = self._address_fields(cr, uid, context=context) + result['value'] = dict((key, value_or_id(parent[key])) for key in address_fields) else: result['value'] = {'use_parent_address': False} return result diff --git a/openerp/addons/base/res/res_partner_view.xml b/openerp/addons/base/res/res_partner_view.xml index fd394549f4b..724cce7bb5f 100644 --- a/openerp/addons/base/res/res_partner_view.xml +++ b/openerp/addons/base/res/res_partner_view.xml @@ -157,8 +157,8 @@
-