From fca83b45f8f5011767e11dc8f654c98d4228cf31 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 23 Jan 2015 15:34:53 +0100 Subject: [PATCH 1/9] [IMP] on non-rpc debug, only break on non-HTTPException Completes/improves fd6dde7ca Because Werkzeug uses/provides flow-control exceptions via HTTPException (which can be used as straight responses) they are used in a few places of the web client, when triggering some redirections for instance. Breaking into the debugger for such mundane situations is surprising and inconvenient for developers trying to debug actual issues in the system, even though HTTPExceptions are by and large not error per-se, and shouldn't warrant triggering post-mortem debugging. So in the non-RPC dispatcher, don't post-mortem on HTTPException either. --- openerp/http.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openerp/http.py b/openerp/http.py index 6ee9aefe87b..1d35c989143 100644 --- a/openerp/http.py +++ b/openerp/http.py @@ -270,7 +270,8 @@ class WebRequest(object): to abitrary responses. Anything returned (except None) will be used as response.""" self._failed = exception # prevent tx commit - if not isinstance(exception, NO_POSTMORTEM): + if not isinstance(exception, NO_POSTMORTEM) \ + and not isinstance(exception, werkzeug.exceptions.HTTPException): openerp.tools.debugger.post_mortem( openerp.tools.config, sys.exc_info()) raise From eed09ba4105ae8f47a37c5071217cea2ef2e153e Mon Sep 17 00:00:00 2001 From: Arthur Maniet Date: Fri, 23 Jan 2015 22:46:46 +0100 Subject: [PATCH 2/9] [FIX] account: reconciliation widget was not assigning an amount on writeoffs lines when a tax with amount == 0 was applied. This undefined amount was interpreted as 0, resulting in tragically unbalanced journal entries. Fixes #4871 --- addons/account/static/src/js/account_widgets.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/addons/account/static/src/js/account_widgets.js b/addons/account/static/src/js/account_widgets.js index cd150cca6ae..7e8fda63b2d 100644 --- a/addons/account/static/src/js/account_widgets.js +++ b/addons/account/static/src/js/account_widgets.js @@ -44,7 +44,6 @@ openerp.account = function (instance) { this.animation_speed = 100; // "Blocking" animations this.aestetic_animation_speed = 300; // eye candy this.map_currency_id_rounding = {}; - this.map_tax_id_amount = {}; this.presets = {}; // We'll need to get the code of an account selected in a many2one (whose value is the id) this.map_account_id_code = {}; @@ -210,13 +209,6 @@ openerp.account = function (instance) { _.each(data, function(o) { self.map_currency_id_rounding[o.id] = o.rounding }); }); - // Create a dict tax id -> amount - new instance.web.Model("account.tax") - .query(['id', 'amount']) - .all().then(function(data) { - _.each(data, function(o) { self.map_tax_id_amount[o.id] = o.amount }); - }); - new instance.web.Model("ir.model.data") .call("xmlid_to_res_id", ["account.menu_bank_reconcile_bank_statements"]) .then(function(data) { @@ -689,7 +681,6 @@ openerp.account = function (instance) { this.model_tax = new instance.web.Model("account.tax"); this.map_currency_id_rounding = this.getParent().map_currency_id_rounding; this.map_account_id_code = this.getParent().map_account_id_code; - this.map_tax_id_amount = this.getParent().map_tax_id_amount; this.presets = this.getParent().presets; this.is_valid = true; this.is_consistent = true; // Used to prevent bad server requests @@ -1438,10 +1429,10 @@ openerp.account = function (instance) { var deferred_tax = new $.Deferred(); if (elt === self.tax_id_field || elt === self.amount_field) { var amount = self.amount_field.get("value"); - var tax = self.map_tax_id_amount[self.tax_id_field.get("value")]; - if (amount && tax) { + var tax_id = self.tax_id_field.get("value"); + if (amount && tax_id) { deferred_tax = $.when(self.model_tax - .call("compute_for_bank_reconciliation", [self.tax_id_field.get("value"), amount])) + .call("compute_for_bank_reconciliation", [tax_id, amount])) .then(function(data){ line_created_being_edited[0].amount_with_tax = line_created_being_edited[0].amount; line_created_being_edited[0].amount = (data.total.toFixed(3) === amount.toFixed(3) ? amount : data.total); From a3c369f53fe934b150ec73373c83a8c2f76bfa78 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 23 Jan 2015 23:23:27 +0100 Subject: [PATCH 3/9] [FIX] product: force empty domain for variants action Takes care of resetting it from older versions e.g. rev d97e7a6a4eaa9e003b48f2522d354669024bc25f and c0076916f31a47a12de6d2de3b524c698ee893bb, as the old `variants` field that was used does not exist anymore, crashing at opening. --- addons/product/product_view.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/product/product_view.xml b/addons/product/product_view.xml index fc6a451329e..0169b392032 100644 --- a/addons/product/product_view.xml +++ b/addons/product/product_view.xml @@ -216,6 +216,7 @@ {'search_default_product_tmpl_id': [active_id], 'default_product_tmpl_id': active_id} +

Click to define a new product. From 740bf28907d97db8dbc8628e4746e1d17d8a95b9 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Sat, 24 Jan 2015 00:15:22 +0100 Subject: [PATCH 4/9] [FIX] ir.model.data: verify record exists in _update_dummy When a stale XML ID exists in the database, `_update_dummy()` must consider it as missing entirely, and the next call to `_update()` will take care of cleaning up the old XML ID. Failing to do so for `noupdate` records means the `_update` will never happen, and as soon as another record is created or updated with a relationship to that stale XML ID, it will plainly crash the installation/update. --- openerp/addons/base/ir/ir_model.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index 579178c36cb..abd43777155 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -985,11 +985,15 @@ class ir_model_data(osv.osv): def _update_dummy(self,cr, uid, model, module, xml_id=False, store=True): if not xml_id: return False + id = False try: - id = self.read(cr, uid, [self._get_id(cr, uid, module, xml_id)], ['res_id'])[0]['res_id'] - self.loads[(module,xml_id)] = (model,id) - except: - id = False + # One step to check the ID is defined and the record actually exists + record = self.get_object(cr, uid, module, xml_id) + if record: + id = record.id + self.loads[(module,xml_id)] = (model,id) + except Exception: + pass return id def clear_caches(self): From 25b1df2eb331275ab6bb5e572665492bbff15bdc Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Sat, 24 Jan 2015 04:25:51 +0100 Subject: [PATCH 5/9] [FIX] product: better expose default_code on product.template For companies not working with variants, it is important to be able to search in the Products menu (product.template) using product codes. It is useful as well to see the codes in the default kanban view too, even if it is only the code of the first variant. --- addons/product/product_view.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/product/product_view.xml b/addons/product/product_view.xml index 0169b392032..e66040d10ad 100644 --- a/addons/product/product_view.xml +++ b/addons/product/product_view.xml @@ -10,7 +10,7 @@ product.template - + @@ -150,9 +150,6 @@ primary - - - @@ -284,6 +281,9 @@

+ + [] +

From 9b749d4d795200ee6d21da965b45617f7f0daa7c Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Mon, 26 Jan 2015 10:12:21 +0100 Subject: [PATCH 6/9] [FIX] Propagate of propagate_from on quants should be done with superuser (courtesy of Jos De Graeve) --- addons/stock/stock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index a9a56e7b4b2..695d76e6df4 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -578,7 +578,7 @@ class stock_quant(osv.osv): if remaining_to_solve_quant_ids: self.write(cr, SUPERUSER_ID, remaining_to_solve_quant_ids, {'propagated_from_id': remaining_neg_quant.id}, context=context) if solving_quant.propagated_from_id and solved_quant_ids: - self.write(cr, uid, solved_quant_ids, {'propagated_from_id': solving_quant.propagated_from_id.id}, context=context) + self.write(cr, SUPERUSER_ID, solved_quant_ids, {'propagated_from_id': solving_quant.propagated_from_id.id}, context=context) #delete the reconciled quants, as it is replaced by the solved quants self.unlink(cr, SUPERUSER_ID, [quant_neg.id], context=context) if solved_quant_ids: From 6ebdcbd2cdf64257d163d69caaeb20c176a2c823 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Mon, 26 Jan 2015 11:21:28 +0100 Subject: [PATCH 7/9] [FIX] account: misleading labels/tooltips on new fiscal position fields --- addons/account/partner.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/account/partner.py b/addons/account/partner.py index c0a1a695e0c..e23a2436c72 100644 --- a/addons/account/partner.py +++ b/addons/account/partner.py @@ -37,10 +37,10 @@ class account_fiscal_position(osv.osv): 'account_ids': fields.one2many('account.fiscal.position.account', 'position_id', 'Account Mapping', copy=True), 'tax_ids': fields.one2many('account.fiscal.position.tax', 'position_id', 'Tax Mapping', copy=True), 'note': fields.text('Notes'), - 'auto_apply': fields.boolean('Automatic', help="Apply automatically this fiscal position."), + 'auto_apply': fields.boolean('Automatic', help="Apply automatically this fiscal position if the conditions match."), 'vat_required': fields.boolean('VAT required', help="Apply only if partner has a VAT number."), - 'country_id': fields.many2one('res.country', 'Countries', help="Apply only if delivery or invoicing country match."), - 'country_group_id': fields.many2one('res.country.group', 'Country Group', help="Apply only if delivery or invocing country match the group."), + 'country_id': fields.many2one('res.country', 'Country', help="Apply when the shipping or invoicing country matches. Takes precedence over positions matching on a country group."), + 'country_group_id': fields.many2one('res.country.group', 'Country Group', help="Apply when the shipping or invoicing country is in this country group, and no position matches the country directly."), } _defaults = { From 1db27f417d20b92e6c390550dbe8365dfd7968f0 Mon Sep 17 00:00:00 2001 From: Aaron Bohy Date: Mon, 26 Jan 2015 10:44:05 +0100 Subject: [PATCH 8/9] [FIX] Packaging: Windows: _prepare_build_dir Catch shutil.Error thrown when addons have already been moved to openerp/addons. Fixes the bug introduced by commit 91026647d43358594df0e17f3d408a3aa415c665. --- setup/package.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/setup/package.py b/setup/package.py index 9ca97d19dd9..71de37bbf99 100755 --- a/setup/package.py +++ b/setup/package.py @@ -246,9 +246,14 @@ def _prepare_build_dir(o, win32=False): if not win32: cmd += ['--exclude', 'setup/win32'] system(cmd + ['%s/' % o.odoo_dir, o.build_dir]) - for i in glob(join(o.build_dir, 'addons/*')): - if i.split(os.path.sep)[-1] not in ADDONS_NOT_TO_PUBLISH: - shutil.move(i, join(o.build_dir, 'openerp/addons')) + try: + for addon_path in glob(join(o.build_dir, 'addons/*')): + if addon_path.split(os.path.sep)[-1] not in ADDONS_NOT_TO_PUBLISH: + shutil.move(addon_path, join(o.build_dir, 'openerp/addons')) + except shutil.Error: + # Thrown when the add-on is already in openerp/addons (if _prepare_build_dir + # has already been called once) + pass def build_tgz(o): system(['python2', 'setup.py', 'sdist', '--quiet', '--formats=gztar,zip'], o.build_dir) From 4e6251581905d74fd3f48a538c259f8a3425d2de Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 26 Jan 2015 15:31:53 +0100 Subject: [PATCH 9/9] [IMP] doc: old/new API clarifications --- doc/reference/orm.rst | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/doc/reference/orm.rst b/doc/reference/orm.rst index 474f0eee895..6b609e52287 100644 --- a/doc/reference/orm.rst +++ b/doc/reference/orm.rst @@ -1,14 +1,19 @@ .. _reference/orm: -=== -ORM -=== +======= +ORM API +======= Recordsets ========== .. versionadded:: 8.0 + This page documents the New API added in Odoo 8.0 which should be the + primary development API going forward. It also provides information about + porting from or bridging with the "old API" of versions 7 and earlier, but + does not explicitly document that API. See the old documentation for that. + Interaction with models and records is performed through recordsets, a sorted set of records of the same model. @@ -444,8 +449,8 @@ Clearing caches can be performed using the .. _reference/orm/oldapi: -Old API compatibility -===================== +Compatibility between new API and old API +========================================= Odoo is currently transitioning from an older (less regular) API, it can be necessary to manually bridge from one to the other manually: @@ -1026,9 +1031,10 @@ Domain criteria can be combined using logical operators in *prefix* form: AND (language is NOT english) AND (country is Belgium OR Germany) -Porting from the old API -======================== +Porting from the old API to the new API +======================================= +* bare lists of ids are to be avoided in the new API, use recordsets instead * methods still written in the old API should be automatically bridged by the ORM, no need to switch to the old API, just call them as if they were a new API method. See :ref:`reference/orm/oldapi/bridging` for more details.