[FIX] stock: use existing lots when importing lots

Steps to reproduce:
1. Install Inventory app.
2. Enable "Storage Locations" in Inventory settings.
3. Create a new product known as "X". Set it's tracking to "By Unique Serial Number".
4. In Inventory -> Configuration -> Operation Types -> Receipts, set "Use Existing Ones" to true.
5. Create a new Receipt, add a new line of product X.
6. In the "Details" page of the X line, click "Import Serials/Lots".
7. Enter at least two lines of two serial numbers and import.

Bug:
Notice that the "Lot/Serial Number" column on each row are blank.
This is happening because the view used for stock move lines here will
display either the lot_id field of a sml, or the lot_name field,
based on varying conditions. In this case, setting "Use Existing Ones"
to true will cause the lot_id field to be displayed (and the lot_name
field to be invisible). When importing lots, only the lot_name  is set
with the user's input but the lot_id is left blank. So because lot_id
is empty, the column is empty. But this works as expected
when "Use Existing Ones" is false because it displays the correctly
set lot_name. When the receipt is validated,
the lot is created and lot_id for each of the smls is set,
so now it displays properly.

Fix:
when "Use Existing Ones" is set first check if lot exists and set it in
that case, otherwise create and set a new lot at that moment

opw-3498812

closes odoo/odoo#140400

X-original-commit: c5a35a1c2a7e16adbd3f2b1e37509003bcfac957
Signed-off-by: William Henrotin (whe) <whe@odoo.com>
Signed-off-by: Walid Hanniche (waha) <waha@odoo.com>
This commit is contained in:
Walid
2023-10-31 14:40:57 +00:00
parent f65699dbd1
commit f949af22ce
3 changed files with 60 additions and 11 deletions
@@ -10,12 +10,6 @@ from odoo.tools.misc import get_lang
class TestStockLot(StockGenerateCommon):
def _import_lots(self, lots, move):
location_id = move.location_id
move_lines_vals = move.split_lots(lots)
move_lines_commands = move._generate_serial_move_line_commands(move_lines_vals, location_dest_id=location_id)
move.update({'move_line_ids': move_lines_commands})
def test_set_multiple_lot_name_with_expiration_date_01(self):
""" In a move line's `lot_name` field, pastes a list of lots and expiration dates.
Checks the values are correctly interpreted and the expiration dates are correctly created
+20 -5
View File
@@ -850,16 +850,31 @@ Please change the quantity done or the rounding precision of your unit of measur
options = options or self._get_formating_options(lot_text_parts[1:])
for extra_string in lot_text_parts[1:]:
field_data = self._convert_string_into_field_data(extra_string, options)
if field_data == "ignore":
# Got an unusable data for this move, updates only the lot_name part.
move_line_vals.update(lot_name=lot_text_parts[0])
elif field_data:
move_line_vals.update(**field_data, lot_name=lot_text_parts[0])
if field_data:
lot_text = lot_text_parts[0]
if field_data == "ignore":
# Got an unusable data for this move, updates only the lot_name part.
move_line_vals.update(lot_name=lot_text)
else:
move_line_vals.update(**field_data, lot_name=lot_text)
else:
# At least this part of the string is erronous and can't be converted,
# don't try to guess and simply use the full string as the lot name.
move_line_vals['lot_name'] = lot_text
break
if self.picking_type_id.use_existing_lots:
lot_id = self.env['stock.lot'].search([
('product_id', '=', self.product_id.id),
('name', '=', lot_text),
('company_id', '=', self.company_id.id),
])
if not lot_id:
lot_id = self.env['stock.lot'].create({
'product_id': self.product_id.id,
'name': lot_text,
'company_id': self.company_id.id,
})
move_line_vals['lot_id'] = lot_id.id
move_lines_vals.append(move_line_vals)
return move_lines_vals
@@ -35,6 +35,13 @@ class StockGenerateCommon(TransactionCase):
cls.Wizard = cls.env['stock.assign.serial']
def _import_lots(self, lots, move):
location_id = move.location_id
move_lines_vals = move.split_lots(lots)
move_lines_commands = move._generate_serial_move_line_commands(move_lines_vals, location_dest_id=location_id)
move.update({'move_line_ids': move_lines_commands})
def get_new_move(self, nbre_of_lines=0, product=False):
product = product or self.product_serial
move_lines_vals = [Command.create({
@@ -369,3 +376,36 @@ class StockGenerateCommon(TransactionCase):
{'quantity': 1, 'lot_name': '003', 'location_dest_id': sub_loc_03.id},
{'quantity': 1, 'lot_name': '004', 'location_dest_id': sub_loc_04.id},
])
def test_import_lots(self):
product_lot = self.env['product.product'].create({
'name': 'Tracked by Lots',
'type': 'product',
'tracking': 'lot',
})
lot_id = self.env['stock.lot'].create({
'product_id': product_lot.id,
'name': 'abc',
})
self.warehouse.in_type_id.use_existing_lots = True
receipt_picking = self.env['stock.picking'].create({
'picking_type_id': self.warehouse.in_type_id.id,
'location_id': self.env.ref('stock.stock_location_suppliers').id,
'location_dest_id': self.warehouse.lot_stock_id.id,
'state': 'draft',
})
move = self.env['stock.move'].create({
'name': product_lot.name,
'product_id': product_lot.id,
'product_uom': product_lot.uom_id.id,
'product_uom_qty': 5.0,
'picking_id': receipt_picking.id,
'location_id': receipt_picking.location_id.id,
'location_dest_id': receipt_picking.location_dest_id.id,
})
self._import_lots("abc;4\ndef", move)
self.assertIn(lot_id, move.move_line_ids.lot_id)
self.assertRecordValues(move.move_line_ids, [
{'quantity': 4, 'lot_name': 'abc'},
{'quantity': 1, 'lot_name': 'def'},
])