From e33baecfa3eff21a74a55f3b48b7a5cec99b9ddf Mon Sep 17 00:00:00 2001 From: Nicolas Lempereur Date: Tue, 7 Jul 2015 09:50:18 +0200 Subject: [PATCH 01/46] [FIX] osv: binary size already in human format In version 8.0, postgresql's pg_size_pretty function is used (http://www.postgresql.org/docs/9.4/static/functions-admin.html) when getting the size of a binary field when reading if `bin_size` or `bin_size_[col_name]` is set in the context. So in 8.0 the size of a binary field get units bytes, kB, MB, GB and TB which was not taken into account. e.g: '5.3 GB'. This fix uses the size of the string to choose to differenciate the two. e.g: '10000 bytes' (the longest size) will be returned directly, but for something longer the human size of the content length will be returned. There is a corner case if a file is shorter than 12 bytes but it is an enough of a small scenario with small implications that it is deemed acceptable. closes #7485 opw-644085 --- openerp/addons/base/ir/ir_attachment.py | 3 --- openerp/osv/fields.py | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/openerp/addons/base/ir/ir_attachment.py b/openerp/addons/base/ir/ir_attachment.py index 82ec746ec6b..a4927931d08 100644 --- a/openerp/addons/base/ir/ir_attachment.py +++ b/openerp/addons/base/ir/ir_attachment.py @@ -162,9 +162,6 @@ class ir_attachment(osv.osv): result[attach.id] = self._file_read(cr, uid, attach.store_fname, bin_size) else: result[attach.id] = attach.db_datas - if bin_size: - result[attach.id] = int(result[attach.id] or 0) - return result def _data_set(self, cr, uid, id, name, value, arg, context=None): diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index b2f71142638..5ef82ed2683 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -1069,6 +1069,8 @@ def get_nice_size(value): size = value elif value: # this is supposed to be a string size = len(value) + if size < 12: # suppose human size + return value return tools.human_size(size) # See http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char From 669948569b66ef384fcbb00b5739ace0ed9d5eef Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Fri, 3 Jul 2015 15:05:48 +0200 Subject: [PATCH 02/46] [FIX] website_sale: alternative products Display correctly the alternative products opw:643934 --- addons/website_sale/views/templates.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/website_sale/views/templates.xml b/addons/website_sale/views/templates.xml index d4dd628102d..dcf473e0a05 100644 --- a/addons/website_sale/views/templates.xml +++ b/addons/website_sale/views/templates.xml @@ -548,9 +548,9 @@

Suggested alternatives:

-
+
-
+
From 7fb37b3e8970e8f4de27c43f9403c900dba6ae35 Mon Sep 17 00:00:00 2001 From: Lionel Sausin Date: Tue, 7 Jul 2015 16:06:57 +0200 Subject: [PATCH 03/46] [FIX] stock: missing default filter for quants menu Most (if not every) other ways to open a list of quants has default filters to include only internal locations. Closes #7501 --- addons/stock/stock_view.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml index f0e7019fa48..8bca5138b0a 100644 --- a/addons/stock/stock_view.xml +++ b/addons/stock/stock_view.xml @@ -1652,6 +1652,7 @@ stock.quant form tree,form,graph + {'search_default_internal_loc': 1} This analysis gives you a fast overview on the current stock level of your products and their today's inventory value. From e27d85480167862decf72a5914c0fffefaecc737 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Wed, 8 Jul 2015 10:27:19 +0200 Subject: [PATCH 04/46] [FIX] website_sale: delete console.log Delete console.log introduced by 4d7671a4c355b33aa75a2aa81d3ea84ce164538f --- addons/website_sale/static/src/js/website_sale.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/addons/website_sale/static/src/js/website_sale.js b/addons/website_sale/static/src/js/website_sale.js index e07b59f97cc..aa8add0dc4c 100644 --- a/addons/website_sale/static/src/js/website_sale.js +++ b/addons/website_sale/static/src/js/website_sale.js @@ -44,7 +44,6 @@ $('.oe_website_sale').each(function () { $(oe_website_sale).find(".oe_cart input.js_quantity").on("change", function () { var $input = $(this); if ($input.data('update_change')) { - console.log($input.val()+ "+++"); return; } var value = parseInt($input.val(), 10); @@ -81,7 +80,6 @@ $('.oe_website_sale').each(function () { .then(function (data) { $input.data('update_change', false); if (value !== parseInt($input.val(), 10)) { - console.log($input.val()+ "***"); $input.trigger('change'); return; } From f86d5870fcf9c592a614c3c938bdcb34e29f412b Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Wed, 8 Jul 2015 11:10:34 +0200 Subject: [PATCH 05/46] [FIX] res.country: Preferred address format According to the USPS, separating the city name and the zip code with a comma is acceptable, but the preferred format omits the comma. http://pe.usps.gov/cpim/ftp/pubs/Pub28/pub28.pdf opw-644000 --- openerp/addons/base/res/res_country_data.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/res/res_country_data.xml b/openerp/addons/base/res/res_country_data.xml index c9ef761d282..243c289a091 100644 --- a/openerp/addons/base/res/res_country_data.xml +++ b/openerp/addons/base/res/res_country_data.xml @@ -1408,7 +1408,7 @@ United States us - + From 91985d7eae34c2c6e1cf7890dd3435e53a966d8d Mon Sep 17 00:00:00 2001 From: Erwin van der Ploeg Date: Mon, 6 Jul 2015 16:28:51 +0200 Subject: [PATCH 06/46] [FIX] stock: visibility of "Recheck Availability" If a picking is partially available and some lines are waiting another operation --- addons/stock/stock_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml index 8bca5138b0a..19b2284da29 100644 --- a/addons/stock/stock_view.xml +++ b/addons/stock/stock_view.xml @@ -642,7 +642,7 @@
') + + def visit_line_block(self, node): + self.body.append(self.starttag(node, 'div', CLASS='line-block')) + def depart_line_block(self, node): + self.body.append(u'
') + def visit_table(self, node): self.body.append(self.starttag(node, 'table', CLASS='table')) def depart_table(self, node): @@ -591,23 +603,31 @@ class BootstrapTranslator(nodes.NodeVisitor, object): entries = [(title, ref)] if not toc else ((e[0], e[1]) for e in toc[0]['entries']) for subtitle, subref in entries: + baseuri = self.builder.get_target_uri(node['parent']) + if subref in env.metadata: cover = env.metadata[subref].get('banner', conf.odoo_cover_default) elif subref in conf.odoo_cover_external: cover = conf.odoo_cover_external[subref] else: cover = conf.odoo_cover_default_external - banner = '_static/' + cover - base, ext = os.path.splitext(banner) - small = "{}.small{}".format(base, ext) - if os.path.isfile(urllib.url2pathname(small)): - banner = small - baseuri = self.builder.get_target_uri(node['parent']) + + if cover: + banner = '_static/' + cover + base, ext = os.path.splitext(banner) + small = "{}.small{}".format(base, ext) + if os.path.isfile(urllib.url2pathname(small)): + banner = small + style = u"background-image: url('{}')".format( + util.relative_uri(baseuri, banner) or '#') + else: + style = u'' + self.body.append(u"""
- +
{title}
@@ -615,7 +635,7 @@ class BootstrapTranslator(nodes.NodeVisitor, object): """.format( link=subref if util.url_re.match(subref) else util.relative_uri( baseuri, self.builder.get_target_uri(subref)), - banner=util.relative_uri(baseuri, banner) or '#', + style=style, title=subtitle if subtitle else util.nodes.clean_astext(env.titles[subref]), )) diff --git a/doc/conf.py b/doc/conf.py index 8ae57282314..bffee53df33 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -92,7 +92,6 @@ pygments_style = 'odoo' # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'odoo' -html_translator_class = 'odoo.translator.BootstrapTranslator' odoo_cover_default = 'banners/installing_odoo.jpg' odoo_cover_external = { From c97cb3508687d05fb5e4241ef5ec7214f38f6fd9 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 8 Jul 2015 12:37:19 +0200 Subject: [PATCH 09/46] [FIX] doc: prevent compacting paragraphs with custom classes --- doc/_extensions/odoo/translator.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/_extensions/odoo/translator.py b/doc/_extensions/odoo/translator.py index 6bb041e2323..9e0762ed208 100644 --- a/doc/_extensions/odoo/translator.py +++ b/doc/_extensions/odoo/translator.py @@ -144,6 +144,13 @@ class BootstrapTranslator(nodes.NodeVisitor, object): addnodes.versionmodified)): # Never compact paragraphs in document or compound. return False + + for key, value in node.attlist(): + # we can ignore a few specific classes, all other non-default + # attributes require that a

node remains + if key != 'classes' or value not in ([], ['first'], ['last'], ['first', 'last']): + return False + first = isinstance(node.parent[0], nodes.label) for child in parent.children[first:]: # only first paragraph can be compact From 5f768ed5b3b9456793aa78873ceb02f788abcd88 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 8 Jul 2015 12:37:40 +0200 Subject: [PATCH 10/46] [IMP] doc: don't limit width of pages with code column --- doc/_extensions/odoo/layout.html | 12 +- doc/_extensions/odoo/static/layout.less | 5 - doc/_extensions/odoo/static/style.css | 811 +----------------------- 3 files changed, 10 insertions(+), 818 deletions(-) diff --git a/doc/_extensions/odoo/layout.html b/doc/_extensions/odoo/layout.html index c14eab647eb..df8f6db8c2a 100644 --- a/doc/_extensions/odoo/layout.html +++ b/doc/_extensions/odoo/layout.html @@ -9,10 +9,11 @@ {% set classes = [] %} {% if pagename == master_doc %} -{% set classes = classes + ['index'] %} + {% set classes = classes + ['index'] %} {% endif %} + {% if 'code-column' in meta %} -{% set classes = classes + ['has_code_col'] %} + {% set classes = classes + ['has_code_col'] %} {% endif %} {%- block doctype -%} @@ -90,7 +91,12 @@ {%- endblock -%} {%- block content -%} -

+ {% if 'code-column' in meta %} + {% set container = 'container-fluid' %} + {% else %} + {% set container = 'container' %} + {% endif %} +
{% if pagename != master_doc %}
@@ -99,6 +98,7 @@
{% if pagename != master_doc %}
+ {% if 'has-toc' not in meta %} -
+ {% endif %} +
{% endif %} {% block body %} {% endblock %} {% if pagename != master_doc %}
diff --git a/doc/_extensions/odoo/static/layout.less b/doc/_extensions/odoo/static/layout.less index bc06a40ab0a..c7ce372f6b6 100644 --- a/doc/_extensions/odoo/static/layout.less +++ b/doc/_extensions/odoo/static/layout.less @@ -118,6 +118,9 @@ main{ padding-left: 30px; @media (min-width: @w-size-medium) { width: 75%; + &.doc-toc { + width: 100%; + } } > *{ max-width: 100%; diff --git a/doc/_extensions/odoo/static/style.css b/doc/_extensions/odoo/static/style.css index 2c5c0bee1e4..5165680ef4b 100644 --- a/doc/_extensions/odoo/static/style.css +++ b/doc/_extensions/odoo/static/style.css @@ -8599,6 +8599,9 @@ main article.doc-body { main article.doc-body { width: 75%; } + main article.doc-body.doc-toc { + width: 100%; + } } main article.doc-body > * { max-width: 100%; From 4be4678d8baa041dfd3be6dc6d94c162ab8da879 Mon Sep 17 00:00:00 2001 From: Lionel Sausin Date: Wed, 8 Jul 2015 17:41:19 +0200 Subject: [PATCH 27/46] [FIX] stock_account: use all inbound/outbound moves when valuating The valuation wizard is based on stock moves and currently only takes into account the moves which have different companies in source vs destination locations. This is a problem because all user-created locations have a default company set to the user's company, even the "virtual" ones. For example in the demo dataset visible on runbot, some supplier locations have a company set and some don't. So we have to make sure to include every move coming from/going to outside locations based on the locations's type too. Closes #7530 --- .../wizard/stock_valuation_history.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/addons/stock_account/wizard/stock_valuation_history.py b/addons/stock_account/wizard/stock_valuation_history.py index 9a12ff24e1f..6856940c0b6 100644 --- a/addons/stock_account/wizard/stock_valuation_history.py +++ b/addons/stock_account/wizard/stock_valuation_history.py @@ -150,8 +150,11 @@ class stock_history(osv.osv): LEFT JOIN product_template ON product_template.id = product_product.product_tmpl_id WHERE quant.qty>0 AND stock_move.state = 'done' AND dest_location.usage in ('internal', 'transit') AND stock_quant_move_rel.quant_id = quant.id - AND stock_quant_move_rel.move_id = stock_move.id AND ((source_location.company_id is null and dest_location.company_id is not null) or - (source_location.company_id is not null and dest_location.company_id is null) or source_location.company_id != dest_location.company_id) + AND stock_quant_move_rel.move_id = stock_move.id AND ( + (source_location.company_id is null and dest_location.company_id is not null) or + (source_location.company_id is not null and dest_location.company_id is null) or + source_location.company_id != dest_location.company_id or + source_location.usage not in ('internal', 'transit')) ) UNION (SELECT '-' || stock_move.id::text || '-' || quant.id::text AS id, @@ -176,8 +179,11 @@ class stock_history(osv.osv): LEFT JOIN product_template ON product_template.id = product_product.product_tmpl_id WHERE quant.qty>0 AND stock_move.state = 'done' AND source_location.usage in ('internal', 'transit') AND stock_quant_move_rel.quant_id = quant.id - AND stock_quant_move_rel.move_id = stock_move.id AND ((dest_location.company_id is null and source_location.company_id is not null) or - (dest_location.company_id is not null and source_location.company_id is null) or dest_location.company_id != source_location.company_id) + AND stock_quant_move_rel.move_id = stock_move.id AND ( + (dest_location.company_id is null and source_location.company_id is not null) or + (dest_location.company_id is not null and source_location.company_id is null) or + dest_location.company_id != source_location.company_id or + dest_location.usage not in ('internal', 'transit')) )) AS foo GROUP BY move_id, location_id, company_id, product_id, product_categ_id, date, price_unit_on_quant, source From f3e4d0a2e82a7effda2be76bb90ca5353da9d6ee Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Wed, 8 Jul 2015 10:48:03 +0200 Subject: [PATCH 28/46] [FIX] openerp: export None instead of False in raw_data mode If we export False or an empty string, the Excel export will consider the field similarly to a boolean, and en empty value will be converted into "=False()" in Excel. To prevent this, we return "None" in the following cases: - String - Date - Datetime - Selection - Reference - Many2one - RelationalMulti Introduced by 6243d18 opw-643966 --- openerp/addons/test_impex/tests/test_export.py | 4 ++-- openerp/fields.py | 17 +++++++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/openerp/addons/test_impex/tests/test_export.py b/openerp/addons/test_impex/tests/test_export.py index 023a27df387..49a16387a3a 100644 --- a/openerp/addons/test_impex/tests/test_export.py +++ b/openerp/addons/test_impex/tests/test_export.py @@ -265,7 +265,7 @@ class test_selection_function(CreatorCase): def test_empty(self): self.assertEqual( self.export(False), - [[False]]) + [[None]]) def test_value(self): # FIXME: selection functions export the *value* itself @@ -278,7 +278,7 @@ class test_selection_function(CreatorCase): # fucking hell self.assertEqual( self.export(0), - [[False]]) + [[None]]) class test_m2o(CreatorCase): model_name = 'export.many2one' diff --git a/openerp/fields.py b/openerp/fields.py index f88bc01c068..ca605dff0f2 100644 --- a/openerp/fields.py +++ b/openerp/fields.py @@ -1092,6 +1092,11 @@ class _String(Field): _column_translate = property(attrgetter('translate')) _related_translate = property(attrgetter('translate')) _description_translate = property(attrgetter('translate')) + + def convert_to_export(self, value, env): + if env.context.get('export_raw_data'): + return value if value else None + return bool(value) and ustr(value) class Char(_String): @@ -1212,7 +1217,7 @@ class Date(Field): def convert_to_export(self, value, env): if value and env.context.get('export_raw_data'): - return self.from_string(value) + return self.from_string(value) or None return bool(value) and ustr(value) @@ -1281,7 +1286,7 @@ class Datetime(Field): def convert_to_export(self, value, env): if value and env.context.get('export_raw_data'): - return self.from_string(value) + return self.from_string(value) or None return bool(value) and ustr(value) def convert_to_display_name(self, value, record=None): @@ -1390,7 +1395,7 @@ class Selection(Field): def convert_to_export(self, value, env): if not isinstance(self.selection, list): # FIXME: this reproduces an existing buggy behavior! - return value + return value or None for item in self._description_selection(env): if item[0] == value: return item[1] @@ -1427,7 +1432,7 @@ class Reference(Selection): return "%s,%s" % (value._name, value.id) if value else False def convert_to_export(self, value, env): - return bool(value) and value.name_get()[0][1] + return value.name_get()[0][1] if value else None def convert_to_display_name(self, value, record=None): return ustr(value and value.display_name) @@ -1567,7 +1572,7 @@ class Many2one(_Relational): return value.id def convert_to_export(self, value, env): - return bool(value) and value.name_get()[0][1] + return value.name_get()[0][1] if value else None def convert_to_display_name(self, value, record=None): return ustr(value.display_name) @@ -1673,7 +1678,7 @@ class _RelationalMulti(_Relational): return result def convert_to_export(self, value, env): - return bool(value) and ','.join(name for id, name in value.name_get()) + return ','.join(name for id, name in value.name_get()) if value else None def convert_to_display_name(self, value, record=None): raise NotImplementedError() From 7c2521a79bc9443adab1bc63007e70661a8c22b7 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Thu, 9 Jul 2015 11:46:32 +0200 Subject: [PATCH 29/46] [FIX] payment_ogone: amount rounding issue The amount to pay must be sent without comma to ogone. e.g., for 66.99 EUR, the amount sent must be 6699. To do that, we simply applied 66.99 * 100, which seems rather good. However, due to the fact how floats are handled in computers, `66.99 * 100` returns 6698.999999999999 and `int(6698.999999999999)` returns 6698 while we expected 6699 Using `float_repr` with `0` as decimal precision instead of using `int` solves this issue. `float_repr(6698.999999999999, 0)` returns 6699, as expected. --- addons/payment_ogone/models/ogone.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/addons/payment_ogone/models/ogone.py b/addons/payment_ogone/models/ogone.py index e3e33c69db9..60864ac4422 100644 --- a/addons/payment_ogone/models/ogone.py +++ b/addons/payment_ogone/models/ogone.py @@ -15,7 +15,7 @@ from openerp.addons.payment_ogone.controllers.main import OgoneController from openerp.addons.payment_ogone.data import ogone from openerp.osv import osv, fields from openerp.tools import float_round, DEFAULT_SERVER_DATE_FORMAT -from openerp.tools.float_utils import float_compare +from openerp.tools.float_utils import float_compare, float_repr _logger = logging.getLogger(__name__) @@ -141,12 +141,11 @@ class PaymentAcquirerOgone(osv.Model): def ogone_form_generate_values(self, cr, uid, id, partner_values, tx_values, context=None): base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url') acquirer = self.browse(cr, uid, id, context=context) - ogone_tx_values = dict(tx_values) temp_ogone_tx_values = { 'PSPID': acquirer.ogone_pspid, 'ORDERID': tx_values['reference'], - 'AMOUNT': '%d' % int(float_round(tx_values['amount'], 2) * 100), + 'AMOUNT': float_repr(float_round(tx_values['amount'], 2) * 100, 0), 'CURRENCY': tx_values['currency'] and tx_values['currency'].name or '', 'LANGUAGE': partner_values['lang'], 'CN': partner_values['name'], From 2835381c7edd472869cd86fe43e35a588b43e6e2 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Thu, 9 Jul 2015 10:49:30 +0200 Subject: [PATCH 30/46] [FIX] acount: aged partner balance In the aged balance report, the reconcile entries are excluded except if the reconciliation date is greater than the date for which the aged balance report is requested. But this exception should never include opening entries. opw:643172 --- .../report/account_aged_partner_balance.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/addons/account/report/account_aged_partner_balance.py b/addons/account/report/account_aged_partner_balance.py index 61649b1a603..3ed137f0a88 100644 --- a/addons/account/report/account_aged_partner_balance.py +++ b/addons/account/report/account_aged_partner_balance.py @@ -75,7 +75,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header): AND (account_account.type IN %s)\ AND account_account.active\ AND ((reconcile_id IS NULL)\ - OR (reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s )))\ + OR (reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s AND not recon.opening_reconciliation)))\ AND (l.partner_id=res_partner.id)\ AND (l.date <= %s)\ AND ' + self.query + ' \ @@ -99,7 +99,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header): AND (account_account.type IN %s)\ AND (l.partner_id IN %s)\ AND ((l.reconcile_id IS NULL)\ - OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s )))\ + OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s AND not recon.opening_reconciliation)))\ AND ' + self.query + '\ AND account_account.active\ AND (l.date <= %s)\ @@ -119,7 +119,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header): AND (COALESCE(l.date_maturity, l.date) < %s)\ AND (l.partner_id IN %s)\ AND ((l.reconcile_id IS NULL)\ - OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s )))\ + OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s AND not recon.opening_reconciliation)))\ AND '+ self.query + '\ AND account_account.active\ AND (l.date <= %s)\ @@ -136,7 +136,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header): AND (COALESCE(l.date_maturity,l.date) > %s)\ AND (l.partner_id IN %s)\ AND ((l.reconcile_id IS NULL)\ - OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s )))\ + OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s AND not recon.opening_reconciliation)))\ AND '+ self.query + '\ AND account_account.active\ AND (l.date <= %s)\ @@ -168,7 +168,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header): AND (account_account.type IN %s) AND (l.partner_id IN %s) AND ((l.reconcile_id IS NULL) - OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s ))) + OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s AND not recon.opening_reconciliation))) AND ''' + self.query + ''' AND account_account.active AND ''' + dates_query + ''' @@ -264,7 +264,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header): AND (l.partner_id IS NULL)\ AND (account_account.type IN %s)\ AND ((l.reconcile_id IS NULL) \ - OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s )))\ + OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s AND not recon.opening_reconciliation)))\ AND ' + self.query + '\ AND (l.date <= %s)\ AND account_account.active ',(tuple(move_state), tuple(self.ACCOUNT_TYPE), self.date_from, self.date_from,)) @@ -281,7 +281,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header): AND (account_account.type IN %s)\ AND (COALESCE(l.date_maturity, l.date) < %s)\ AND ((l.reconcile_id IS NULL)\ - OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s )))\ + OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s AND not recon.opening_reconciliation)))\ AND '+ self.query + '\ AND account_account.active ', (tuple(move_state), tuple(self.ACCOUNT_TYPE), self.date_from, self.date_from)) t = self.cr.fetchall() @@ -296,7 +296,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header): AND (account_account.type IN %s)\ AND (COALESCE(l.date_maturity,l.date) > %s)\ AND ((l.reconcile_id IS NULL)\ - OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s )))\ + OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s AND not recon.opening_reconciliation)))\ AND '+ self.query + '\ AND account_account.active ', (tuple(move_state), tuple(self.ACCOUNT_TYPE), self.date_from, self.date_from)) t = self.cr.fetchall() @@ -324,7 +324,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header): AND (account_account.type IN %s)\ AND (l.partner_id IS NULL)\ AND ((l.reconcile_id IS NULL)\ - OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s )))\ + OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s AND not recon.opening_reconciliation)))\ AND '+ self.query + '\ AND account_account.active\ AND ' + dates_query + '\ From dacf29427f9a2b951a53296f5ecc4db3b5ee71ec Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Thu, 9 Jul 2015 12:15:44 +0200 Subject: [PATCH 31/46] [FIX] purchase: Invoicing on incoming shipments The filter "Incoming Shipments to Invoice" must not include shipments that are already invoiced. opw:644407 --- addons/purchase/stock_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/purchase/stock_view.xml b/addons/purchase/stock_view.xml index 174dc99d4f5..d157f3cd07d 100644 --- a/addons/purchase/stock_view.xml +++ b/addons/purchase/stock_view.xml @@ -18,7 +18,7 @@ - + From 85a06f8a6e43d32c8bca117e9deeca89ce939046 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Thu, 9 Jul 2015 13:58:13 +0200 Subject: [PATCH 32/46] [FIX] sale: confirmed sale order line The filter "Confirmed" is applied on sale order line. Introduced by b927f8a8643b7de4c326de5dc7de94b9fd81e738 --- addons/sale/sale_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml index 28264cf049a..a669ed17681 100644 --- a/addons/sale/sale_view.xml +++ b/addons/sale/sale_view.xml @@ -421,7 +421,7 @@ - + From 4adb4b8d15c528f8946cc8c766fa712c3effbb85 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Thu, 9 Jul 2015 15:47:46 +0200 Subject: [PATCH 33/46] [FIX] sale, website_sale: Send email on sale order confirmation Not just when coming back from the payment provider to the payment validation route `/shop/payment/validate`. Otherwise, if you do not come back from the payment provider page, that you quit just after having paid but just before being redirected to Odoo, you do not receive the email. The change within the `sale` module, while this issue concerns `website_sale` only, has been accepted because this is a mechanism that could be used by other modules. opw-644348 --- addons/sale/sale.py | 23 +++++++++++++++++++++++ addons/website_sale/controllers/main.py | 24 +----------------------- addons/website_sale/models/payment.py | 2 +- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/addons/sale/sale.py b/addons/sale/sale.py index 48ad722300b..0575c48d2bd 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -598,8 +598,31 @@ class sale_order(osv.osv): return True def action_button_confirm(self, cr, uid, ids, context=None): + if not context: + context = {} assert len(ids) == 1, 'This option should only be used for a single id at a time.' self.signal_workflow(cr, uid, ids, 'order_confirm') + if context.get('send_email'): + order_id = ids[0] + email_act = self.action_quotation_send(cr, uid, [order_id], context=context) + if email_act and email_act.get('context'): + composer_obj = self.pool['mail.compose.message'] + composer_values = {} + email_ctx = email_act['context'] + template_values = [ + email_ctx.get('default_template_id'), + email_ctx.get('default_composition_mode'), + email_ctx.get('default_model'), + email_ctx.get('default_res_id'), + ] + composer_values.update(composer_obj.onchange_template_id(cr, uid, None, *template_values, context=context).get('value', {})) + if not composer_values.get('email_from'): + composer_values['email_from'] = self.browse(cr, uid, order_id, context=context).company_id.email + for key in ['attachment_ids', 'partner_ids']: + if composer_values.get(key): + composer_values[key] = [(6, 0, composer_values[key])] + composer_id = composer_obj.create(cr, uid, composer_values, context=email_ctx) + composer_obj.send_mail(cr, uid, [composer_id], context=email_ctx) return True def action_wait(self, cr, uid, ids, context=None): diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index 32da18da360..cee6d529e57 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -802,33 +802,11 @@ class website_sale(http.Controller): if (not order.amount_total and not tx): # Orders are confirmed by payment transactions, but there is none for free orders, # (e.g. free events), so confirm immediately - order.action_button_confirm() - # send by email - email_act = sale_order_obj.action_quotation_send(cr, SUPERUSER_ID, [order.id], context=request.context) + order.with_context(dict(context, send_email=True)).action_button_confirm() elif tx and tx.state == 'cancel': # cancel the quotation sale_order_obj.action_cancel(cr, SUPERUSER_ID, [order.id], context=request.context) - # send the email - if email_act and email_act.get('context'): - composer_obj = request.registry['mail.compose.message'] - composer_values = {} - email_ctx = email_act['context'] - template_values = [ - email_ctx.get('default_template_id'), - email_ctx.get('default_composition_mode'), - email_ctx.get('default_model'), - email_ctx.get('default_res_id'), - ] - composer_values.update(composer_obj.onchange_template_id(cr, SUPERUSER_ID, None, *template_values, context=context).get('value', {})) - if not composer_values.get('email_from') and uid == request.website.user_id.id: - composer_values['email_from'] = request.website.user_id.company_id.email - for key in ['attachment_ids', 'partner_ids']: - if composer_values.get(key): - composer_values[key] = [(6, 0, composer_values[key])] - composer_id = composer_obj.create(cr, SUPERUSER_ID, composer_values, context=email_ctx) - composer_obj.send_mail(cr, SUPERUSER_ID, [composer_id], context=email_ctx) - # clean context and session, then redirect to the confirmation page request.website.sale_reset(context=context) diff --git a/addons/website_sale/models/payment.py b/addons/website_sale/models/payment.py index 36b681a759b..32411b56c1e 100644 --- a/addons/website_sale/models/payment.py +++ b/addons/website_sale/models/payment.py @@ -23,6 +23,6 @@ class PaymentTransaction(orm.Model): if hasattr(self, tx_find_method_name): tx = getattr(self, tx_find_method_name)(cr, uid, data, context=context) if tx and tx.state == 'done' and tx.sale_order_id and tx.sale_order_id.state in ['draft', 'sent']: - self.pool['sale.order'].action_button_confirm(cr, SUPERUSER_ID, [tx.sale_order_id.id], context=context) + self.pool['sale.order'].action_button_confirm(cr, SUPERUSER_ID, [tx.sale_order_id.id], context=dict(context, send_email=True)) return res From 23cb6ef7dfd4ef73a1a5458cc0561988a3f47ef0 Mon Sep 17 00:00:00 2001 From: "Jose J. Duran" Date: Fri, 3 Jul 2015 10:26:06 +0200 Subject: [PATCH 34/46] [FIX] account_asset: missing named arguments in signature Otherwise the context of original method is lost. --- addons/account_asset/account_asset_invoice.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/account_asset/account_asset_invoice.py b/addons/account_asset/account_asset_invoice.py index 7e2f24f0d0a..4b235c874c3 100644 --- a/addons/account_asset/account_asset_invoice.py +++ b/addons/account_asset/account_asset_invoice.py @@ -24,8 +24,8 @@ from openerp.osv import fields, osv class account_invoice(osv.osv): _inherit = 'account.invoice' - def action_number(self, cr, uid, ids, *args): - result = super(account_invoice, self).action_number(cr, uid, ids, *args) + def action_number(self, cr, uid, ids, *args, **kargs): + result = super(account_invoice, self).action_number(cr, uid, ids, *args, **kargs) for inv in self.browse(cr, uid, ids): self.pool.get('account.invoice.line').asset_create(cr, uid, inv.invoice_line) return result From f27acff15a7793ab238394d8f423e95cd020a7c3 Mon Sep 17 00:00:00 2001 From: Lorenzo Battistini Date: Fri, 19 Jun 2015 11:35:41 +0200 Subject: [PATCH 35/46] [FIX] calendar: missing ondelete cascade calendar.attendee record should not exist without calendar.event --- addons/calendar/calendar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/calendar/calendar.py b/addons/calendar/calendar.py index 1beca121120..d1aa4674029 100644 --- a/addons/calendar/calendar.py +++ b/addons/calendar/calendar.py @@ -95,7 +95,7 @@ class calendar_attendee(osv.Model): 'email': fields.char('Email', help="Email of Invited Person"), 'availability': fields.selection([('free', 'Free'), ('busy', 'Busy')], 'Free/Busy', readonly="True"), 'access_token': fields.char('Invitation Token'), - 'event_id': fields.many2one('calendar.event', 'Meeting linked'), + 'event_id': fields.many2one('calendar.event', 'Meeting linked', ondelete='cascade'), } _defaults = { 'state': 'needsAction', From 1d0187223bb4f91da97455640f7fad54d44a4023 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 11 Sep 2014 12:34:54 -0400 Subject: [PATCH 36/46] [FIX] auth_oauth_signup: Factor out user signup values There is no easy way to edit the values sent to newly generated users from oauth_signup. In some cases, the mapping from an oauth provider can be different. * ex: login is something other than email In other cases, there are additional fields in res_users added by a module * ex: firstname and last name in `partner_firstname` This factorization allows modules inheriting from `auth_oauth_signup` to alter values sent to the copy of Template User. This means smaller changes to the default behaviour and the ability to properly inherit (multiple times if needed) this module without losing needed behaviour. Closes #2355 --- addons/auth_oauth_signup/res_users.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/addons/auth_oauth_signup/res_users.py b/addons/auth_oauth_signup/res_users.py index a06968fa46f..3f011aa14db 100644 --- a/addons/auth_oauth_signup/res_users.py +++ b/addons/auth_oauth_signup/res_users.py @@ -31,6 +31,20 @@ _logger = logging.getLogger(__name__) class res_users(osv.Model): _inherit = 'res.users' + def _generate_signup_values(self, cr, uid, provider, validation, params, context=None): + oauth_uid = validation['user_id'] + email = validation.get('email', 'provider_%s_user_%s' % (provider, oauth_uid)) + name = validation.get('name', email) + return { + 'name': name, + 'login': email, + 'email': email, + 'oauth_provider_id': provider, + 'oauth_uid': oauth_uid, + 'oauth_access_token': params['access_token'], + 'active': True, + } + def _auth_oauth_signin(self, cr, uid, provider, validation, params, context=None): # overridden to use signup method if regular oauth signin fails try: @@ -41,18 +55,7 @@ class res_users(osv.Model): return None state = simplejson.loads(params['state']) token = state.get('t') - oauth_uid = validation['user_id'] - email = validation.get('email', 'provider_%s_user_%s' % (provider, oauth_uid)) - name = validation.get('name', email) - values = { - 'name': name, - 'login': email, - 'email': email, - 'oauth_provider_id': provider, - 'oauth_uid': oauth_uid, - 'oauth_access_token': params['access_token'], - 'active': True, - } + values = self._generate_signup_values(cr, uid, provider, validation, params, context=context) try: _, login, _ = self.signup(cr, uid, values, token, context=context) except SignupError: From d780f9476d43eb4fd25c852dd4e691002f4a6dcf Mon Sep 17 00:00:00 2001 From: David Beal Date: Tue, 16 Sep 2014 11:56:16 +0200 Subject: [PATCH 37/46] [FIX] res.currency: allow duplication Currencies must be unique per company. Therefore, without this revision, adding `(Copy)` to the currency name on duplication, this is simply not possible to duplicate a currency. Closes #2443 --- openerp/addons/base/res/res_currency.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/openerp/addons/base/res/res_currency.py b/openerp/addons/base/res/res_currency.py index f12102d3577..6119de2798f 100644 --- a/openerp/addons/base/res/res_currency.py +++ b/openerp/addons/base/res/res_currency.py @@ -134,6 +134,16 @@ class res_currency(osv.osv): reads = self.read(cr, uid, ids, ['name','symbol'], context=context, load='_classic_write') return [(x['id'], tools.ustr(x['name'])) for x in reads] + def copy(self, cr, uid, id, default=None, context=None): + if context is None: + context = {} + if not default: + default = {} + default.update(name=_("%s (copy)") + % (self.browse(cr, uid, id, context=context).name)) + return super(res_currency, self).copy( + cr, uid, id, default=default, context=context) + @api.v8 def round(self, amount): """ Return `amount` rounded according to currency `self`. """ From 937f05a49220a150929df61a770eff172287d94b Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Fri, 10 Jul 2015 11:07:17 +0200 Subject: [PATCH 38/46] [FIX] website_forum: remove duplicated term Courtesy of Vincent Briffaux --- addons/website_forum/i18n/website_forum.pot | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/addons/website_forum/i18n/website_forum.pot b/addons/website_forum/i18n/website_forum.pot index b081a739e9d..54476ca5197 100644 --- a/addons/website_forum/i18n/website_forum.pot +++ b/addons/website_forum/i18n/website_forum.pot @@ -184,12 +184,8 @@ msgstr "" #. module: website_forum #: view:website:website_forum.header -msgid "Ask a Question" -msgstr "" - -#. module: website_forum #: field:forum.forum,karma_ask:0 -msgid "Ask a question" +msgid "Ask a Question" msgstr "" #. module: website_forum From cfb444a9d1b5c564112385338e997484923dbf51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20=C5=BBbikowski?= Date: Fri, 10 Jul 2015 11:36:11 +0200 Subject: [PATCH 39/46] =?UTF-8?q?[CLA]=20Dariusz=20=C5=BBbikowski?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/cla/individual/zbik2607.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 doc/cla/individual/zbik2607.md diff --git a/doc/cla/individual/zbik2607.md b/doc/cla/individual/zbik2607.md new file mode 100644 index 00000000000..d7803f4e447 --- /dev/null +++ b/doc/cla/individual/zbik2607.md @@ -0,0 +1,9 @@ +Poland, 2015-07-09 + +I hereby agree to the terms of the Odoo Individual Contributor License Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this declaration. + +Signed, + +Dariusz Żbikowski darek@krokus.com.pl https://github.com/zbik2607 \ No newline at end of file From 0f4399bb7b9ed811ebb85f65b47c4a3161283412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20=C5=BBbikowski?= Date: Fri, 10 Jul 2015 11:37:34 +0200 Subject: [PATCH 40/46] [FIX] res.country: address format in polan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address format in Poland looks like: Legionów 93 91-072 Lodz Poland see: http://en.wikipedia.org/wiki/Address_%28geography%29#Poland Closes #2416 --- openerp/addons/base/res/res_country_data.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/openerp/addons/base/res/res_country_data.xml b/openerp/addons/base/res/res_country_data.xml index 243c289a091..8764e6172b0 100644 --- a/openerp/addons/base/res/res_country_data.xml +++ b/openerp/addons/base/res/res_country_data.xml @@ -1081,6 +1081,7 @@ Poland pl + From 610f6fdafe8beecf90a50b40a271a444f66161f8 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 10 Jul 2015 11:56:02 +0200 Subject: [PATCH 41/46] [IMP] doc: support for image centering Also handle (and ignore) substitution definition nodes. --- doc/_extensions/odoo/translator.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/doc/_extensions/odoo/translator.py b/doc/_extensions/odoo/translator.py index 9e0762ed208..1fd73493098 100644 --- a/doc/_extensions/odoo/translator.py +++ b/doc/_extensions/odoo/translator.py @@ -356,6 +356,19 @@ class BootstrapTranslator(nodes.NodeVisitor, object): attrs = {'src': uri, 'class': 'img-responsive'} if 'alt' in node: attrs['alt'] = node['alt'] + if 'align' in node: + if node['align'] == 'center': + attrs['class'] += ' center-block' + else: + doc = None + if node.source: + doc = node.source + if node.line: + doc += ':%d' % node.line + self.builder.app.warn( + "Unsupported alignment value \"%s\"" % node['align'], + location=doc + ) # todo: explicit width/height/scale? self.body.append(self.starttag(node, 'img', **attrs)) def depart_image(self, node): pass @@ -661,3 +674,6 @@ class BootstrapTranslator(nodes.NodeVisitor, object): self.body.append('' % t) # Keep non-HTML raw text out of output: raise nodes.SkipNode + + # internal node + def visit_substitution_definition(self, node): raise nodes.SkipNode From 1bc4ed7c95f2cf0bc81f01d7b64fd2c5fcdc0ffb Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Fri, 10 Jul 2015 12:02:52 +0200 Subject: [PATCH 42/46] [FIX] point_of_sale: receipt report, qty decimal precision In the receipt report, the quantity decimal precision was hardcoded to 0, while it should use the decimal precision from the field definition. opw-644507 --- addons/point_of_sale/views/report_receipt.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/point_of_sale/views/report_receipt.xml b/addons/point_of_sale/views/report_receipt.xml index 4bbd44afbe4..39192072514 100644 --- a/addons/point_of_sale/views/report_receipt.xml +++ b/addons/point_of_sale/views/report_receipt.xml @@ -31,7 +31,7 @@ - + From 436fc5b67c36d5a4e5a4dfefe56e13239d962c92 Mon Sep 17 00:00:00 2001 From: stijnh92 Date: Thu, 4 Jun 2015 11:30:43 +0200 Subject: [PATCH 43/46] [FIX] l10n_ro: res.partner form inheritance The field property_account_position is added by the view account.view_partner_property_form which is restricted to users with accounting rights. If tired to access the view, the inheritance made on l10n_ro would fail. Fixes #6952 --- addons/l10n_ro/partner_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/l10n_ro/partner_view.xml b/addons/l10n_ro/partner_view.xml index 46c0cef1149..d13148160aa 100644 --- a/addons/l10n_ro/partner_view.xml +++ b/addons/l10n_ro/partner_view.xml @@ -3,7 +3,7 @@ res.partner.form.ro - + res.partner From d2b564309e8d875faa9a3d3854f1ead9f03af908 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Fri, 10 Jul 2015 12:10:22 +0200 Subject: [PATCH 44/46] [I18N] sale_stock: remove untranslatable string --- addons/sale_stock/i18n/sale_stock.pot | 5 ----- 1 file changed, 5 deletions(-) diff --git a/addons/sale_stock/i18n/sale_stock.pot b/addons/sale_stock/i18n/sale_stock.pot index 32b9977a1b6..db2bf052fb0 100644 --- a/addons/sale_stock/i18n/sale_stock.pot +++ b/addons/sale_stock/i18n/sale_stock.pot @@ -360,8 +360,3 @@ msgstr "" msgid "days" msgstr "" -#. module: sale_stock -#: view:sale.order:sale_stock.view_order_form_inherit -msgid "{\"shipping_except\":\"red\",\"invoice_except\":\"red\",\"waiting_date\":\"blue\"}" -msgstr "" - From 90e4aed1357e756007306c7573468ec02cf0c590 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Fri, 10 Jul 2015 12:20:10 +0200 Subject: [PATCH 45/46] [FIX] event: email templates should not be reset on update In case you customize these emails, you do not want to have them reset when you update the module (-u) Same thing for the two default value in this file for event.type opw-644082 --- addons/event/email_template.xml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/addons/event/email_template.xml b/addons/event/email_template.xml index d4479bcfc87..5bc0e484764 100644 --- a/addons/event/email_template.xml +++ b/addons/event/email_template.xml @@ -1,6 +1,6 @@ - + Confirmation of the Event @@ -15,9 +15,6 @@

Best regards

]]>
-
- - Confirmation of the Registration From 6e73a311468fb5bcebb5bbe93715ba585d07f4c3 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Wed, 8 Jul 2015 19:19:28 +0200 Subject: [PATCH 46/46] [FIX] base: ir.qweb: fault tolerant save of assets. Do not fail if an asset cannot be cached into the database. --- openerp/addons/base/ir/ir_qweb.py | 51 +++++++++++++++++++------------ 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/openerp/addons/base/ir/ir_qweb.py b/openerp/addons/base/ir/ir_qweb.py index f74170de46c..3d7c67cb6e3 100644 --- a/openerp/addons/base/ir/ir_qweb.py +++ b/openerp/addons/base/ir/ir_qweb.py @@ -20,6 +20,7 @@ import babel.dates import werkzeug from lxml import etree, html from PIL import Image +import psycopg2 import openerp.http import openerp.tools @@ -1257,16 +1258,21 @@ class AssetsBundle(object): ira = self.registry['ir.attachment'] url_prefix = '/web/%s/%s/' % (type, self.xmlid) # Invalidate previous caches - oids = ira.search(self.cr, openerp.SUPERUSER_ID, [('url', '=like', url_prefix + '%')], context=self.context) - if oids: - ira.unlink(self.cr, openerp.SUPERUSER_ID, oids, context=self.context) - url = url_prefix + self.version - ira.create(self.cr, openerp.SUPERUSER_ID, dict( + try: + with self.cr.savepoint(): + domain = [('url', '=like', url_prefix + '%')] + oids = ira.search(self.cr, openerp.SUPERUSER_ID, domain, context=self.context) + if oids: + ira.unlink(self.cr, openerp.SUPERUSER_ID, oids, context=self.context) + url = url_prefix + self.version + ira.create(self.cr, openerp.SUPERUSER_ID, dict( datas=content.encode('utf8').encode('base64'), type='binary', name=url, url=url, ), context=self.context) + except psycopg2.Error: + pass def css_message(self, message): return """ @@ -1504,21 +1510,26 @@ class SassAsset(StylesheetAsset): def to_html(self): if self.url: - ira = self.registry['ir.attachment'] - url = self.html_url % self.url - domain = [('type', '=', 'binary'), ('url', '=', self.url)] - ira_id = ira.search(self.cr, openerp.SUPERUSER_ID, domain, context=self.context) - if ira_id: - # TODO: update only if needed - ira.write(self.cr, openerp.SUPERUSER_ID, [ira_id], {'datas': self.content}, context=self.context) - else: - ira.create(self.cr, openerp.SUPERUSER_ID, dict( - datas=self.content.encode('utf8').encode('base64'), - mimetype='text/css', - type='binary', - name=url, - url=url, - ), context=self.context) + try: + ira = self.registry['ir.attachment'] + url = self.html_url % self.url + domain = [('type', '=', 'binary'), ('url', '=', self.url)] + with self.cr.savepoint(): + ira_id = ira.search(self.cr, openerp.SUPERUSER_ID, domain, context=self.context) + if ira_id: + # TODO: update only if needed + ira.write(self.cr, openerp.SUPERUSER_ID, [ira_id], {'datas': self.content}, + context=self.context) + else: + ira.create(self.cr, openerp.SUPERUSER_ID, dict( + datas=self.content.encode('utf8').encode('base64'), + mimetype='text/css', + type='binary', + name=url, + url=url, + ), context=self.context) + except psycopg2.Error: + pass return super(SassAsset, self).to_html() def get_source(self):