Odoo18-Base/addons/stock/tests/test_picking_tours.py
2025-01-06 10:57:38 +07:00

306 lines
12 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import Command
from odoo.tests import Form, HttpCase, tagged
@tagged('-at_install', 'post_install')
class TestStockPickingTour(HttpCase):
def setUp(self):
self.receipt = self.env['stock.picking'].create({
'picking_type_id': self.env.ref('stock.picking_type_in').id,
'location_id': self.env.ref('stock.stock_location_suppliers').id,
'location_dest_id': self.env.ref('stock.stock_location_stock').id,
})
return super().setUp()
def _get_picking_url(self, picking_id):
return '/odoo/action-stock.action_picking_tree_incoming/%s' % (picking_id)
def test_detailed_op_no_save_1(self):
"""validate a receipt with some move without any save except the last one"""
product_lot = self.env['product.product'].create({
'name': 'Product Lot',
'is_storable': True,
'tracking': 'lot',
})
url = self._get_picking_url(self.receipt.id)
self.start_tour(url, 'test_detailed_op_no_save_1', login='admin', timeout=60)
self.assertEqual(self.receipt.state, 'done')
self.assertEqual(self.receipt.move_ids.product_uom_qty, 0)
self.assertEqual(self.receipt.move_ids.quantity, 4)
lot = self.env['stock.lot'].search([
('name', '=', 'lot1'),
('product_id', '=', product_lot.id),
])
self.assertEqual(len(lot), 1)
self.assertEqual(lot.product_qty, 4)
def test_generate_serial_1(self):
"""generate some serial numbers in the detailed operation modal"""
product_serial = self.env['product.product'].create({
'name': 'Product Serial',
'is_storable': True,
'tracking': 'serial',
})
url = self._get_picking_url(self.receipt.id)
self.start_tour(url, 'test_generate_serial_1', login='admin', timeout=60)
self.assertEqual(self.receipt.state, 'done')
self.assertEqual(self.receipt.move_ids.product_uom_qty, 0)
self.assertEqual(self.receipt.move_ids.quantity, 5)
self.assertEqual(len(self.receipt.move_ids.move_line_ids), 5)
serial = self.env['stock.lot'].search([
('name', 'ilike', 'serial_n_%'),
('product_id', '=', product_serial.id),
])
self.assertEqual(len(serial), 5)
def test_generate_serial_2(self):
""" Generate lot numbers in the detailed operation modal """
product_lot_1 = self.env['product.product'].create({
'name': 'Product Lot 1',
'is_storable': True,
'tracking': 'lot',
})
url = self._get_picking_url(self.receipt.id)
self.start_tour(url, 'test_generate_serial_2', login='admin', timeout=60)
self.assertEqual(self.receipt.state, 'done')
self.assertEqual(self.receipt.move_ids.product_uom_qty, 100)
self.assertEqual(self.receipt.move_ids.quantity, 100)
self.assertEqual(len(self.receipt.move_ids.move_line_ids), 11)
lots_batch_1 = self.env['stock.lot'].search([
('name', 'ilike', 'lot_n_1_%'),
('product_id', '=', product_lot_1.id)
], order='name asc')
lots_batch_2 = self.env['stock.lot'].search([
('name', 'ilike', 'lot_n_2_%'),
('product_id', '=', product_lot_1.id)
], order='name asc')
self.assertEqual(len(lots_batch_1), 7)
self.assertEqual(lots_batch_1[-1].product_qty, 5)
self.assertEqual(len(lots_batch_2), 4)
self.assertEqual(lots_batch_2[-1].product_qty, 11)
def test_inventory_adjustment_apply_all(self):
"""
Checks if the "Apply All" button works for all new entries, even if
it was pressed immediately after entering the last entry's quantity
(without clicking on anything else)
"""
self.env['product.product'].create([
{'name': 'Product 1', 'is_storable': True},
{'name': 'Product 2', 'is_storable': True},
])
menu = self.env.ref('stock.menu_action_inventory_tree')
url = '/odoo/stock.quant?menu_id=%s' % (menu['id'])
# We need a bigger window, so the "Apply All" button is immediately visible
self.browser_size = '1920,1080'
self.start_tour(url, 'test_inventory_adjustment_apply_all', login='admin', timeout=60)
def test_add_new_line(self):
product_one, _ = self.env["product.product"].create([
{
'name': 'Product one',
'is_storable': True,
'tracking': 'serial',
},
{
'name': 'Product two',
'is_storable': True,
'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_add_new_line_in_detailled_op(self):
"""
Check that the unsaved quantity/location changes of the detailed operations impact dynamically
the creation of new move lines (considering the real avaible quantity rather than DB data's).
"""
warehouse = self.env.ref("stock.warehouse0")
product_lot = self.env['product.product'].create({
'name': 'Product Lot',
'is_storable': True,
'tracking': 'lot',
})
lot_1, lot_2, lot_3 = self.env['stock.lot'].create([
{'name': 'LOT001', 'product_id': product_lot.id, 'company_id': warehouse.company_id.id},
{'name': 'LOT002', 'product_id': product_lot.id, 'company_id': warehouse.company_id.id},
{'name': 'LOT003', 'product_id': product_lot.id, 'company_id': warehouse.company_id.id},
])
self.env['stock.quant']._update_available_quantity(product_lot, warehouse.lot_stock_id, quantity=10, lot_id=lot_1)
self.env['stock.quant']._update_available_quantity(product_lot, warehouse.lot_stock_id, quantity=15, lot_id=lot_2)
self.env['stock.quant']._update_available_quantity(product_lot, warehouse.lot_stock_id, quantity=10, lot_id=lot_3)
partner = self.env['res.partner'].create({'name': 'Bob'})
delivery = self.picking_in = self.env['stock.picking'].create({
'picking_type_id': warehouse.out_type_id.id,
'partner_id': partner.id,
'location_id': warehouse.lot_stock_id.id,
'location_dest_id': self.ref('stock.stock_location_customers'),
'move_ids': [Command.create({
'name': product_lot.name,
'product_id': product_lot.id,
'location_id': warehouse.lot_stock_id.id,
'location_dest_id': self.ref('stock.stock_location_customers'),
'product_uom_qty': 20,
})]
})
delivery.action_confirm()
self.assertRecordValues(delivery.move_line_ids, [
{'lot_id': lot_1.id, 'quantity': 10.0},
{'lot_id': lot_2.id, 'quantity': 10.0},
])
url = self._get_picking_url(delivery.id)
self.start_tour(url, 'test_add_new_line_in_detailled_op', login='admin', timeout=100)
self.assertRecordValues(delivery.move_line_ids.sorted("quantity"), [
{'quantity': 2.0, 'lot_id': lot_1.id},
{'quantity': 3.0, 'lot_id': lot_1.id},
{'quantity': 15.0, 'lot_id': lot_2.id},
])
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',
'is_storable': True,
'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"])
def test_edit_existing_lines_2(self):
self.uom_unit = self.env.ref('uom.product_uom_unit')
product_a, product_b = self.env["product.product"].create([
{
'name': 'Product a',
'is_storable': True,
'tracking': 'serial',
},
{
'name': 'Product b',
'is_storable': True,
'tracking': 'serial',
}
])
self.receipt.write({
"move_ids": [
Command.create({
"name": "Product a",
"product_id": product_a.id,
"location_id": self.receipt.location_id.id,
"location_dest_id": self.receipt.location_dest_id.id,
"product_uom_qty": 1,
}),
Command.create({
"name": "Product b",
"product_id": product_b.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()
url = self._get_picking_url(self.receipt.id)
self.start_tour(url, 'test_edit_existing_lines_2', login='admin', timeout=60)
names = self.receipt.move_ids.move_line_ids.mapped('lot_name')
self.assertEqual(names, ["SNa001", "SNb001"])
def test_onchange_serial_lot_ids(self):
"""
Checks that onchange behaves correctly with respect to multiple unlinks
"""
product_serial = self.env['product.product'].create({
'name': 'PSerial',
'is_storable': True,
'tracking': 'serial',
'categ_id': self.env.ref('product.product_category_all').id,
})
lots = self.env['stock.lot'].create([{
'name': 'SN01',
'product_id': product_serial.id,
'company_id': self.env.company.id,
}, {
'name': 'SN02',
'product_id': product_serial.id,
'company_id': self.env.company.id,
}, {
'name': 'SN03',
'product_id': product_serial.id,
'company_id': self.env.company.id,
}])
stock_location = self.env.ref('stock.stock_location_stock')
for lot in lots:
self.env['stock.quant']._update_available_quantity(product_serial, stock_location, 1, lot_id=lot)
picking = self.env['stock.picking'].create({
'location_id': stock_location.id,
'location_dest_id': self.ref('stock.stock_location_customers'),
'picking_type_id': self.ref('stock.picking_type_out'),
'move_ids': [Command.create({
'name': product_serial.name,
'product_id': product_serial.id,
'product_uom_qty': 3,
'product_uom': product_serial.uom_id.id,
'location_id': stock_location.id,
'location_dest_id': self.ref('stock.stock_location_customers'),
})]
})
picking.action_confirm()
with Form(picking) as form:
with form.move_ids_without_package.edit(0) as move_form:
move_form.quantity = 3.0
move_form.lot_ids = lots
url = self._get_picking_url(picking.id)
self.start_tour(url, 'test_onchange_twice_lot_ids', login='admin')
self.assertRecordValues(picking.move_ids, [{"quantity": 1, "lot_ids": lots[2].ids}])