diff --git a/addons/account/partner.py b/addons/account/partner.py index 0107835ad6d..6166c28423c 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 = { diff --git a/addons/account/static/src/js/account_widgets.js b/addons/account/static/src/js/account_widgets.js index 136c571f495..4b826808457 100644 --- a/addons/account/static/src/js/account_widgets.js +++ b/addons/account/static/src/js/account_widgets.js @@ -47,7 +47,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 = {}; @@ -213,13 +212,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) { @@ -716,7 +708,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 @@ -1472,10 +1463,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_before_tax = (data.total.toFixed(3) === amount.toFixed(3) ? data.total : data.total_included); line_created_being_edited[0].amount = data.total diff --git a/addons/product/product_view.xml b/addons/product/product_view.xml index 0b01f805f1d..31e81052e77 100644 --- a/addons/product/product_view.xml +++ b/addons/product/product_view.xml @@ -218,6 +218,7 @@ {'search_default_product_tmpl_id': [active_id], 'default_product_tmpl_id': active_id} +

Click to define a new product. @@ -290,6 +291,9 @@

+ + [] +

diff --git a/addons/stock/stock.py b/addons/stock/stock.py index d68dbac1942..d4d762dbb99 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -582,7 +582,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: 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. diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index 96f351b9ee3..5b2a013aa05 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -983,11 +983,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): diff --git a/openerp/http.py b/openerp/http.py index e3c4039c1c8..439be25c4ff 100644 --- a/openerp/http.py +++ b/openerp/http.py @@ -272,7 +272,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 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)