质量模块和库存扫码
This commit is contained in:
6
stock_barcode/tests/__init__.py
Normal file
6
stock_barcode/tests/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import test_barcode
|
||||
from . import test_barcode_client_action
|
||||
from . import test_barcode_client_action_inventory
|
||||
from . import test_barcode_client_action_picking
|
||||
182
stock_barcode/tests/test_barcode.py
Normal file
182
stock_barcode/tests/test_barcode.py
Normal file
@@ -0,0 +1,182 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.tests import HttpCase, tagged
|
||||
|
||||
|
||||
@tagged('-at_install', 'post_install')
|
||||
class TestBarcodeClientAction(HttpCase):
|
||||
def test_filter_picking_by_product_gs1(self):
|
||||
""" Checks if a product is searched with a complete GS1 barcode, the
|
||||
product data is correctly retrieved and the search operates only on the
|
||||
product's part of the GS1 barcode. Also, checks a product can still be
|
||||
searched by its raw barcode even if GS1 nomenclature is used.
|
||||
"""
|
||||
Product = self.env['product.product']
|
||||
product_category_all = self.env.ref('product.product_category_all')
|
||||
# Creates three products.
|
||||
product1 = Product.create({
|
||||
'name': 'product1',
|
||||
'barcode': '01304510',
|
||||
'categ_id': product_category_all.id,
|
||||
'type': 'product',
|
||||
})
|
||||
product2 = Product.create({
|
||||
'name': 'product2',
|
||||
'barcode': '73411048',
|
||||
'categ_id': product_category_all.id,
|
||||
'type': 'product',
|
||||
})
|
||||
product3 = Product.create({
|
||||
'name': 'product3',
|
||||
'barcode': '00000073411048', # Ambiguous with the product2 barcode.
|
||||
'categ_id': product_category_all.id,
|
||||
'type': 'product',
|
||||
})
|
||||
|
||||
# Searches while using the default barcode nomenclature.
|
||||
product = Product.search([('barcode', '=', '01304510')])
|
||||
self.assertEqual(len(product), 1, "Product should be found when searching by its barcode")
|
||||
self.assertEqual(product.id, product1.id)
|
||||
product = Product.search([('barcode', '=', '0100000001304510')])
|
||||
self.assertEqual(len(product), 0, "Product shouldn't be found with GS1 barcode if GS1 nomenclature is inactive")
|
||||
|
||||
# Searches while using the GS1 barcode nomenclature.
|
||||
self.env.company.nomenclature_id = self.env.ref('barcodes_gs1_nomenclature.default_gs1_nomenclature')
|
||||
for operator in ['=', 'ilike']:
|
||||
product = Product.search([('barcode', operator, '01304510')])
|
||||
self.assertEqual(len(product), 1, "Product should still be found when searching by its raw barcode even if GS1 nomenclature is active")
|
||||
self.assertEqual(product.id, product1.id)
|
||||
product = Product.search([('barcode', operator, '300005\x1D0100000001304510')])
|
||||
self.assertEqual(len(product), 1, "Product should be found when scanning a GS1 barcode containing its data")
|
||||
self.assertEqual(product.id, product1.id)
|
||||
product = Product.search([('barcode', operator, '0100000001304510\x1Dt00.d4r|<')])
|
||||
self.assertEqual(len(product), 0, "No products should be found because of invalid GS1 barcode")
|
||||
product = Product.search([('barcode', operator, '0100000073411048')])
|
||||
self.assertEqual(len(product), 2, "Should found two products because of the ambiguity")
|
||||
self.assertEqual(product.ids, [product2.id, product3.id])
|
||||
|
||||
# Checks search for all products except one from a GS1 barcode is workking as expected.
|
||||
for operator in ['!=', 'not ilike']:
|
||||
products = Product.search([('barcode', operator, '01304510')])
|
||||
self.assertFalse(product1 in products)
|
||||
self.assertTrue(product2 in products and product3 in products)
|
||||
products = Product.search([('barcode', operator, '300005\x1D0100000001304510')])
|
||||
self.assertFalse(product1 in products)
|
||||
self.assertTrue(product2 in products and product3 in products)
|
||||
products = Product.search([('barcode', operator, '00000073411048')])
|
||||
self.assertTrue(product1 in products)
|
||||
self.assertFalse(product2 in products, "product2 shouldn't be found due to unpadding of the barcode implied in the search")
|
||||
self.assertFalse(product3 in products)
|
||||
products = Product.search([('barcode', operator, '0100000073411048300005')])
|
||||
self.assertTrue(product1 in products)
|
||||
self.assertFalse(product2 in products or product3 in products)
|
||||
|
||||
def test_filter_picking_by_package_gs1(self):
|
||||
grp_pack = self.env.ref('stock.group_tracking_lot')
|
||||
self.env.user.write({'groups_id': [(3, grp_pack.id)]})
|
||||
|
||||
Package = self.env['stock.quant.package']
|
||||
# Creates three packages.
|
||||
package1 = Package.create({
|
||||
'name': '1234560000000018',
|
||||
})
|
||||
package2 = Package.create({
|
||||
'name': '7189085627231896',
|
||||
})
|
||||
package3 = Package.create({
|
||||
'name': '007189085627231896', # Ambiguous with the package2 barcode.
|
||||
})
|
||||
|
||||
# Searches while using the default barcode nomenclature.
|
||||
self.env.company.nomenclature_id = self.env.ref('barcodes.default_barcode_nomenclature')
|
||||
package = Package.search([('name', '=', '1234560000000018')])
|
||||
self.assertEqual(len(package), 1, "Package should be found when searching by its barcode")
|
||||
self.assertEqual(package.id, package1.id)
|
||||
package = Package.search([('name', '=', '00007189085627231896')])
|
||||
self.assertFalse(package, "Package shouldn't be found with GS1 barcode if GS1 nomenclature is inactive")
|
||||
|
||||
# Searches while using the GS1 barcode nomenclature.
|
||||
self.env.company.nomenclature_id = self.env.ref('barcodes_gs1_nomenclature.default_gs1_nomenclature')
|
||||
for operator in ['=', 'ilike']:
|
||||
package = Package.search([('name', operator, '1234560000000018')])
|
||||
self.assertEqual(len(package), 1, "Package should still be found when searching by its raw barcode even if GS1 nomenclature is active")
|
||||
self.assertEqual(package.id, package1.id)
|
||||
package = Package.search([('name', operator, '300005\x1D00001234560000000018')])
|
||||
self.assertEqual(len(package), 1, "Package should be found when scanning a GS1 barcode containing its data")
|
||||
self.assertEqual(package.id, package1.id)
|
||||
package = Package.search([('name', operator, '00007189085627231896\x1Dt00.d4r|<')])
|
||||
self.assertEqual(len(package), 0, "No package should be found because of invalid GS1 barcode")
|
||||
package = Package.search([('name', operator, '00007189085627231896')])
|
||||
self.assertEqual(len(package), 2, "Should found two packages because of the ambiguity")
|
||||
self.assertTrue(package.ids, (package2 | package3).ids)
|
||||
|
||||
# Checks search for all packages except one from a GS1 barcode is workking as expected.
|
||||
for operator in ['!=', 'not ilike']:
|
||||
packages = Package.search([('name', operator, '1234560000000018')])
|
||||
self.assertFalse(package1 in packages)
|
||||
self.assertTrue(packages.ids, (package2 | package3).ids)
|
||||
packages = Package.search([('name', operator, '300005\x1D00001234560000000018')])
|
||||
self.assertFalse(package1 in packages)
|
||||
self.assertTrue(packages.ids, (package2 | package3).ids)
|
||||
packages = Package.search([('name', operator, '007189085627231896')])
|
||||
self.assertTrue(package1 in packages)
|
||||
self.assertFalse(package2 in packages, "package2 shouldn't be found due to unpadding of the barcode implied in the search")
|
||||
self.assertFalse(package3 in packages)
|
||||
package = Package.search([('name', operator, '00007189085627231896')])
|
||||
self.assertTrue(package1 in packages)
|
||||
self.assertFalse(package2 in packages or package3 in packages)
|
||||
|
||||
def test_filter_picking_by_location_gs1(self):
|
||||
Location = self.env['stock.location']
|
||||
# Creates three locations.
|
||||
location1 = Location.create({
|
||||
'name': 'loc1',
|
||||
'barcode': '5055218716187',
|
||||
})
|
||||
location2 = Location.create({
|
||||
'name': 'loc2',
|
||||
'barcode': '614141000531',
|
||||
})
|
||||
location3 = Location.create({
|
||||
'name': 'loc3',
|
||||
'barcode': '0614141000531', # Ambiguous with the package2 barcode.
|
||||
})
|
||||
|
||||
# Searches while using the default barcode nomenclature.
|
||||
self.env.company.nomenclature_id = self.env.ref('barcodes.default_barcode_nomenclature')
|
||||
location = Location.search([('barcode', '=', '5055218716187')])
|
||||
self.assertEqual(len(location), 1, "Location should be found when searching by its barcode")
|
||||
self.assertEqual(location.id, location1.id)
|
||||
package = Location.search([('name', '=', '4100614141000531')])
|
||||
self.assertFalse(package, "Package shouldn't be found with GS1 barcode if GS1 nomenclature is inactive")
|
||||
|
||||
# Searches while using the GS1 barcode nomenclature.
|
||||
self.env.company.nomenclature_id = self.env.ref('barcodes_gs1_nomenclature.default_gs1_nomenclature')
|
||||
for operator in ['=', 'ilike']:
|
||||
location = Location.search([('barcode', operator, '5055218716187')])
|
||||
self.assertEqual(len(location), 1, "Location should still be found when searching by its raw barcode even if GS1 nomenclature is active")
|
||||
self.assertEqual(location.id, location1.id)
|
||||
location = Location.search([('barcode', operator, '300005\x1D4145055218716187')])
|
||||
self.assertEqual(len(location), 1, "Location should be found when scanning a GS1 barcode containing its data")
|
||||
self.assertEqual(location.id, location1.id)
|
||||
location = Location.search([('barcode', operator, '4100614141000531\x1Dt00.d4r|<')])
|
||||
self.assertEqual(len(location), 0, "No location should be found because of invalid GS1 barcode")
|
||||
location = Location.search([('barcode', operator, '4100614141000531')])
|
||||
self.assertEqual(len(location), 2, "Should found two locations because of the ambiguity")
|
||||
self.assertTrue(location.ids, (location2 | location3).ids)
|
||||
|
||||
# Checks search for all locations except one from a GS1 barcode is workking as expected.
|
||||
for operator in ['!=', 'not ilike']:
|
||||
locations = Location.search([('barcode', operator, '5055218716187')])
|
||||
self.assertFalse(location1 in locations)
|
||||
self.assertTrue(location2.id in locations.ids and location3.id in locations.ids)
|
||||
locations = Location.search([('barcode', operator, '300005\x1D4145055218716187')])
|
||||
self.assertFalse(location1 in locations)
|
||||
self.assertTrue(location2.id in locations.ids and location3.id in locations.ids)
|
||||
locations = Location.search([('barcode', operator, '0614141000531')])
|
||||
self.assertTrue(location1 in locations)
|
||||
self.assertFalse(location2 in locations, "location2 shouldn't be found due to unpadding of the barcode implied in the search")
|
||||
self.assertFalse(location3 in locations)
|
||||
locations = Location.search([('barcode', operator, '4100614141000531')])
|
||||
self.assertTrue(location1 in locations)
|
||||
self.assertFalse(location2 in locations or location3 in locations)
|
||||
114
stock_barcode/tests/test_barcode_client_action.py
Normal file
114
stock_barcode/tests/test_barcode_client_action.py
Normal file
@@ -0,0 +1,114 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.tests import HttpCase, tagged
|
||||
|
||||
|
||||
@tagged('-at_install', 'post_install')
|
||||
class TestBarcodeClientAction(HttpCase):
|
||||
def setUp(self):
|
||||
super(TestBarcodeClientAction, self).setUp()
|
||||
self.uid = self.env.ref('base.user_admin').id
|
||||
self.supplier_location = self.env.ref('stock.stock_location_suppliers')
|
||||
self.stock_location = self.env.ref('stock.stock_location_stock')
|
||||
self.stock_location.write({
|
||||
'barcode': 'LOC-01-00-00',
|
||||
})
|
||||
self.customer_location = self.env.ref('stock.stock_location_customers')
|
||||
self.pack_location = self.env.ref('stock.location_pack_zone')
|
||||
self.shelf3 = self.env['stock.location'].create({
|
||||
'name': 'Section 3',
|
||||
'location_id': self.stock_location.id,
|
||||
'barcode': 'shelf3',
|
||||
})
|
||||
self.shelf1 = self.env["stock.location"].create({
|
||||
'name': 'Section 1',
|
||||
'location_id': self.env.ref('stock.warehouse0').lot_stock_id.id,
|
||||
'barcode': 'LOC-01-01-00',
|
||||
})
|
||||
self.shelf2 = self.env['stock.location'].create({
|
||||
'name': 'Section 2',
|
||||
'location_id': self.env.ref('stock.warehouse0').lot_stock_id.id,
|
||||
'barcode': 'LOC-01-02-00',
|
||||
})
|
||||
self.shelf4 = self.env['stock.location'].create({
|
||||
'name': 'Section 4',
|
||||
'location_id': self.stock_location.id,
|
||||
'barcode': 'shelf4',
|
||||
})
|
||||
self.picking_type_in = self.env.ref('stock.picking_type_in')
|
||||
self.picking_type_internal = self.env.ref('stock.picking_type_internal')
|
||||
self.picking_type_out = self.env.ref('stock.picking_type_out')
|
||||
|
||||
self.uom_unit = self.env.ref('uom.product_uom_unit')
|
||||
self.uom_dozen = self.env.ref('uom.product_uom_dozen')
|
||||
|
||||
# Two stockable products without tracking
|
||||
self.product1 = self.env['product.product'].create({
|
||||
'name': 'product1',
|
||||
'default_code': 'TEST',
|
||||
'type': 'product',
|
||||
'categ_id': self.env.ref('product.product_category_all').id,
|
||||
'barcode': 'product1',
|
||||
})
|
||||
self.product2 = self.env['product.product'].create({
|
||||
'name': 'product2',
|
||||
'type': 'product',
|
||||
'categ_id': self.env.ref('product.product_category_all').id,
|
||||
'barcode': 'product2',
|
||||
})
|
||||
self.productserial1 = self.env['product.product'].create({
|
||||
'name': 'productserial1',
|
||||
'type': 'product',
|
||||
'categ_id': self.env.ref('product.product_category_all').id,
|
||||
'barcode': 'productserial1',
|
||||
'tracking': 'serial',
|
||||
})
|
||||
self.productlot1 = self.env['product.product'].create({
|
||||
'name': 'productlot1',
|
||||
'type': 'product',
|
||||
'categ_id': self.env.ref('product.product_category_all').id,
|
||||
'barcode': 'productlot1',
|
||||
'tracking': 'lot',
|
||||
})
|
||||
self.package = self.env['stock.quant.package'].create({
|
||||
'name': 'P00001',
|
||||
})
|
||||
self.owner = self.env['res.partner'].create({
|
||||
'name': 'Azure Interior',
|
||||
})
|
||||
|
||||
# Creates records specific to GS1 use cases.
|
||||
self.product_tln_gtn8 = self.env['product.product'].create({
|
||||
'name': 'Battle Droid',
|
||||
'default_code': 'B1',
|
||||
'type': 'product',
|
||||
'tracking': 'lot',
|
||||
'categ_id': self.env.ref('product.product_category_all').id,
|
||||
'barcode': '76543210', # (01)00000076543210 (GTIN-8 format)
|
||||
'uom_id': self.env.ref('uom.product_uom_unit').id
|
||||
})
|
||||
|
||||
self.call_count = 0
|
||||
|
||||
def clean_access_rights(self):
|
||||
""" Removes all access right link to stock application to the users
|
||||
given as parameter"""
|
||||
grp_lot = self.env.ref('stock.group_production_lot')
|
||||
grp_multi_loc = self.env.ref('stock.group_stock_multi_locations')
|
||||
grp_pack = self.env.ref('stock.group_tracking_lot')
|
||||
grp_uom = self.env.ref('uom.group_uom')
|
||||
self.env.user.write({'groups_id': [(3, grp_lot.id)]})
|
||||
self.env.user.write({'groups_id': [(3, grp_multi_loc.id)]})
|
||||
self.env.user.write({'groups_id': [(3, grp_pack.id)]})
|
||||
# Explicitly remove the UoM group.
|
||||
group_user = self.env.ref('base.group_user')
|
||||
group_user.write({'implied_ids': [(3, grp_uom.id)]})
|
||||
self.env.user.write({'groups_id': [(3, grp_uom.id)]})
|
||||
|
||||
def tearDown(self):
|
||||
self.call_count = 0
|
||||
super(TestBarcodeClientAction, self).tearDown()
|
||||
|
||||
def _get_client_action_url(self, picking_id):
|
||||
action = self.env["ir.actions.actions"]._for_xml_id("stock_barcode.stock_barcode_picking_client_action")
|
||||
return '/web#action=%s&active_id=%s' % (action['id'], picking_id)
|
||||
350
stock_barcode/tests/test_barcode_client_action_inventory.py
Normal file
350
stock_barcode/tests/test_barcode_client_action_inventory.py
Normal file
@@ -0,0 +1,350 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.tests import tagged
|
||||
from odoo.addons.stock_barcode.tests.test_barcode_client_action import TestBarcodeClientAction
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestInventoryAdjustmentBarcodeClientAction(TestBarcodeClientAction):
|
||||
def test_inventory_adjustment(self):
|
||||
""" Simulate the following actions:
|
||||
- Open the inventory from the barcode app.
|
||||
- Scan twice the product 1.
|
||||
- Edit the line.
|
||||
- Add a product with the form view.
|
||||
- Validate
|
||||
"""
|
||||
|
||||
action_id = self.env.ref('stock_barcode.stock_barcode_action_main_menu')
|
||||
url = "/web#action=" + str(action_id.id)
|
||||
|
||||
self.start_tour(url, 'test_inventory_adjustment', login='admin', timeout=180)
|
||||
|
||||
inventory_moves = self.env['stock.move'].search([('product_id', 'in', [self.product1.id, self.product2.id]),
|
||||
('is_inventory', '=', True)])
|
||||
self.assertEqual(len(inventory_moves), 2)
|
||||
self.assertEqual(inventory_moves.mapped('quantity_done'), [2.0, 2.0])
|
||||
self.assertEqual(inventory_moves.mapped('state'), ['done', 'done'])
|
||||
|
||||
quants = self.env['stock.quant'].search([('product_id', 'in', [self.product1.id, self.product2.id]),
|
||||
('location_id.usage', '=', 'internal')])
|
||||
self.assertEqual(quants.mapped('quantity'), [2.0, 2.0])
|
||||
self.assertEqual(quants.mapped('inventory_quantity'), [0, 0])
|
||||
self.assertEqual(quants.mapped('inventory_diff_quantity'), [0, 0])
|
||||
|
||||
def test_inventory_adjustment_multi_location(self):
|
||||
""" Simulate the following actions:
|
||||
- Generate those lines with scan:
|
||||
WH/stock product1 qty: 2
|
||||
WH/stock product2 qty: 1
|
||||
WH/stock/shelf1 product2 qty: 1
|
||||
WH/stock/shelf2 product1 qty: 1
|
||||
- Validate
|
||||
"""
|
||||
self.clean_access_rights()
|
||||
grp_multi_loc = self.env.ref('stock.group_stock_multi_locations')
|
||||
self.env.user.write({'groups_id': [(4, grp_multi_loc.id, 0)]})
|
||||
|
||||
action_id = self.env.ref('stock_barcode.stock_barcode_action_main_menu')
|
||||
url = "/web#action=" + str(action_id.id)
|
||||
|
||||
self.start_tour(url, 'test_inventory_adjustment_multi_location', login='admin', timeout=180)
|
||||
|
||||
inventory_moves = self.env['stock.move'].search([('product_id', 'in', [self.product1.id, self.product2.id]),
|
||||
('is_inventory', '=', True)])
|
||||
self.assertEqual(len(inventory_moves), 4)
|
||||
self.assertEqual(inventory_moves.mapped('state'), ['done', 'done', 'done', 'done'])
|
||||
inventory_move_in_WH_stock = inventory_moves.filtered(lambda l: l.location_dest_id == self.stock_location)
|
||||
self.assertEqual(set(inventory_move_in_WH_stock.mapped('product_id')), set([self.product1, self.product2]))
|
||||
self.assertEqual(inventory_move_in_WH_stock.filtered(lambda l: l.product_id == self.product1).quantity_done, 2.0)
|
||||
self.assertEqual(inventory_move_in_WH_stock.filtered(lambda l: l.product_id == self.product2).quantity_done, 1.0)
|
||||
|
||||
inventory_move_in_shelf1 = inventory_moves.filtered(lambda l: l.location_dest_id == self.shelf1)
|
||||
self.assertEqual(len(inventory_move_in_shelf1), 1)
|
||||
self.assertEqual(inventory_move_in_shelf1.product_id, self.product2)
|
||||
self.assertEqual(inventory_move_in_shelf1.quantity_done, 1.0)
|
||||
|
||||
inventory_move_in_shelf2 = inventory_moves.filtered(lambda l: l.location_dest_id == self.shelf2)
|
||||
self.assertEqual(len(inventory_move_in_shelf2), 1)
|
||||
self.assertEqual(inventory_move_in_shelf2.product_id, self.product1)
|
||||
self.assertEqual(inventory_move_in_shelf2.quantity_done, 1.0)
|
||||
|
||||
def test_inventory_adjustment_tracked_product(self):
|
||||
""" Simulate the following actions:
|
||||
- Generate those lines with scan:
|
||||
productlot1 with a lot named lot1 (qty 2)
|
||||
productserial1 with serial1 (qty 1)
|
||||
productserial1 with serial2 (qty 1)
|
||||
productserial1 with serial3 (qty 1)
|
||||
productlot1 with a lot named lot2 (qty 1)
|
||||
productlot1 with a lot named lot3 (qty 1)
|
||||
- Validate
|
||||
"""
|
||||
self.clean_access_rights()
|
||||
grp_lot = self.env.ref('stock.group_production_lot')
|
||||
self.env.user.write({'groups_id': [(4, grp_lot.id, 0)]})
|
||||
|
||||
action_id = self.env.ref('stock_barcode.stock_barcode_action_main_menu')
|
||||
url = "/web#action=" + str(action_id.id)
|
||||
|
||||
self.start_tour(url, 'test_inventory_adjustment_tracked_product', login='admin', timeout=180)
|
||||
|
||||
inventory_moves = self.env['stock.move'].search([('product_id', 'in', [self.productlot1.id, self.productserial1.id]),
|
||||
('is_inventory', '=', True)])
|
||||
self.assertEqual(len(inventory_moves), 6)
|
||||
self.assertEqual(inventory_moves.mapped('state'), ['done', 'done', 'done', 'done', 'done', 'done'])
|
||||
|
||||
moves_with_lot = inventory_moves.filtered(lambda l: l.product_id == self.productlot1)
|
||||
mls_with_lot = self.env['stock.move.line']
|
||||
mls_with_sn = self.env['stock.move.line']
|
||||
for move in moves_with_lot:
|
||||
mls_with_lot |= move._get_move_lines()
|
||||
moves_with_sn = inventory_moves.filtered(lambda l: l.product_id == self.productserial1)
|
||||
for move in moves_with_sn:
|
||||
mls_with_sn |= move._get_move_lines()
|
||||
self.assertEqual(len(mls_with_lot), 3)
|
||||
self.assertEqual(len(mls_with_sn), 3)
|
||||
self.assertEqual(mls_with_lot.mapped('lot_id.name'), ['lot1', 'lot2', 'lot3'])
|
||||
self.assertEqual(mls_with_lot.filtered(lambda ml: ml.lot_id.name == 'lot1').qty_done, 3)
|
||||
self.assertEqual(mls_with_lot.filtered(lambda ml: ml.lot_id.name == 'lot2').qty_done, 1)
|
||||
self.assertEqual(mls_with_lot.filtered(lambda ml: ml.lot_id.name == 'lot3').qty_done, 1)
|
||||
self.assertEqual(set(mls_with_sn.mapped('lot_id.name')), set(['serial1', 'serial2', 'serial3']))
|
||||
|
||||
def test_inventory_nomenclature(self):
|
||||
""" Simulate scanning a product and its weight
|
||||
thanks to the barcode nomenclature """
|
||||
self.clean_access_rights()
|
||||
self.env.company.nomenclature_id = self.env.ref('barcodes.default_barcode_nomenclature')
|
||||
|
||||
product_weight = self.env['product.product'].create({
|
||||
'name': 'product_weight',
|
||||
'type': 'product',
|
||||
'categ_id': self.env.ref('product.product_category_all').id,
|
||||
'barcode': '2145631000000',
|
||||
})
|
||||
|
||||
action_id = self.env.ref('stock_barcode.stock_barcode_action_main_menu')
|
||||
url = "/web#action=" + str(action_id.id)
|
||||
|
||||
self.start_tour(url, 'test_inventory_nomenclature', login='admin', timeout=180)
|
||||
quantity = self.env['stock.move.line'].search([
|
||||
('product_id', '=', product_weight.id),
|
||||
('state', '=', 'done'),
|
||||
('location_id', '=', product_weight.property_stock_inventory.id),
|
||||
])
|
||||
|
||||
self.assertEqual(quantity.qty_done, 12.35)
|
||||
|
||||
def test_inventory_package(self):
|
||||
""" Simulate an adjustment where a package is scanned and edited """
|
||||
self.clean_access_rights()
|
||||
grp_pack = self.env.ref('stock.group_tracking_lot')
|
||||
self.env.user.write({'groups_id': [(4, grp_pack.id, 0)]})
|
||||
|
||||
pack = self.env['stock.quant.package'].create({
|
||||
'name': 'PACK001',
|
||||
})
|
||||
|
||||
self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 7, package_id=pack)
|
||||
self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 3, package_id=pack)
|
||||
|
||||
action_id = self.env.ref('stock_barcode.stock_barcode_action_main_menu')
|
||||
url = "/web#action=" + str(action_id.id)
|
||||
|
||||
self.start_tour(url, "test_inventory_package", login="admin", timeout=180)
|
||||
|
||||
# Check the package is updated after adjustment
|
||||
self.assertDictEqual(
|
||||
{q.product_id: q.quantity for q in pack.quant_ids},
|
||||
{self.product1: 7, self.product2: 21}
|
||||
)
|
||||
|
||||
def test_inventory_owner_scan_package(self):
|
||||
group_owner = self.env.ref('stock.group_tracking_owner')
|
||||
group_pack = self.env.ref('stock.group_tracking_lot')
|
||||
self.env.user.write({'groups_id': [(4, group_pack.id, 0)]})
|
||||
self.env.user.write({'groups_id': [(4, group_owner.id, 0)]})
|
||||
|
||||
self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 7, package_id=self.package, owner_id=self.owner)
|
||||
action_id = self.env.ref('stock_barcode.stock_barcode_action_main_menu')
|
||||
url = "/web#action=" + str(action_id.id)
|
||||
|
||||
self.start_tour(url, 'test_inventory_owner_scan_package', login='admin', timeout=180)
|
||||
|
||||
inventory_moves = self.env['stock.move'].search([('product_id', '=', self.product1.id), ('is_inventory', '=', True)])
|
||||
self.assertEqual(len(inventory_moves), 1)
|
||||
self.assertEqual(inventory_moves.state, 'done')
|
||||
self.assertEqual(inventory_moves._get_move_lines().owner_id.id, self.owner.id)
|
||||
|
||||
def test_inventory_using_buttons(self):
|
||||
""" Creates an inventory from scratch, then scans products and verifies
|
||||
the buttons behavior is right.
|
||||
"""
|
||||
# Adds some quantities for product2.
|
||||
self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 10)
|
||||
|
||||
action_id = self.env.ref('stock_barcode.stock_barcode_action_main_menu')
|
||||
url = "/web#action=" + str(action_id.id)
|
||||
|
||||
self.start_tour(url, 'test_inventory_using_buttons', login='admin', timeout=180)
|
||||
product1_quant = self.env['stock.quant'].search([
|
||||
('product_id', '=', self.product1.id),
|
||||
('quantity', '>', 0)
|
||||
])
|
||||
self.assertEqual(len(product1_quant), 1)
|
||||
self.assertEqual(product1_quant.quantity, 1.0)
|
||||
self.assertEqual(product1_quant.location_id.id, self.stock_location.id)
|
||||
|
||||
productlot1_quant = self.env['stock.quant'].search([
|
||||
('product_id', '=', self.productlot1.id),
|
||||
('quantity', '>', 0)
|
||||
])
|
||||
self.assertEqual(len(product1_quant), 1)
|
||||
self.assertEqual(productlot1_quant.quantity, 1.0)
|
||||
self.assertEqual(productlot1_quant.lot_id.name, 'toto-42')
|
||||
self.assertEqual(productlot1_quant.location_id.id, self.stock_location.id)
|
||||
|
||||
def test_gs1_inventory_gtin_8(self):
|
||||
""" Simulate scanning a product with his gs1 barcode """
|
||||
self.clean_access_rights()
|
||||
self.env.company.nomenclature_id = self.env.ref('barcodes_gs1_nomenclature.default_gs1_nomenclature')
|
||||
|
||||
product = self.env['product.product'].create({
|
||||
'name': 'PRO_GTIN_8',
|
||||
'type': 'product',
|
||||
'categ_id': self.env.ref('product.product_category_all').id,
|
||||
'barcode': '82655853', # GTIN-8 format
|
||||
'uom_id': self.env.ref('uom.product_uom_unit').id
|
||||
})
|
||||
|
||||
action_id = self.env.ref('stock_barcode.stock_barcode_action_main_menu')
|
||||
url = "/web#action=" + str(action_id.id)
|
||||
|
||||
self.start_tour(url, 'test_gs1_inventory_gtin_8', login='admin', timeout=180)
|
||||
|
||||
# Checks the inventory adjustment correclty created a move line.
|
||||
move_line = self.env['stock.move.line'].search([
|
||||
('product_id', '=', product.id),
|
||||
('state', '=', 'done'),
|
||||
('location_id', '=', product.property_stock_inventory.id),
|
||||
])
|
||||
self.assertEqual(move_line.qty_done, 78)
|
||||
|
||||
def test_gs1_inventory_product_units(self):
|
||||
""" Scans a product with a GS1 barcode containing multiple quantities."""
|
||||
self.clean_access_rights()
|
||||
self.env.company.nomenclature_id = self.env.ref('barcodes_gs1_nomenclature.default_gs1_nomenclature')
|
||||
|
||||
product = self.env['product.product'].create({
|
||||
'name': 'PRO_GTIN_8',
|
||||
'type': 'product',
|
||||
'categ_id': self.env.ref('product.product_category_all').id,
|
||||
'barcode': '82655853', # GTIN-8 format
|
||||
'uom_id': self.env.ref('uom.product_uom_unit').id
|
||||
})
|
||||
|
||||
action_id = self.env.ref('stock_barcode.stock_barcode_action_main_menu')
|
||||
url = "/web#action=" + str(action_id.id)
|
||||
|
||||
self.start_tour(url, 'test_gs1_inventory_product_units', login='admin', timeout=180)
|
||||
|
||||
quantity = self.env['stock.move.line'].search([
|
||||
('product_id', '=', product.id),
|
||||
('state', '=', 'done'),
|
||||
('location_id', '=', product.property_stock_inventory.id),
|
||||
])
|
||||
|
||||
self.assertEqual(quantity.qty_done, 102)
|
||||
|
||||
def test_gs1_inventory_package(self):
|
||||
""" Scans existing packages and checks their products are correclty added
|
||||
to the inventory adjustment. Then scans some products, scans a new package
|
||||
and checks the package was created and correclty assigned to those products.
|
||||
"""
|
||||
self.clean_access_rights()
|
||||
self.env.company.nomenclature_id = self.env.ref('barcodes_gs1_nomenclature.default_gs1_nomenclature')
|
||||
grp_multi_loc = self.env.ref('stock.group_stock_multi_locations')
|
||||
grp_pack = self.env.ref('stock.group_tracking_lot')
|
||||
self.env.user.write({'groups_id': [(4, grp_multi_loc.id, 0)]})
|
||||
self.env.user.write({'groups_id': [(4, grp_pack.id, 0)]})
|
||||
|
||||
product = self.env['product.product'].create({
|
||||
'name': 'PRO_GTIN_8',
|
||||
'type': 'product',
|
||||
'categ_id': self.env.ref('product.product_category_all').id,
|
||||
'barcode': '82655853', # GTIN-8 format
|
||||
'uom_id': self.env.ref('uom.product_uom_unit').id
|
||||
})
|
||||
|
||||
# Creates a first package in Section 1 and adds some products.
|
||||
pack_1 = self.env['stock.quant.package'].create({'name': '987654123487568456'})
|
||||
self.env['stock.quant']._update_available_quantity(self.product1, self.shelf1, 8, package_id=pack_1)
|
||||
# Creates a second package in Section 2 and adds some other products.
|
||||
pack_2 = self.env['stock.quant.package'].create({'name': '487325612456785124'})
|
||||
self.env['stock.quant']._update_available_quantity(self.product2, self.shelf2, 6, package_id=pack_2)
|
||||
|
||||
action_id = self.env.ref('stock_barcode.stock_barcode_action_main_menu')
|
||||
url = "/web#action=" + str(action_id.id)
|
||||
self.start_tour(url, 'test_gs1_inventory_package', login='admin', timeout=180)
|
||||
|
||||
pack_3 = self.env['stock.quant.package'].search([('name', '=', '122333444455555670')])
|
||||
self.assertEqual(pack_3.location_id.id, self.shelf2.id)
|
||||
self.assertEqual(pack_3.quant_ids.product_id.ids, [product.id])
|
||||
|
||||
def test_gs1_inventory_lot_serial(self):
|
||||
""" Checks tracking numbers and quantites are correctly got from GS1
|
||||
barcodes for tracked products."""
|
||||
self.clean_access_rights()
|
||||
self.env.company.nomenclature_id = self.env.ref('barcodes_gs1_nomenclature.default_gs1_nomenclature')
|
||||
|
||||
product_lot = self.env['product.product'].create({
|
||||
'name': 'PRO_GTIN_12_lot',
|
||||
'type': 'product',
|
||||
'categ_id': self.env.ref('product.product_category_all').id,
|
||||
'barcode': '111155555717', # GTIN-12 format
|
||||
'uom_id': self.env.ref('uom.product_uom_unit').id,
|
||||
'tracking': 'lot',
|
||||
})
|
||||
|
||||
product_serial = self.env['product.product'].create({
|
||||
'name': 'PRO_GTIN_14_serial',
|
||||
'type': 'product',
|
||||
'categ_id': self.env.ref('product.product_category_all').id,
|
||||
'barcode': '15222222222219', # GTIN-14 format
|
||||
'uom_id': self.env.ref('uom.product_uom_unit').id,
|
||||
'tracking': 'serial',
|
||||
})
|
||||
|
||||
action_id = self.env.ref('stock_barcode.stock_barcode_action_main_menu')
|
||||
url = "/web#action=" + str(action_id.id)
|
||||
self.start_tour(url, 'test_gs1_inventory_lot_serial', login='admin', timeout=180)
|
||||
|
||||
smls_lot = self.env['stock.move.line'].search([
|
||||
('product_id', '=', product_lot.id),
|
||||
('state', '=', 'done'),
|
||||
('location_id', '=', product_lot.property_stock_inventory.id),
|
||||
])
|
||||
self.assertEqual(len(smls_lot), 3)
|
||||
self.assertEqual(smls_lot[0].qty_done, 10)
|
||||
self.assertEqual(smls_lot[1].qty_done, 15)
|
||||
self.assertEqual(smls_lot[2].qty_done, 20)
|
||||
self.assertEqual(
|
||||
smls_lot.lot_id.mapped('name'),
|
||||
['LOT-AAA', 'LOT-AAB', 'LOT-AAC']
|
||||
)
|
||||
|
||||
smls_serial = self.env['stock.move.line'].search([
|
||||
('product_id', '=', product_serial.id),
|
||||
('state', '=', 'done'),
|
||||
('location_id', '=', product_serial.property_stock_inventory.id),
|
||||
])
|
||||
self.assertEqual(len(smls_serial), 5)
|
||||
self.assertEqual(smls_serial[0].qty_done, 1)
|
||||
self.assertEqual(smls_serial[1].qty_done, 1)
|
||||
self.assertEqual(smls_serial[2].qty_done, 1)
|
||||
self.assertEqual(smls_serial[3].qty_done, 20)
|
||||
self.assertEqual(smls_serial[4].qty_done, 1)
|
||||
self.assertEqual(
|
||||
smls_serial.lot_id.mapped('name'),
|
||||
['Serial1', 'Serial2', 'Serial3', 'Serial4']
|
||||
)
|
||||
2038
stock_barcode/tests/test_barcode_client_action_picking.py
Normal file
2038
stock_barcode/tests/test_barcode_client_action_picking.py
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user