From b25c054c93e7e5123fecf3e0e1165238c423e705 Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Wed, 23 Mar 2016 14:50:46 +0100 Subject: [PATCH 001/140] [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 002/140] [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 003/140] [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 f40e9ecfc30ba93a2b931a485565660f819436ad Mon Sep 17 00:00:00 2001 From: Joren Van Onder Date: Wed, 6 Apr 2016 15:24:30 +0200 Subject: [PATCH 004/140] [FIX] point_of_sale: match payment to order amount when invoicing The POS generates journal entries for both the amount of money the customer pays and the amount of money the POS user returns to the customer (the 'change'). Whether or not this is the correct thing to do is up for debate, but we can't change that in stable anyway. One of the main issues is that in 9.0 accounting will propose unreconciled payments belonging to the customer on open, unpaid invoices. This does not work well with the account entries generated by the POS. Accounting will propose the amount the customer paid, without taking into account the change. Example: a customer buys $7 worth of products and pays with a $10 bill. The customer gets $3 change. The invoice will propose the $10 payment. When you add that payment to the invoice a residual amount ($3 in the example) will remain on the paymentline, complicating everything even more. Although we cannot change how the POS does accounting in a stable release, we at least want people to be able to easily handle invoices generated through the POS. To achieve that this patch will make the backend match the payment to the total amount of the invoice removing any potential change. opw-671486 --- addons/point_of_sale/point_of_sale.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/addons/point_of_sale/point_of_sale.py b/addons/point_of_sale/point_of_sale.py index 2115fdd5249..5d0b3526740 100644 --- a/addons/point_of_sale/point_of_sale.py +++ b/addons/point_of_sale/point_of_sale.py @@ -701,6 +701,23 @@ class pos_order(osv.osv): return new_session_id + def _match_payment_to_invoice(self, cr, uid, order, context=None): + account_precision = self.pool.get('decimal.precision').precision_get(cr, uid, 'Account') + + # ignore orders with an amount_paid of 0 because those are returns through the POS + if not float_is_zero(order['amount_return'], account_precision) and not float_is_zero(order['amount_paid'], account_precision): + cur_amount_paid = 0 + payments_to_keep = [] + for payment in order.get('statement_ids'): + if cur_amount_paid + payment[2]['amount'] > order['amount_total']: + payment[2]['amount'] = order['amount_total'] - cur_amount_paid + payments_to_keep.append(payment) + break + cur_amount_paid += payment[2]['amount'] + payments_to_keep.append(payment) + order['statement_ids'] = payments_to_keep + order['amount_return'] = 0 + def _process_order(self, cr, uid, order, context=None): session = self.pool.get('pos.session').browse(cr, uid, order['pos_session_id'], context=context) @@ -757,6 +774,10 @@ class pos_order(osv.osv): for tmp_order in orders_to_save: to_invoice = tmp_order['to_invoice'] order = tmp_order['data'] + + if to_invoice: + self._match_payment_to_invoice(cr, uid, order, context=context) + order_id = self._process_order(cr, uid, order, context=context) order_ids.append(order_id) From 1174cd3fd5c432d212d57fc6623dcd8c34d33de0 Mon Sep 17 00:00:00 2001 From: Yenthe Date: Mon, 11 Apr 2016 09:08:32 +0200 Subject: [PATCH 005/140] [FIX] doc: Improve english Some rephrasing to slightly improve the docs. Closes #11652 --- doc/reference/guidelines.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/reference/guidelines.rst b/doc/reference/guidelines.rst index 17e50fe89ae..51bff7936ba 100644 --- a/doc/reference/guidelines.rst +++ b/doc/reference/guidelines.rst @@ -16,7 +16,7 @@ Module structure Directories ----------- -A module is organised in a few directory : +A module is organised in a few directories : - *data/* : demo and data xml - *models/* : models definition @@ -266,7 +266,7 @@ Inside these 3 groups, the imported lines are alphabetically sorted. Idioms ------ -- Prefer ``%`` over ``.format()``, prefer ``%(varname)`` instead of position (This is better for translation) +- Prefer ``%`` over ``.format()``, prefer ``%(varname)`` instead of position (This is better for translations) - Try to avoid generators and decorators - Always favor *Readability* over *conciseness* or using the language features or idioms. - Use list comprehension, dict comprehension, and basic manipulation using ``map``, ``filter``, ``sum``, ... They make the code easier to read. From 607ad5855e382cff76ebffd9f371fbdfc6a72608 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Tue, 12 Apr 2016 15:39:42 +0200 Subject: [PATCH 006/140] [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 30febb1c978db403540a716e9fe63b2b35d66cec Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 12 Apr 2016 16:13:15 +0200 Subject: [PATCH 007/140] [IMP] modules loading: pipe down INFO while loading a7c1f371974f1295d0640d4d82d727aa878ae37b was a bit on the noisy side --- openerp/modules/loading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/modules/loading.py b/openerp/modules/loading.py index 017fd411ea1..5824993aeb5 100644 --- a/openerp/modules/loading.py +++ b/openerp/modules/loading.py @@ -120,7 +120,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules= if skip_modules and module_name in skip_modules: continue - _logger.info('loading module %s (%d/%d)', module_name, index, module_count) + _logger.debug('loading module %s (%d/%d)', module_name, index, module_count) migrations.migrate_module(package, 'pre') load_openerp_module(package.name) From 10e1d45db992b51d0973180f954eabfdd9ff3fa2 Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Tue, 12 Apr 2016 18:11:04 +0200 Subject: [PATCH 008/140] [FIX] crm: date_closed When a lead is set to 'Won', the date_closed is defined. However, the user might have clicked by mistake, and he might want to change the state back. We need to take this into account, otherwise the lead is considered as closed although it is not. opw-674226 --- addons/crm/crm_lead.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 43d0b18b0c7..711292eb4e3 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -906,6 +906,8 @@ class crm_lead(format_address, osv.osv): vals.update(onchange_stage_values) if vals.get('probability') >= 100 or not vals.get('active', True): vals['date_closed'] = fields.datetime.now() + elif vals.get('probability') < 100: + vals['date_closed'] = False return super(crm_lead, self).write(cr, uid, ids, vals, context=context) def copy(self, cr, uid, id, default=None, context=None): From 534ff9dd8c2d5ac16163b93ece18f9798ad98e48 Mon Sep 17 00:00:00 2001 From: Joren Van Onder Date: Wed, 13 Apr 2016 08:50:23 +0200 Subject: [PATCH 009/140] [FIX] point_of_sale: hide non-active pos.configs from dashboard The introduction of the new pos.config dashboard at 48ab50ed0d668537cfd1bb97fb45c862ed7dc93c does not filter non-active pos.configs. There are no constraints against opening sessions on inactive or deprecated pos.configs so after deprecating/inactivating users could still open new sessions through the dashboard. opw-673020 --- addons/point_of_sale/point_of_sale_view.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/point_of_sale/point_of_sale_view.xml b/addons/point_of_sale/point_of_sale_view.xml index b54c1892c13..5720fac7c6c 100644 --- a/addons/point_of_sale/point_of_sale_view.xml +++ b/addons/point_of_sale/point_of_sale_view.xml @@ -979,6 +979,7 @@ form kanban,tree,form + [('state','=','active')]

Click to create a new PoS config. From 48e79865aadedd4b7d2d369227cb7f83dd41552f Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Tue, 12 Apr 2016 14:46:05 +0200 Subject: [PATCH 010/140] [FIX] product: sale price in report productlabel The price displayed in product label report musr be the sale price opw:673086 --- addons/product/views/report_productlabel.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/product/views/report_productlabel.xml b/addons/product/views/report_productlabel.xml index 8bc9db97a6a..4065cbcfcde 100644 --- a/addons/product/views/report_productlabel.xml +++ b/addons/product/views/report_productlabel.xml @@ -13,7 +13,7 @@ - + From 383074881dfc215a40fa28e5aab62581c397d60e Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Tue, 12 Apr 2016 13:56:56 +0200 Subject: [PATCH 011/140] [FIX] purchase: Incoming Shipments to Invoice filter The invoicing method to create an invoice on incoming shipment has been removed in 9.0 opw:674323 --- addons/purchase/stock_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/purchase/stock_view.xml b/addons/purchase/stock_view.xml index 6f4f09497ae..e050c45ca76 100644 --- a/addons/purchase/stock_view.xml +++ b/addons/purchase/stock_view.xml @@ -18,7 +18,7 @@ - + From f8d38821730f9c8a379f7710c6c393432162d277 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Tue, 12 Apr 2016 16:56:38 +0200 Subject: [PATCH 012/140] [FIX] website_quote: _onchange_product_uom on_change_product_id and product_uom_change have been removed in the sale.quote.option views. --- addons/website_quote/models/order.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/addons/website_quote/models/order.py b/addons/website_quote/models/order.py index 2c3825a598f..8af74a76149 100644 --- a/addons/website_quote/models/order.py +++ b/addons/website_quote/models/order.py @@ -340,6 +340,17 @@ class sale_quote_option(osv.osv): domain = {'uom_id': [('category_id', '=', self.product_id.uom_id.category_id.id)]} return {'domain': domain} + @api.onchange('uom_id') + def _onchange_product_uom(self): + if not self.product_id: + return + if not self.uom_id: + self.price_unit = 0.0 + return + if self.uom_id.id != self.product_id.uom_id.id: + new_price = self.product_id.uom_id._compute_price(self.product_id.uom_id.id, self.price_unit, self.uom_id.id) + self.price_unit = new_price + def on_change_product_id(self, cr, uid, ids, product, uom_id=None, context=None): vals, domain = {}, [] product_obj = self.pool.get('product.product').browse(cr, uid, product, context=context) From 5c052451afd4d2555fa9b1ef11d420e235cdb799 Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Wed, 13 Apr 2016 12:18:34 +0200 Subject: [PATCH 013/140] [FIX] crm: traceback due to typo opw-674520 --- addons/crm/report/crm_opportunity_report.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/crm/report/crm_opportunity_report.py b/addons/crm/report/crm_opportunity_report.py index b612d3ad349..4427e254d40 100644 --- a/addons/crm/report/crm_opportunity_report.py +++ b/addons/crm/report/crm_opportunity_report.py @@ -70,7 +70,7 @@ class crm_opportunity_report(osv.Model): c.team_id, (SELECT COUNT(*) FROM mail_message m - WHERE m.model = 'crm.lead' and m.res_id = c.id) as nbr_activity, + WHERE m.model = 'crm.lead' and m.res_id = c.id) as nbr_activities, c.active, c.campaign_id, c.source_id, From b03921cbca572204c27f022ddff8ae31f5652541 Mon Sep 17 00:00:00 2001 From: qsm-odoo Date: Wed, 13 Apr 2016 12:57:26 +0200 Subject: [PATCH 014/140] [FIX] report: missing mt/mb (and others) definitions Since the website/web_editor split, the mt/mb definitions were not included in reports anymore. Those were not the only rules that were forgotten. In 9.0, as a fix, those rules were added back in the report.css file. As the assets have been refactored in saas-10, the fix here is to link the missing file (unique in saas-10) in the report assets. --- addons/report/views/layouts.xml | 2 ++ addons/web_editor/views/editor.xml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/addons/report/views/layouts.xml b/addons/report/views/layouts.xml index 85077214bd8..d5fdb0a942d 100644 --- a/addons/report/views/layouts.xml +++ b/addons/report/views/layouts.xml @@ -7,6 +7,8 @@ + + diff --git a/addons/web_editor/views/editor.xml b/addons/web_editor/views/editor.xml index 5b27aee1086..3d65fea2ebb 100644 --- a/addons/web_editor/views/editor.xml +++ b/addons/web_editor/views/editor.xml @@ -67,7 +67,7 @@ -