From 3dec09079e9fc84c7b7b64cb7dabf7f2e1f9b797 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 17 Jul 2014 14:22:20 +0200 Subject: [PATCH 01/11] [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 f9170a04fba1fecd27f89ce67d556836de42fa4a Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 17 Jul 2014 16:09:52 +0200 Subject: [PATCH 02/11] [FIX] website_sale: make the 'Ship to a different address' always available In the backend the option 'Allow a different address for delivery and invoicing' will set the group sale.group_delivery_invoice_address to employees. However the public user is not an employee (and we don't want to change that) so does not get this group. As we don't have similar group mechanism for public user, we have no other choice than always displaying the option to have different address. opw 610118 --- addons/website_sale/views/website_sale.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/website_sale/views/website_sale.xml b/addons/website_sale/views/website_sale.xml index 3a3979c12aa..f68a08fc852 100644 --- a/addons/website_sale/views/website_sale.xml +++ b/addons/website_sale/views/website_sale.xml @@ -791,14 +791,14 @@
-
+
-
+

Shipping Information

@@ -942,7 +942,7 @@ - +

Ship To:

- +

Ship To:

=', 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 04/11] [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 05/11] [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 06/11] [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 07/11] [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 08/11] [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 09/11] [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); From 586b0e2f5d84a373c9a7e703a49af460a0def069 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Wed, 23 Jul 2014 08:56:36 +0200 Subject: [PATCH 10/11] [FIX] website_sale: _rec_name product.attribute.line Set the _rec_name for product.attribute.line model, as its column name wasn't defined, and therefore search on it wasn't possible (For instance, do an advanced search on product.product with "Product Attributes" "Contains" "Something" wasn't possible). --- addons/website_sale/models/product_characteristics.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/website_sale/models/product_characteristics.py b/addons/website_sale/models/product_characteristics.py index ae641184db3..84eebdcd73b 100644 --- a/addons/website_sale/models/product_characteristics.py +++ b/addons/website_sale/models/product_characteristics.py @@ -66,6 +66,7 @@ class attributes_value(osv.Model): class attributes_product(osv.Model): _name = "product.attribute.line" _order = 'attribute_id, value_id, value' + _rec_name = 'attribute_id' _columns = { 'value': fields.float('Numeric Value'), 'value_id': fields.many2one('product.attribute.value', 'Textual Value'), From 474eae9a43ad7860f11f1d3c1cb8c587eeb98412 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Wed, 23 Jul 2014 12:00:09 +0200 Subject: [PATCH 11/11] [FIX] website_sale: translated terms payment status Payment status (website_sale confirmation page) inject a status message, which was not set to be translatable. It should be the case. --- addons/website_sale/controllers/main.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index 5d888714b19..1871dd64e02 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -685,7 +685,7 @@ class Ecommerce(http.Controller): if not order: return { 'state': 'error', - 'message': '

There seems to be an error with your request.

', + 'message': '

%s

' % _('There seems to be an error with your request.'), } tx_ids = request.registry['payment.transaction'].search( @@ -697,7 +697,7 @@ class Ecommerce(http.Controller): if order.amount_total: return { 'state': 'error', - 'message': '

There seems to be an error with your request.

', + 'message': '

%s

' % _('There seems to be an error with your request.'), } else: state = 'done' @@ -707,14 +707,14 @@ class Ecommerce(http.Controller): tx = request.registry['payment.transaction'].browse(cr, uid, tx_ids[0], context=context) state = tx.state if state == 'done': - message = '

Your payment has been received.

' + message = '

%s

' % _('Your payment has been received.') elif state == 'cancel': - message = '

The payment seems to have been canceled.

' + message = '

%s

' % _('The payment seems to have been canceled.') elif state == 'pending' and tx.acquirer_id.validation == 'manual': - message = '

Your transaction is waiting confirmation.

' + message = '

%s

' % _('Your transaction is waiting confirmation.') message += tx.acquirer_id.post_msg else: - message = '

Your transaction is waiting confirmation.

' + message = '

%s

' % _('Your transaction is waiting confirmation.') validation = tx.acquirer_id.validation return {