From b25c054c93e7e5123fecf3e0e1165238c423e705 Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Wed, 23 Mar 2016 14:50:46 +0100 Subject: [PATCH 1/6] [FIX] web: prevent crash in rare case with status field Current behavior before PR: if you create a new record within a one2many field and the model's form has a clickable status bar defined, clicking this status bar will raise an exception because the virtual id (one2many_v_XXXX) will be passed to the model's write method Desired behavior after PR is merged: clicking just changes the cached value --- addons/web/static/src/js/view_form.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 9f89f729a58..72744618fa4 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -6145,13 +6145,20 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({ val = $li.data("id"); } if (val != self.get('value')) { - this.view.recursive_save().done(function() { - var change = {}; - change[self.name] = val; - self.view.dataset.write(self.view.datarecord.id, change).done(function() { - self.view.reload(); + if(!this.view.datarecord.id || + this.view.datarecord.id.toString().match(instance.web.BufferedDataSet.virtual_id_regex)) { + // don't save, only set value for not-yet-saved many2ones + self.set_value(val); + } + else { + this.view.recursive_save().done(function() { + var change = {}; + change[self.name] = val; + self.view.dataset.write(self.view.datarecord.id, change).done(function() { + self.view.reload(); + }); }); - }); + } } }, }); From 267097255e44ffb76f184838d8775195f8fd42f4 Mon Sep 17 00:00:00 2001 From: Joren Van Onder Date: Mon, 11 Apr 2016 14:55:15 +0200 Subject: [PATCH 2/6] [FIX] pos_restaurant: hide references to floor.background_image For some reason this made it into a stable release. Although you can set a background image on a floor this image never actually got displayed on the floor in the POS. Only the background_color field is respected. Something like this is always a bit tricky, because you would either have to scale the image to fit on the floor (ugly if the user uploads a low-res image or an image with the wrong aspect ratio), or you would have to tile the image (also ugly in most cases). Because of the above and because this has never worked and because I don't consider it a particularly useful feature we will remove it completely in master. opw-674031 --- addons/pos_restaurant/restaurant.py | 1 + addons/pos_restaurant/restaurant_view.xml | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/pos_restaurant/restaurant.py b/addons/pos_restaurant/restaurant.py index 512b1e7cdc3..730e88297c8 100644 --- a/addons/pos_restaurant/restaurant.py +++ b/addons/pos_restaurant/restaurant.py @@ -33,6 +33,7 @@ class restaurant_floor(osv.osv): _columns = { 'name': fields.char('Floor Name', required=True, help='An internal identification of the restaurant floor'), 'pos_config_id': fields.many2one('pos.config','Point of Sale'), + # todo: remove in master 'background_image': fields.binary('Background Image', help='A background image used to display a floor layout in the point of sale interface'), 'background_color': fields.char('Background Color', help='The background color of the floor layout, (must be specified in a html-compatible format)'), 'table_ids': fields.one2many('restaurant.table','floor_id','Tables', help='The list of tables in this floor'), diff --git a/addons/pos_restaurant/restaurant_view.xml b/addons/pos_restaurant/restaurant_view.xml index 27f323651b7..dda6e821562 100644 --- a/addons/pos_restaurant/restaurant_view.xml +++ b/addons/pos_restaurant/restaurant_view.xml @@ -28,7 +28,6 @@ - From 880e951f344cc1a4f96040b5e9e7d07936ac0d81 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Mon, 11 Apr 2016 17:10:55 +0200 Subject: [PATCH 3/6] [FIX] website_event_sale: get_unit_price with event ticket When the line is linked to an event ticket, the price must be taken on the ticket. Fixes #11521 opw:673176 --- addons/website_event_sale/controllers/main.py | 18 +++++++++++++++++- .../website_sale/static/src/js/website_sale.js | 3 ++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/addons/website_event_sale/controllers/main.py b/addons/website_event_sale/controllers/main.py index f57f0c8e175..1d7f4c65ddf 100644 --- a/addons/website_event_sale/controllers/main.py +++ b/addons/website_event_sale/controllers/main.py @@ -23,7 +23,7 @@ from openerp import SUPERUSER_ID from openerp.addons.web import http from openerp.addons.web.http import request from openerp.addons.website_event.controllers.main import website_event -from openerp.addons.website_sale.controllers.main import get_pricelist +from openerp.addons.website_sale.controllers.main import get_pricelist, website_sale from openerp.tools.translate import _ @@ -74,4 +74,20 @@ class website_event(website_event): return super(website_event, self)._add_event(event_name, context, **kwargs) +class website_sale(website_sale): + @http.route(['/shop/get_unit_price'], type='json', auth="public", methods=['POST'], website=True) + def get_unit_price(self, product_ids, add_qty, use_order_pricelist=False, **kw): + cr, uid, context, pool = request.cr, request.uid, request.context, request.registry + res_ticket = {} + if 'line_id' in kw: + line = pool['sale.order.line'].browse(cr, SUPERUSER_ID, kw['line_id']) + if line.event_ticket_id: + if line.order_id.pricelist_id: + ticket = pool['event.event.ticket'].browse(cr, SUPERUSER_ID, line.event_ticket_id.id, context=dict(context, pricelist=line.order_id.pricelist_id.id)) + else: + ticket = line.event_ticket_id + res_ticket = {ticket.product_id.id: ticket.price_reduce or ticket.price} + product_ids.remove(ticket.product_id.id) + res_options = super(website_sale, self).get_unit_price(product_ids, add_qty, use_order_pricelist, **kw) + return dict(res_ticket.items() + res_options.items()) diff --git a/addons/website_sale/static/src/js/website_sale.js b/addons/website_sale/static/src/js/website_sale.js index b72df30c67f..565e82b458b 100644 --- a/addons/website_sale/static/src/js/website_sale.js +++ b/addons/website_sale/static/src/js/website_sale.js @@ -69,7 +69,8 @@ $('.oe_website_sale').each(function () { openerp.jsonRpc("/shop/get_unit_price", 'call', { 'product_ids': product_ids, 'add_qty': value, - 'use_order_pricelist': true}) + 'use_order_pricelist': true, + 'line_id': line_id}) .then(function (res) { //basic case $dom.find('span.oe_currency_value').last().text(res[product_id].toFixed(2)); From 607ad5855e382cff76ebffd9f371fbdfc6a72608 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Tue, 12 Apr 2016 15:39:42 +0200 Subject: [PATCH 4/6] [FIX] stock: raise UserError when two inventory adjustments are in progress When two inventory adjustments are in progress state with a common product, raise a UserError instead of a Warning. opw:673686 --- 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 4059565680d..251d157dcc0 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -3002,7 +3002,7 @@ class stock_inventory_line(osv.osv): if res: location = self.pool['stock.location'].browse(cr, uid, values.get('location_id'), context=context) product = product_obj.browse(cr, uid, values.get('product_id'), context=context) - raise Warning(_("You cannot have two inventory adjustements in state 'in Progess' with the same product(%s), same location(%s), same package, same owner and same lot. Please first validate the first inventory adjustement with this product before creating another one.") % (product.name, location.name)) + raise UserError(_("You cannot have two inventory adjustements in state 'in Progess' with the same product(%s), same location(%s), same package, same owner and same lot. Please first validate the first inventory adjustement with this product before creating another one.") % (product.name, location.name)) if 'product_id' in values and not 'product_uom_id' in values: values['product_uom_id'] = product_obj.browse(cr, uid, values.get('product_id'), context=context).uom_id.id return super(stock_inventory_line, self).create(cr, uid, values, context=context) From ffdfadfc9148c679c9f82393703e4a3877edbf08 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Wed, 13 Apr 2016 14:34:45 +0200 Subject: [PATCH 5/6] [FIX] paypal: no spurious warning about IPN version In addition to being mostly useless because Paypal's API changes are supposed to be backwards-compatible, this warning was using inconsistent version numbers. Switched to a simple INFO line with IPN version. --- addons/payment_paypal/models/paypal.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/addons/payment_paypal/models/paypal.py b/addons/payment_paypal/models/paypal.py index 52c3ec768d4..fa9c4e7a660 100644 --- a/addons/payment_paypal/models/paypal.py +++ b/addons/payment_paypal/models/paypal.py @@ -203,11 +203,7 @@ class TxPaypal(osv.Model): def _paypal_form_get_invalid_parameters(self, cr, uid, tx, data, context=None): invalid_parameters = [] - if data.get('notify_version')[0] != '3.4': - _logger.warning( - 'Received a notification from Paypal with version %s instead of 2.6. This could lead to issues when managing it.' % - data.get('notify_version') - ) + _logger.info('Received a notification from Paypal with IPN version %s', data.get('notify_version')) if data.get('test_ipn'): _logger.warning( 'Received a notification from Paypal using sandbox' From 46c5f93b6cfa2b348078e674cd9e271ef5f81292 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Wed, 13 Apr 2016 12:51:20 +0200 Subject: [PATCH 6/6] [FIX] website_sale: verify match between TX and SO amount When processing a payment transaction, double-check the match between the amount of the transaction and the amount of the SO, to be sure that we won't be validating a SO that has been modified since the payment. Such cases have to be double-checked manually. Also add a bit of extra logging to make auditing ecommerce transactions easier. --- addons/website_sale/models/payment.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/addons/website_sale/models/payment.py b/addons/website_sale/models/payment.py index 6129de092aa..f38b9463d05 100644 --- a/addons/website_sale/models/payment.py +++ b/addons/website_sale/models/payment.py @@ -3,6 +3,7 @@ import logging from openerp import SUPERUSER_ID from openerp.osv import orm, fields +from openerp.tools import float_compare _logger = logging.getLogger(__name__) @@ -26,10 +27,20 @@ class PaymentTransaction(orm.Model): tx_find_method_name = '_%s_form_get_tx_from_data' % acquirer_name 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=dict(context, send_email=True)) - elif tx and tx.state not in ['cancel'] and tx.sale_order_id and tx.sale_order_id.state in ['draft']: - self.pool['sale.order'].force_quotation_send(cr, SUPERUSER_ID, [tx.sale_order_id.id], context=context) + _logger.info('<%s> transaction processed: tx ref:%s, tx amount: %s', acquirer_name, tx.reference if tx else 'n/a', tx.amount if tx else 'n/a') + + if tx and tx.sale_order_id: + # verify SO/TX match, excluding tx.fees which are currently not included in SO + amount_matches = (tx.sale_order_id.state in ['draft', 'sent'] and float_compare(tx.amount, tx.sale_order_id.amount_total, 2) == 0) + if amount_matches: + if tx.state == 'done': + _logger.info('<%s> transaction completed, confirming order %s (ID %s)', acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id) + self.pool['sale.order'].action_button_confirm(cr, SUPERUSER_ID, [tx.sale_order_id.id], context=dict(context, send_email=True)) + elif tx.state != 'cancel' and tx.sale_order_id.state == 'draft': + _logger.info('<%s> transaction pending, sending quote email for order %s (ID %s)', acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id) + self.pool['sale.order'].force_quotation_send(cr, SUPERUSER_ID, [tx.sale_order_id.id], context=context) + else: + _logger.warning('<%s> transaction MISMATCH for order %s (ID %s)', acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id) except Exception: _logger.exception('Fail to confirm the order or send the confirmation email%s', tx and ' for the transaction %s' % tx.reference or '')