From 5a64fffe9abe58adf64312a3bd9ca8e5bb25f792 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 7 Aug 2018 19:06:02 +0200 Subject: [PATCH 01/14] [FIX] base: explicitly allow superuser to write on attachment's assets --- openerp/addons/base/ir/ir_attachment.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openerp/addons/base/ir/ir_attachment.py b/openerp/addons/base/ir/ir_attachment.py index c3be895e236..8128c701153 100644 --- a/openerp/addons/base/ir/ir_attachment.py +++ b/openerp/addons/base/ir/ir_attachment.py @@ -246,6 +246,8 @@ class ir_attachment(osv.osv): def _check_serving_attachments(self, cr, uid, ids, context=None): # restrict writing on attachments that could be served by the # ir.http's dispatch exception handling + if uid == SUPERUSER_ID: + return True user = self.pool['res.users'].browse(cr, uid, uid, context=context) for ira in self.browse(cr, uid, ids, context): if ira.type == 'binary' and ira.url: From 19f477299bf3399e7696d8102975dd0dd1c1687f Mon Sep 17 00:00:00 2001 From: Damien Bouvy Date: Wed, 8 Aug 2018 07:59:45 +0200 Subject: [PATCH 02/14] [FIX] hr_gamification: csv space EoL Can cause some issues with importing the files --- addons/hr_gamification/security/ir.model.access.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/hr_gamification/security/ir.model.access.csv b/addons/hr_gamification/security/ir.model.access.csv index 9ace96f7139..78979d89de5 100644 --- a/addons/hr_gamification/security/ir.model.access.csv +++ b/addons/hr_gamification/security/ir.model.access.csv @@ -2,4 +2,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink challenge_officer,"Challenge Officer",gamification.model_gamification_challenge,hr.group_hr_user,1,1,1,1 challenge_line_officer,"Challenge Line Officer",gamification.model_gamification_challenge_line,hr.group_hr_user,1,1,1,1 badge_officer,"Badge Officer",gamification.model_gamification_badge,hr.group_hr_user,1,1,1,1 -badge_user_officer,"Badge-user Officer",gamification.model_gamification_badge_user,hr.group_hr_user,1,1,1,1 +badge_user_officer,"Badge-user Officer",gamification.model_gamification_badge_user,hr.group_hr_user,1,1,1,1 From 0ab71f124797912b3df39e748552741df430e4fc Mon Sep 17 00:00:00 2001 From: len-odoo Date: Tue, 7 Aug 2018 10:26:50 +0200 Subject: [PATCH 03/14] [FIX] stock, sale_stock: copy the to_refund field when splitting a move The to_refund attribute is set to copy=False. However when splitting a move to create a backorder, a new move is created as a copy with the remaining work to do. This attribute is needed so that the backorder refund is consistently applied. Essentially a backport of commit: https://github.com/odoo/odoo/commit/c5ffca151160f9d99bec036330def108e4e91e0b opw 1865324 --- addons/sale_stock/models/stock.py | 5 +++++ addons/stock/models/stock_move.py | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/addons/sale_stock/models/stock.py b/addons/sale_stock/models/stock.py index 054b070b152..c9514a22084 100644 --- a/addons/sale_stock/models/stock.py +++ b/addons/sale_stock/models/stock.py @@ -40,6 +40,11 @@ class StockMove(models.Model): subtype_id=self.env.ref('mail.mt_note').id) return result + def _prepare_move_split_vals(self, defaults): + defaults = super(StockMove, self)._prepare_move_split_vals(defaults) + defaults['to_refund_so'] = self.to_refund_so + return defaults + class StockPicking(models.Model): _inherit = 'stock.picking' diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 352392ccb7d..c170d2cc5fa 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -938,6 +938,10 @@ class StockMove(models.Model): new_move_prop = self.move_dest_id.split(qty) new_move.write({'move_dest_id': new_move_prop}) + def _prepare_move_split_vals(self, defaults): + # hook to add values in default vals in other modules + return defaults + @api.multi def split(self, qty, restrict_lot_id=False, restrict_partner_id=False): """ Splits qty from move move into a new move @@ -967,6 +971,9 @@ class StockMove(models.Model): 'move_dest_id': self.move_dest_id.id, 'origin_returned_move_id': self.origin_returned_move_id.id, } + + defaults = self._prepare_move_split_vals(defaults) + if restrict_partner_id: defaults['restrict_partner_id'] = restrict_partner_id From 8ff138a0daf6fcec4a122ec4e98ce3e5000611ed Mon Sep 17 00:00:00 2001 From: Nicolas Lempereur Date: Tue, 7 Aug 2018 15:00:27 +0200 Subject: [PATCH 04/14] [FIX] barcodes: ok PageUp/Down/Home/End in firefox Same reason as 8d948d92. In firefox if barcode is installed, for example on a form view the keys to navigate the possible scrolling PageUp/PageDown/Home/End don't work at all. This is caused by the interface barcode catching and differences of the key event handling between firefox and other browser. So in this change, we add these keys so they are not catched by barcode. note: aso backport 5bc29744c so the code is the same between 10 and 11. related to opw-706352 closes #26219 --- addons/barcodes/static/src/js/barcode_events.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/barcodes/static/src/js/barcode_events.js b/addons/barcodes/static/src/js/barcode_events.js index bff05aa4636..287989d0efa 100644 --- a/addons/barcodes/static/src/js/barcode_events.js +++ b/addons/barcodes/static/src/js/barcode_events.js @@ -115,7 +115,9 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, { e.key === "ArrowUp" || e.key === "ArrowDown" || e.key === "Escape" || e.key === "Tab" || e.key === "Backspace" || e.key === "Delete" || - /F\d\d?/.test(e.key)) { + e.key === "Home" || e.key === "End" || + e.key === "PageUp" || e.key === "PageDown" || + e.key === "Unidentified" || /F\d\d?/.test(e.key)) { return true; } else { return false; From c61cddf814c2bddaab0a3aa415ea6934521ff140 Mon Sep 17 00:00:00 2001 From: Damien Bouvy Date: Wed, 8 Aug 2018 07:57:33 +0200 Subject: [PATCH 05/14] [FIX] hr_gamification: csv space EoL Can cause some issues with importing the files --- addons/hr_gamification/security/ir.model.access.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/hr_gamification/security/ir.model.access.csv b/addons/hr_gamification/security/ir.model.access.csv index 9ace96f7139..78979d89de5 100644 --- a/addons/hr_gamification/security/ir.model.access.csv +++ b/addons/hr_gamification/security/ir.model.access.csv @@ -2,4 +2,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink challenge_officer,"Challenge Officer",gamification.model_gamification_challenge,hr.group_hr_user,1,1,1,1 challenge_line_officer,"Challenge Line Officer",gamification.model_gamification_challenge_line,hr.group_hr_user,1,1,1,1 badge_officer,"Badge Officer",gamification.model_gamification_badge,hr.group_hr_user,1,1,1,1 -badge_user_officer,"Badge-user Officer",gamification.model_gamification_badge_user,hr.group_hr_user,1,1,1,1 +badge_user_officer,"Badge-user Officer",gamification.model_gamification_badge_user,hr.group_hr_user,1,1,1,1 From a4a9196c8d18cf0e994cb760fe4ed7db286483cd Mon Sep 17 00:00:00 2001 From: Wolfgang Taferner Date: Sun, 5 Aug 2018 11:23:32 +0200 Subject: [PATCH 06/14] [FIX] account: regression - display partner_name as placeholder --- .../src/js/reconciliation/reconciliation_renderer.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/addons/account/static/src/js/reconciliation/reconciliation_renderer.js b/addons/account/static/src/js/reconciliation/reconciliation_renderer.js index 33f969237d1..f5927b617ac 100644 --- a/addons/account/static/src/js/reconciliation/reconciliation_renderer.js +++ b/addons/account/static/src/js/reconciliation/reconciliation_renderer.js @@ -292,8 +292,12 @@ var LineRenderer = Widget.extend(FieldManagerMixin, { self.fields = { partner_id : new relational_fields.FieldMany2One(self, 'partner_id', - self.model.get(recordID), - {mode: 'edit'} + self.model.get(recordID), { + mode: 'edit', + attrs: { + placeholder: self._initialState.st_line.communication_partner_name || '', + } + } ) }; self.fields.partner_id.appendTo(self.$('.accounting_view caption')); From bb8bb3cbfe07a23c0adad173a6afcc7bcaccedc7 Mon Sep 17 00:00:00 2001 From: Gert Pellin Date: Wed, 8 Aug 2018 09:59:20 +0200 Subject: [PATCH 07/14] [FIX] point_of_sale: wrong behavior Price Control (#26232) Before the fix price control only worked like should on initialisation of a pos section. On switching cashier during a setting manager would lose price change rights and normal users would gain them. --- addons/point_of_sale/static/src/js/screens.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js index 95a7555e5d2..182af5308d4 100644 --- a/addons/point_of_sale/static/src/js/screens.js +++ b/addons/point_of_sale/static/src/js/screens.js @@ -394,7 +394,9 @@ var NumpadWidget = PosBaseWidget.extend({ this.$el.find('.mode-button').click(_.bind(this.clickChangeMode, this)); }, applyAccessRights: function() { - var has_price_control_rights = !this.pos.config.restrict_price_control || this.pos.get_cashier().role == 'manager'; + var has_price_control_rights = !this.pos.config.restrict_price_control + || (this.pos.changed.cashier && this.pos.changed.cashier.role == 'manager') + || (!this.pos.changed.cashier && this.pos.get_cashier().role == 'manager'); this.$el.find('.mode-button[data-mode="price"]') .toggleClass('disabled-mode', !has_price_control_rights) .prop('disabled', !has_price_control_rights); From f2b2d872360d5be241c0bac2a60bf8c788481046 Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Tue, 7 Aug 2018 14:47:49 +0200 Subject: [PATCH 08/14] [FIX] account: default name for analytic line from aml Create an account_move, with at least one move line having an analytic account on it AND no label Save and Post Before this commit, the post failed because an analytic.line should have a label (required) After this commit, we fill in a default name for the analytic line, composed of the data of the line, if available, or '/' OPW 1863418 closes #26013 --- addons/account/models/account_move.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 879fa6cb6d4..3b8968f8912 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -1459,8 +1459,9 @@ class AccountMoveLine(models.Model): an analytic account. This method is intended to be extended in other modules. """ amount = (self.credit or 0.0) - (self.debit or 0.0) + default_name = self.name or (self.ref or '/' + ' -- ' + (self.partner_id and self.partner_id.name or '/')) return { - 'name': self.name, + 'name': default_name, 'date': self.date, 'account_id': self.analytic_account_id.id, 'tag_ids': [(6, 0, self.analytic_tag_ids.ids)], From 6ded4d9ce89465a4a83f8bca4a1c01d995995bc1 Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Tue, 7 Aug 2018 14:43:21 +0200 Subject: [PATCH 09/14] [FIX] payment_stripe: disable button - Create an order from the eCommerce - Choose to pay with Stripe - Enter the credit card info, validate There is a short window of time (before the reload of the page) where the user can click on 'Pay Now' again. This is because the HTML is completely replaced, including the button. We restore it when necessary. opw-1866332 --- addons/payment_stripe/static/src/js/stripe.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/payment_stripe/static/src/js/stripe.js b/addons/payment_stripe/static/src/js/stripe.js index c1ddb41351b..2701edf015e 100644 --- a/addons/payment_stripe/static/src/js/stripe.js +++ b/addons/payment_stripe/static/src/js/stripe.js @@ -92,7 +92,10 @@ odoo.define('payment_stripe.stripe', function(require) { so_id: so_id, so_token: so_token }, {'async': false}).then(function (data) { + var $pay_stripe = $('#pay_stripe').detach(); $form.html(data); + // Restore 'Pay Now' button HTML since data might have changed it. + $form.find('#pay_stripe').replaceWith($pay_stripe); handler.open({ name: $("input[name='merchant']").val(), email: $("input[name='email']").val(), From d32a5eddc850f482d0a88855462de5e5a0705223 Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Wed, 8 Aug 2018 14:30:07 +0200 Subject: [PATCH 10/14] [FIX] point_of_sale: wrong behavior Price Control This is not expected since it leads to an inconsistent result: the user and the access rights do not match. Better add a PIN to the manager. This reverts commit bb8bb3cbfe07a23c0adad173a6afcc7bcaccedc7. --- addons/point_of_sale/static/src/js/screens.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js index 182af5308d4..95a7555e5d2 100644 --- a/addons/point_of_sale/static/src/js/screens.js +++ b/addons/point_of_sale/static/src/js/screens.js @@ -394,9 +394,7 @@ var NumpadWidget = PosBaseWidget.extend({ this.$el.find('.mode-button').click(_.bind(this.clickChangeMode, this)); }, applyAccessRights: function() { - var has_price_control_rights = !this.pos.config.restrict_price_control - || (this.pos.changed.cashier && this.pos.changed.cashier.role == 'manager') - || (!this.pos.changed.cashier && this.pos.get_cashier().role == 'manager'); + var has_price_control_rights = !this.pos.config.restrict_price_control || this.pos.get_cashier().role == 'manager'; this.$el.find('.mode-button[data-mode="price"]') .toggleClass('disabled-mode', !has_price_control_rights) .prop('disabled', !has_price_control_rights); From b122526666d6919804a0e3411aed5093b3593f33 Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Wed, 8 Aug 2018 15:42:13 +0200 Subject: [PATCH 11/14] [FIX] pad_project: avoid rewriting project on task saving Due to the side effect on related fields that are not readonly, the value is saved in project although not changed. Putting it readonly avoids the problem. Fixes #26156 Closes #26171 --- addons/pad_project/models/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/pad_project/models/project.py b/addons/pad_project/models/project.py index f994b3a5ea7..6d2273b15dd 100644 --- a/addons/pad_project/models/project.py +++ b/addons/pad_project/models/project.py @@ -9,7 +9,7 @@ class ProjectTask(models.Model): _inherit = ["project.task", 'pad.common'] description_pad = fields.Char('Pad URL', pad_content_field='description', copy=False) - use_pad = fields.Boolean(related="project_id.use_pads", string="Use collaborative pad") + use_pad = fields.Boolean(related="project_id.use_pads", string="Use collaborative pad", readonly=True) @api.model def create(self, vals): From 325399ab44d2563d121edc9422479e61b40e401b Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Wed, 8 Aug 2018 19:38:19 +0200 Subject: [PATCH 12/14] [FIX] {sale_,}stock: revert 0ab71f124797912b3df Esentially forward-porting a backport is not a good idea... --- addons/sale_stock/models/stock.py | 5 ----- addons/stock/models/stock_move.py | 7 ------- 2 files changed, 12 deletions(-) diff --git a/addons/sale_stock/models/stock.py b/addons/sale_stock/models/stock.py index 7a378c408d3..b13e71d6c6f 100644 --- a/addons/sale_stock/models/stock.py +++ b/addons/sale_stock/models/stock.py @@ -43,11 +43,6 @@ class StockMove(models.Model): line.qty_delivered = line._get_delivered_qty() return res - def _prepare_move_split_vals(self, defaults): - defaults = super(StockMove, self)._prepare_move_split_vals(defaults) - defaults['to_refund_so'] = self.to_refund_so - return defaults - class ProcurementGroup(models.Model): _inherit = 'procurement.group' diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 081a69c5c8c..7b5ee057159 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -1161,10 +1161,6 @@ class StockMove(models.Model): vals['product_uom'] = self.env.context['force_split_uom_id'] return vals - def _prepare_move_split_vals(self, defaults): - # hook to add values in default vals in other modules - return defaults - def _split(self, qty, restrict_partner_id=False): """ Splits qty from move move into a new move @@ -1194,9 +1190,6 @@ class StockMove(models.Model): else: defaults = self.with_context(force_split_uom_id=self.product_id.uom_id.id)._prepare_move_split_vals(qty) - - defaults = self._prepare_move_split_vals(defaults) - if restrict_partner_id: defaults['restrict_partner_id'] = restrict_partner_id From d92f17cebe048190679f7f86456d93aa98c0cb2a Mon Sep 17 00:00:00 2001 From: Jigar A Date: Wed, 8 Aug 2018 11:57:48 -0700 Subject: [PATCH 13/14] [FIX] signup: allow non-admin to invite portal users --- addons/auth_signup/models/res_partner.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/auth_signup/models/res_partner.py b/addons/auth_signup/models/res_partner.py index c3f3d8996b0..8ff7b8ce91c 100644 --- a/addons/auth_signup/models/res_partner.py +++ b/addons/auth_signup/models/res_partner.py @@ -108,6 +108,7 @@ class ResPartner(models.Model): allow_signup = self.env['ir.config_parameter'].sudo().get_param('auth_signup.allow_uninvited', 'False').lower() == 'true' for partner in self: if allow_signup and not partner.user_ids: + partner = partner.sudo() partner.signup_prepare() res[partner.id]['auth_signup_token'] = partner.signup_token elif partner.user_ids: From 252bc396b445d1635e8dac1f3cfa1dd5de8cc36e Mon Sep 17 00:00:00 2001 From: Simon Lejeune Date: Mon, 9 Jul 2018 15:34:08 +0200 Subject: [PATCH 14/14] [FIX] stock: button_validate: forced move lines When a move line is not linked to a move, it'll be linked to the first move of the same product at validation time. We slightly improve this logic by linking it to the first non-completed move. To be completely correct, we should split the move line if necessary and link it to all needed moves, but at this time we don't want to make the logic too complex. Use case: create a sale order with three sale order lines of the same products, use the detailed operations view and add three move lines of the same products, validate the picking. Before the patch, all move lines were linked to the first move and thus only the first sale order line had delivered quantities. Fixes #25488 opw-1861765 --- addons/sale_stock/tests/test_sale_stock.py | 73 ++++++++++++++++++++++ addons/stock/models/stock_picking.py | 7 ++- 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/addons/sale_stock/tests/test_sale_stock.py b/addons/sale_stock/tests/test_sale_stock.py index c4a32bbf4dc..1081e18f153 100644 --- a/addons/sale_stock/tests/test_sale_stock.py +++ b/addons/sale_stock/tests/test_sale_stock.py @@ -421,3 +421,76 @@ class TestSaleStock(TestSale): # check the delivered quantity self.assertEqual(so1.order_line.qty_delivered, 3.0) + def test_07_forced_qties(self): + """ Make multiple sale order lines of the same product which isn't available in stock. On + the picking, create new move lines (through the detailed operations view). See that the move + lines are correctly dispatched through the moves. + """ + uom_unit = self.env.ref('product.product_uom_unit') + uom_dozen = self.env.ref('product.product_uom_dozen') + item1 = self.products['prod_order'] + + self.assertEqual(item1.uom_id.id, uom_unit.id) + + # sell a dozen + so1 = self.env['sale.order'].create({ + 'partner_id': self.partner.id, + 'order_line': [ + (0, 0, { + 'name': item1.name, + 'product_id': item1.id, + 'product_uom_qty': 1, + 'product_uom': uom_dozen.id, + 'price_unit': item1.list_price, + }), + (0, 0, { + 'name': item1.name, + 'product_id': item1.id, + 'product_uom_qty': 1, + 'product_uom': uom_dozen.id, + 'price_unit': item1.list_price, + }), + (0, 0, { + 'name': item1.name, + 'product_id': item1.id, + 'product_uom_qty': 1, + 'product_uom': uom_dozen.id, + 'price_unit': item1.list_price, + }), + ], + }) + so1.action_confirm() + + self.assertEqual(len(so1.picking_ids.move_lines), 3) + so1.picking_ids.write({ + 'move_line_ids': [ + (0, 0, { + 'product_id': item1.id, + 'product_uom_qty': 0, + 'qty_done': 1, + 'product_uom_id': uom_dozen.id, + 'location_id': so1.picking_ids.location_id.id, + 'location_dest_id': so1.picking_ids.location_dest_id.id, + }), + (0, 0, { + 'product_id': item1.id, + 'product_uom_qty': 0, + 'qty_done': 1, + 'product_uom_id': uom_dozen.id, + 'location_id': so1.picking_ids.location_id.id, + 'location_dest_id': so1.picking_ids.location_dest_id.id, + }), + (0, 0, { + 'product_id': item1.id, + 'product_uom_qty': 0, + 'qty_done': 1, + 'product_uom_id': uom_dozen.id, + 'location_id': so1.picking_ids.location_id.id, + 'location_dest_id': so1.picking_ids.location_dest_id.id, + }), + ], + }) + so1.picking_ids.button_validate() + self.assertEqual(so1.picking_ids.state, 'done') + self.assertEqual(so1.order_line.mapped('qty_delivered'), [1, 1, 1]) + diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index 314fee31e06..f99e59b9c9b 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -631,8 +631,9 @@ class Picking(models.Model): # # Link existing moves or add moves when no one is related for ops in pick.move_line_ids.filtered(lambda x: not x.move_id): # Search move with this product - moves = pick.move_lines.filtered(lambda x: x.product_id == ops.product_id) - if moves: #could search move that needs it the most (that has some quantities left) + moves = pick.move_lines.filtered(lambda x: x.product_id == ops.product_id) + moves = sorted(moves, key=lambda m: m.quantity_done < m.product_qty, reverse=True) + if moves: ops.move_id = moves[0].id else: new_move = self.env['stock.move'].create({ @@ -802,7 +803,7 @@ class Picking(models.Model): quantity_done[quant.product_id.id] += quant.qty for pack in self.mapped('move_line_ids').filtered(lambda x: x.product_id and not x.move_id): quantity_done.setdefault(pack.product_id.id, 0) - quantity_done[pack.product_id.id] += pack.qty_done + quantity_done[pack.product_id.id] += pack.product_uom_id._compute_quantity(pack.qty_done, pack.product_id.uom_id) return any(quantity_done[x] < quantity_todo.get(x, 0) for x in quantity_done) @api.multi