diff --git a/addons/stock/static/src/views/picking_form/stock_move_one2many.js b/addons/stock/static/src/views/picking_form/stock_move_one2many.js index d618192bec6..a1db35eab0a 100644 --- a/addons/stock/static/src/views/picking_form/stock_move_one2many.js +++ b/addons/stock/static/src/views/picking_form/stock_move_one2many.js @@ -46,10 +46,14 @@ export class StockMoveX2ManyField extends X2ManyField { async openRecord(record) { - if (this.canOpenRecord) { + if (this.canOpenRecord && !record.isNew) { const dirty = await record.isDirty(); if (dirty && 'quantity' in record._changes) { await record.model.root.save({ reload: true }); + record = record.model.root.data[this.props.name].records.find(e => e.resId === record.resId); + if (!record) { + return; + } } } return super.openRecord(record); diff --git a/addons/stock/static/tests/tours/stock_picking_tour.js b/addons/stock/static/tests/tours/stock_picking_tour.js index 6b42ca4fffe..4361c7db37b 100644 --- a/addons/stock/static/tests/tours/stock_picking_tour.js +++ b/addons/stock/static/tests/tours/stock_picking_tour.js @@ -104,3 +104,55 @@ registry.category("web_tour.tours").add('test_generate_serial_1', { test: true, isCheck: true, }, ]}); + +registry.category("web_tour.tours").add('test_add_new_line', { + test: true, + steps: () => [ + { + extra_trigger: '.o_form_editable', + trigger: '.o_field_x2many_list_row_add > a' + }, + { + trigger: ".o_field_widget[name=product_id] input", + run: 'text two', + }, + { trigger: ".ui-menu-item > a:contains('Product two')" }, + { trigger: ".fa-list:eq(1)" }, + { trigger: "h4:contains('Stock move')" }, + { trigger: '.o_field_x2many_list_row_add > a' }, + { + trigger: ".o_field_widget[name=lot_name] input", + run: 'text two', + }, + { trigger: ".o_form_view.modal-content .o_form_button_save" }, + { trigger: ".o_form_view:not(.modal-content) .o_form_button_save" }, + { + trigger: ".o_form_renderer.o_form_saved", + isCheck: true, + }, + ] +}); + +registry.category("web_tour.tours").add('test_edit_existing_line', { + test: true, + steps: () => [ + { trigger: ".o_data_cell[name=quantity]" }, + { + trigger: ".o_field_widget[name=quantity] input", + run: 'text 2', + }, + { trigger: ".fa-list" }, + { trigger: "h4:contains('Stock move')" }, + { trigger: ".o_data_cell[name=quantity]:eq(1)" }, + { + trigger: ".o_field_widget[name=lot_name] input", + run: 'text two', + }, + { trigger: ".o_form_view.modal-content .o_form_button_save" }, + { trigger: ".o_form_view:not(.modal-content) .o_form_button_save" }, + { + trigger: ".o_form_renderer.o_form_saved", + isCheck: true, + }, + ] +}); diff --git a/addons/stock/tests/test_picking_tours.py b/addons/stock/tests/test_picking_tours.py index be95c7b60b8..8ddf6bc91c3 100644 --- a/addons/stock/tests/test_picking_tours.py +++ b/addons/stock/tests/test_picking_tours.py @@ -1,4 +1,5 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo import Command from odoo.tests import HttpCase, tagged @@ -57,3 +58,63 @@ class TestStockPickingTour(HttpCase): ('product_id', '=', product_serial.id), ]) self.assertEqual(len(serial), 5) + + def test_add_new_line(self): + product_one, _ = self.env["product.product"].create([ + { + 'name': 'Product one', + 'type': 'product', + 'tracking': 'serial', + }, + { + 'name': 'Product two', + 'type': 'product', + 'tracking': 'serial', + } + ]) + + self.receipt.write({ + "move_ids": [Command.create({ + "name": "test", + "product_uom_qty": 1, + "product_id": product_one.id, + "location_id": self.receipt.location_id.id, + "location_dest_id": self.receipt.location_dest_id.id, + })] + }) + + self.receipt.action_confirm() + self.receipt.move_ids.move_line_ids.lot_name = "one" + + url = self._get_picking_url(self.receipt.id) + self.start_tour(url, 'test_add_new_line', login='admin', timeout=60) + + names = self.receipt.move_ids.move_line_ids.mapped('lot_name') + self.assertEqual(names, ["two", "one"]) + + def test_edit_existing_line(self): + self.uom_unit = self.env.ref('uom.product_uom_unit') + product_one = self.env['product.product'].create({ + 'name': 'Product one', + 'type': 'product', + 'tracking': 'serial', + }) + + self.receipt.write({ + "move_ids": [Command.create({ + "name": "test", + "product_id": product_one.id, + "location_id": self.receipt.location_id.id, + "location_dest_id": self.receipt.location_dest_id.id, + "product_uom_qty": 1, + })] + }) + + self.receipt.action_confirm() + self.receipt.move_ids.move_line_ids.lot_name = "one" + + url = self._get_picking_url(self.receipt.id) + self.start_tour(url, 'test_edit_existing_line', login='admin', timeout=60) + + names = self.receipt.move_ids.move_line_ids.mapped('lot_name') + self.assertEqual(names, ["one", "two"])