From 3dec09079e9fc84c7b7b64cb7dabf7f2e1f9b797 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 17 Jul 2014 14:22:20 +0200 Subject: [PATCH 1/8] [FIX] ir_values: fallback when no condition When searching for default values, if we set a condition (e.g. 'type=out_invoice'), fetch also the default values without any condition set. Thanks to the order by clause, the one with a condition have an higher priority than the one without and will not affect existing result. This fixes default journal/currency on an invoice where the journal is retrieved in the onchange_company_id method (domain is forced). Without this patch only ir.values with a domain set will match, opw 610645 --- openerp/addons/base/ir/ir_values.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/ir/ir_values.py b/openerp/addons/base/ir/ir_values.py index bf0128dffd6..953d1aad0d4 100644 --- a/openerp/addons/base/ir/ir_values.py +++ b/openerp/addons/base/ir/ir_values.py @@ -310,10 +310,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' From ed58bcf26b311f1bfd720f03384e942af5c27a49 Mon Sep 17 00:00:00 2001 From: TheCloneMaster Date: Thu, 17 Jul 2014 23:58:44 -0600 Subject: [PATCH 2/8] [FIX] hr_timesheet: missing '&' in domain clause To search the contracts for payroll, the domain is constructed with three clauses. Each of these clauses needs to start with a '&' to make sure they are correctly combined with the OR clause' --- addons/hr_payroll/hr_payroll.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/hr_payroll/hr_payroll.py b/addons/hr_payroll/hr_payroll.py index 67fb89ebcf5..90cf53775c5 100644 --- a/addons/hr_payroll/hr_payroll.py +++ b/addons/hr_payroll/hr_payroll.py @@ -386,7 +386,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 From 738270557febbac6a318bc1da8c4a06c1585f929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9rome=20Maes?= Date: Fri, 18 Jul 2014 13:02:07 +0200 Subject: [PATCH 3/8] [FIX] crm : propagate the lead_id when scheldule other phone calls --- addons/crm/crm_phonecall.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/crm/crm_phonecall.py b/addons/crm/crm_phonecall.py index 22582f3132f..3ad024623b3 100644 --- a/addons/crm/crm_phonecall.py +++ b/addons/crm/crm_phonecall.py @@ -134,6 +134,7 @@ class crm_phonecall(base_state, 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': From 22bbfdaab137dea7e4bfcca312a5972983eeb1df Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Fri, 18 Jul 2014 13:56:42 +0200 Subject: [PATCH 4/8] [FIX] procurement: avoid to run multiple scheduler Avoid to run the procurement scheduler multiple times in the same time, otherwise, they tend to interfere with each others --- addons/procurement/wizard/schedulers_all.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/addons/procurement/wizard/schedulers_all.py b/addons/procurement/wizard/schedulers_all.py index 9311ffcd11d..b6eeded7e93 100644 --- a/addons/procurement/wizard/schedulers_all.py +++ b/addons/procurement/wizard/schedulers_all.py @@ -19,11 +19,14 @@ # ############################################################################## +import logging import threading -from openerp import pooler +from openerp import pooler, SUPERUSER_ID, tools from openerp.osv import fields, osv +_logger = logging.getLogger(__name__) + class procurement_compute_all(osv.osv_memory): _name = 'procurement.order.compute.all' _description = 'Compute all schedulers' @@ -47,6 +50,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 = pooler.get_db(cr.dbname).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 {} for proc in self.browse(new_cr, uid, ids, context=context): proc_obj.run_scheduler(new_cr, uid, automatic=proc.automatic, use_new_cursor=new_cr.dbname,\ context=context) From c58bf1e3bc40db83e0a922081008f6189e2bd2d4 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Wed, 4 Jun 2014 16:33:58 +0200 Subject: [PATCH 5/8] [FIX] account: better error message when regenarating opening entries (opw 606923) If we try to generate twice entries on the same fiscal year, we can get completly unrelated errors ("You can only reconcile journal items with the same partner"). With this, we make sure people will first cancel the entries before regeneraing the entries. --- addons/account/account_move_line.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py index a7fd2adf33e..bdc1941238d 100644 --- a/addons/account/account_move_line.py +++ b/addons/account/account_move_line.py @@ -1030,6 +1030,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: From ae678d9e05a131b2461b4b4498647f3f99d5d9cc Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Fri, 18 Jul 2014 17:26:48 +0200 Subject: [PATCH 6/8] [FIX] sale: only propose services for pay advances When creating an invoice from a sale order, if the user choose to invoice a fixed price (deposit), he has the possibility to choose an advance product. As described in the help message, this product should be a service product. Therefore, we add a domain so only services are displayed in the dropdown list --- addons/sale/wizard/sale_make_invoice_advance.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/sale/wizard/sale_make_invoice_advance.py b/addons/sale/wizard/sale_make_invoice_advance.py index c35b1a78635..9c3160cb46a 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'), From 8320f01fefa498d1c9f50d111a37b506e238ccdc Mon Sep 17 00:00:00 2001 From: Dhs-odoo Date: Mon, 14 Jul 2014 15:23:39 +0530 Subject: [PATCH 7/8] [FIX] project : do not show canceled projects in task fixes #938, opw 610318 --- addons/project/project_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index 7d14f923847..04d5c0fb104 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -376,7 +376,7 @@ - + Date: Wed, 28 May 2014 16:01:47 +0200 Subject: [PATCH 8/8] [FIX] web: reload after wizard when record has been removed cause exception If an action unlink the current records (e.g. unreconcile on account.move.reconcile), trigger history_back to avoid errors when trying to reload inexistant record (opw 607883) This is a partial backport of saas-4 code (rev c0db6ae, 162ad1c) and should not be forward ported. --- addons/web/static/src/js/chrome.js | 10 ++++------ addons/web/static/src/js/view_form.js | 16 ++++++++++++---- addons/web/static/src/js/view_list.js | 9 +++++---- addons/web/static/src/js/views.js | 8 ++++---- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index 8fb13aae746..9d69b908f4d 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -101,9 +101,6 @@ instance.web.Dialog = instance.web.Widget.extend({ autoOpen: false, position: [false, 40], buttons: null, - beforeClose: function () { - self.trigger("closing"); - }, resizeStop: function() { self.trigger("resized"); }, @@ -204,8 +201,9 @@ instance.web.Dialog = instance.web.Widget.extend({ /** Closes the popup, if destroy_on_close was passed to the constructor, it is also destroyed. */ - close: function() { + close: function(reason) { if (this.dialog_inited && this.$el.is(":data(dialog)")) { + this.trigger("closing", reason); this.$el.dialog('close'); } }, @@ -221,14 +219,14 @@ instance.web.Dialog = instance.web.Widget.extend({ /** Destroys the popup, also closes it. */ - destroy: function () { + destroy: function (reason) { this.$buttons.remove(); _.each(this.getChildren(), function(el) { el.destroy(); }); if (! this.__tmp_dialog_closing) { this.__tmp_dialog_destroying = true; - this.close(); + this.close(reason); this.__tmp_dialog_destroying = undefined; } if (this.dialog_inited && !this.isDestroyed() && this.$el.is(":data(dialog)")) { diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 2f3d5593bb4..790fa88caa5 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -957,14 +957,20 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM } else { var fields = _.keys(self.fields_view.fields); fields.push('display_name'); - return self.dataset.read_index(fields, + // Use of search_read instead of read to check if we can still read the record (security rules) + return self.dataset.call('search_read', [[['id', '=', self.dataset.ids[self.dataset.index]]], fields], { context: { 'bin_size': true, 'future_display_name': true } }).then(function(r) { - self.trigger('load_record', r); + if (_.isEmpty(r)){ + self.do_action('history_back'); + } + else{ + self.trigger('load_record', r[0]); + } }); } }); @@ -1972,8 +1978,10 @@ instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({ return this.view.do_execute_action( _.extend({}, this.node.attrs, {context: context}), - this.view.dataset, this.view.datarecord.id, function () { - self.view.recursive_reload(); + this.view.dataset, this.view.datarecord.id, function (reason) { + if (!_.isObject(reason)) { + self.view.recursive_reload(); + } }); }, check_disable: function() { diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index 3dad5b2e667..9d4c781b785 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -528,13 +528,14 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi }, reload_record: function (record) { var self = this; - return this.dataset.read_ids( - [record.get('id')], + // Use of search_read instead of read to check if we can still read the record (security rules) + return this.dataset.call('search_read', [ + [['id', '=', record.get('id')]], _.pluck(_(this.columns).filter(function (r) { return r.tag === 'field'; - }), 'name') + }), 'name')] ).done(function (records) { - var values = records[0]; + var values = _.isEmpty(records) ? undefined : records[0]; if (!values) { self.records.remove(record); return; diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index df02686f8e5..7677ddfb9f5 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -22,9 +22,9 @@ instance.web.ActionManager = instance.web.Widget.extend({ this._super.apply(this, arguments); this.$el.on('click', 'a.oe_breadcrumb_item', this.on_breadcrumb_clicked); }, - dialog_stop: function () { + dialog_stop: function (reason) { if (this.dialog) { - this.dialog.destroy(); + this.dialog.destroy(reason); } this.dialog = null; }, @@ -376,7 +376,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ if (this.dialog_widget && !this.dialog_widget.isDestroyed()) { this.dialog_widget.destroy(); } - this.dialog_stop(); + this.dialog_stop(executor.action); this.dialog = new instance.web.Dialog(this, { dialogClass: executor.klass, }); @@ -394,7 +394,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ this.dialog.open(); return initialized; } else { - this.dialog_stop(); + this.dialog_stop(executor.action); this.inner_action = executor.action; this.inner_widget = widget; executor.post_process(widget);