[ADD] stock: bunch of tests

This commit is contained in:
Simon Lejeune
2017-07-14 17:08:21 +02:00
parent 809605bb8f
commit 10efaa91bc
7 changed files with 3629 additions and 0 deletions
+1
View File
@@ -19,6 +19,7 @@
'data/stock_demo.yml',
'data/stock_location_demo_cpu1.xml',
'data/stock_location_demo_cpu3.yml',
'data/stock_quant_demo.xml',
],
'data': [
'security/stock_security.xml',
+12
View File
@@ -0,0 +1,12 @@
<odoo>
<record id="test_quant_product" model="product.product">
<field name="name">Whiteboard</field>
<field name="type">product</field>
</record>
<record id="test_quant_quant" model="stock.quant">
<field name="product_id" ref="stock.test_quant_product"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="location_id" ref="stock_location_stock"/>
<field name="quantity">10.0</field>
</record>
</odoo>
+4
View File
@@ -5,3 +5,7 @@ from . import test_product
from . import test_warehouse
from . import test_shipment
from . import test_stock_location_search
from . import test_quant
from . import test_inventory
from . import test_move
from . import test_move2
+143
View File
@@ -0,0 +1,143 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase
class TestInventory(TransactionCase):
def setUp(self):
super(TestInventory, self).setUp()
self.stock_location = self.env.ref('stock.stock_location_stock')
self.uom_unit = self.env.ref('product.product_uom_unit')
self.product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
'categ_id': self.env.ref('product.product_category_all').id,
})
self.product2 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
'tracking': 'serial',
'categ_id': self.env.ref('product.product_category_all').id,
})
def test_inventory_1(self):
""" Check that making an inventory adjustment to remove all products from stock is working
as expected.
"""
# make some stock
self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 100)
self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.stock_location)), 1.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 100.0)
# remove them with an inventory adjustment
inventory = self.env['stock.inventory'].create({
'name': 'remove product1',
'filter': 'product',
'location_id': self.stock_location.id,
'product_id': self.product1.id,
})
inventory.prepare_inventory()
self.assertEqual(len(inventory.line_ids), 1)
self.assertEqual(inventory.line_ids.theoretical_qty, 100)
inventory.line_ids.product_qty = 0 # Put the quantity back to 0
inventory.action_done()
# check
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 0.0)
self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.stock_location)), 0.0)
def test_inventory_2(self):
""" Check that adding a tracked product through an inventory adjustment work as expected.
"""
inventory = self.env['stock.inventory'].create({
'name': 'remove product1',
'filter': 'product',
'location_id': self.stock_location.id,
'product_id': self.product2.id,
'exhausted': True, # should be set by an onchange
})
inventory.prepare_inventory()
self.assertEqual(len(inventory.line_ids), 1)
self.assertEqual(inventory.line_ids.theoretical_qty, 0)
lot1 = self.env['stock.production.lot'].create({
'name': 'sn2',
'product_id': self.product2.id,
})
inventory.line_ids.prod_lot_id = lot1
inventory.line_ids.product_qty = 1
inventory.action_done()
# check
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location, lot_id=lot1), 1.0)
self.assertEqual(len(self.env['stock.quant']._gather(self.product2, self.stock_location, lot_id=lot1)), 1.0)
self.assertEqual(lot1.product_qty, 1.0)
def test_inventory_3(self):
""" Check that it's not posisble to have multiple products with a serial number through an
inventory adjustment
"""
inventory = self.env['stock.inventory'].create({
'name': 'remove product1',
'filter': 'product',
'location_id': self.stock_location.id,
'product_id': self.product2.id,
'exhausted': True, # should be set by an onchange
})
inventory.prepare_inventory()
self.assertEqual(len(inventory.line_ids), 1)
self.assertEqual(inventory.line_ids.theoretical_qty, 0)
lot1 = self.env['stock.production.lot'].create({
'name': 'sn2',
'product_id': self.product2.id,
})
inventory.line_ids.prod_lot_id = lot1
inventory.line_ids.product_qty = 2
with self.assertRaises(ValidationError):
inventory.action_done()
def test_inventory_4(self):
""" Check that even if a product is tracked by serial number, it's possible to add
untracked one in an inventory adjustment.
"""
inventory = self.env['stock.inventory'].create({
'name': 'remove product1',
'filter': 'product',
'location_id': self.stock_location.id,
'product_id': self.product2.id,
'exhausted': True, # should be set by an onchange
})
inventory.prepare_inventory()
self.assertEqual(len(inventory.line_ids), 1)
self.assertEqual(inventory.line_ids.theoretical_qty, 0)
lot1 = self.env['stock.production.lot'].create({
'name': 'sn2',
'product_id': self.product2.id,
})
inventory.line_ids.prod_lot_id = lot1
inventory.line_ids.product_qty = 1
self.env['stock.inventory.line'].create({
'inventory_id': inventory.id,
'product_id': self.product2.id,
'product_uom_id': self.uom_unit.id,
'product_qty': 10,
'location_id': self.stock_location.id,
})
inventory.action_done()
# check
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location, lot_id=lot1, strict=True), 1.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location, strict=True), 10.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location), 11.0)
self.assertEqual(len(self.env['stock.quant']._gather(self.product2, self.stock_location, lot_id=lot1, strict=True)), 1.0)
self.assertEqual(len(self.env['stock.quant']._gather(self.product2, self.stock_location, strict=True)), 1.0)
self.assertEqual(len(self.env['stock.quant']._gather(self.product2, self.stock_location)), 2.0)
File diff suppressed because it is too large Load Diff
+701
View File
@@ -0,0 +1,701 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.stock.tests.common import TestStockCommon
class TestPickShip(TestStockCommon):
def create_pick_ship(self):
picking_client = self.env['stock.picking'].create({
'location_id': self.pack_location,
'location_dest_id': self.customer_location,
'partner_id': self.partner_delta_id,
'picking_type_id': self.picking_type_out,
})
dest = self.MoveObj.create({
'name': self.productA.name,
'product_id': self.productA.id,
'product_uom_qty': 10,
'product_uom': self.productA.uom_id.id,
'picking_id': picking_client.id,
'location_id': self.pack_location,
'location_dest_id': self.customer_location,
'state': 'waiting',
})
picking_pick = self.env['stock.picking'].create({
'location_id': self.stock_location,
'location_dest_id': self.pack_location,
'partner_id': self.partner_delta_id,
'picking_type_id': self.picking_type_out,
})
self.MoveObj.create({
'name': self.productA.name,
'product_id': self.productA.id,
'product_uom_qty': 10,
'product_uom': self.productA.uom_id.id,
'picking_id': picking_pick.id,
'location_id': self.stock_location,
'location_dest_id': self.pack_location,
'move_dest_ids': [(4, dest.id)],
'state': 'confirmed',
})
return picking_pick, picking_client
def test_mto_moves(self):
"""
10 in stock, do pick->ship and check ship is assigned when pick is done, then backorder of ship
"""
picking_pick, picking_client = self.create_pick_ship()
location = self.env['stock.location'].browse(self.stock_location)
# make some stock
self.env['stock.quant']._increase_available_quantity(self.productA, location, 10.0)
picking_pick.action_assign()
picking_pick.move_lines[0].pack_operation_ids[0].qty_done = 10.0
picking_pick.do_transfer()
self.assertEqual(picking_client.state, 'assigned', 'The state of the client should be assigned')
# Now partially transfer the ship
picking_client.move_lines[0].pack_operation_ids[0].qty_done = 5
picking_client.do_transfer() # no new in order to create backorder
backorder = self.env['stock.picking'].search([('backorder_id', '=', picking_client.id)])
self.assertEqual(backorder.state, 'assigned', 'Backorder should be started')
def test_mto_moves_transfer(self):
"""
10 in stock, 5 in pack. Make sure it does not assign the 5 pieces in pack
"""
picking_pick, picking_client = self.create_pick_ship()
stock_location = self.env['stock.location'].browse(self.stock_location)
self.env['stock.quant']._increase_available_quantity(self.productA, stock_location, 10.0)
pack_location = self.env['stock.location'].browse(self.pack_location)
self.env['stock.quant']._increase_available_quantity(self.productA, pack_location, 5.0)
self.assertEqual(len(self.env['stock.quant']._gather(self.productA, stock_location)), 1.0)
self.assertEqual(len(self.env['stock.quant']._gather(self.productA, pack_location)), 1.0)
(picking_pick + picking_client).action_assign()
move_pick = picking_pick.move_lines
move_cust = picking_client.move_lines
self.assertEqual(move_pick.state, 'assigned')
self.assertEqual(picking_pick.state, 'assigned')
self.assertEqual(move_cust.state, 'waiting')
self.assertEqual(picking_client.state, 'waiting', 'The picking should not assign what it does not have')
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, stock_location), 0.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location), 5.0)
move_pick.pack_operation_ids[0].qty_done = 10.0
picking_pick.do_transfer()
self.assertEqual(move_pick.state, 'done')
self.assertEqual(picking_pick.state, 'done')
self.assertEqual(move_cust.state, 'assigned')
self.assertEqual(picking_client.state, 'assigned', 'The picking should not assign what it does not have')
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, stock_location), 0.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location), 5.0)
self.assertEqual(len(self.env['stock.quant']._gather(self.productA, stock_location)), 0.0)
self.assertEqual(len(self.env['stock.quant']._gather(self.productA, pack_location)), 1.0)
def test_mto_moves_return(self):
picking_pick, picking_client = self.create_pick_ship()
stock_location = self.env['stock.location'].browse(self.stock_location)
self.env['stock.quant']._increase_available_quantity(self.productA, stock_location, 10.0)
picking_pick.action_assign()
picking_pick.move_lines[0].pack_operation_ids[0].qty_done = 10.0
picking_pick.do_transfer()
self.assertEqual(picking_pick.state, 'done')
self.assertEqual(picking_client.state, 'assigned')
# return a part of what we've done
stock_return_picking = self.env['stock.return.picking']\
.with_context(active_ids=picking_pick.ids, active_id=picking_pick.ids[0])\
.create({})
stock_return_picking.product_return_moves.quantity = 2.0 # Return only 2
stock_return_picking_action = stock_return_picking.create_returns()
return_pick = self.env['stock.picking'].browse(stock_return_picking_action['res_id'])
return_pick.move_lines[0].pack_operation_ids[0].qty_done = 2.0
return_pick.do_transfer()
# the client picking should not be assigned anymore, as we returned partially what we took
self.assertEqual(picking_client.state, 'confirmed')
def test_no_backorder_1(self):
""" Check the behavior of doing less than asked in the picking pick and chosing not to
create a backorder. In this behavior, the second picking should obviously only be able to
reserve what was brought, but its initial demand should stay the same and the system will
ask the user will have to consider again if he wants to create a backorder or not.
"""
picking_pick, picking_client = self.create_pick_ship()
location = self.env['stock.location'].browse(self.stock_location)
# make some stock
self.env['stock.quant']._increase_available_quantity(self.productA, location, 10.0)
picking_pick.action_assign()
picking_pick.move_lines[0].pack_operation_ids[0].qty_done = 5.0
# create a backorder
picking_pick.do_transfer()
picking_pick_backorder = self.env['stock.picking'].search([('backorder_id', '=', picking_pick.id)])
self.assertEqual(picking_pick_backorder.state, 'assigned')
self.assertEqual(picking_pick_backorder.pack_operation_ids.product_qty, 5.0)
self.assertEqual(picking_client.state, 'partially_available')
# cancel the backorder
picking_pick_backorder.action_cancel()
self.assertEqual(picking_client.state, 'partially_available')
def test_edit_done_chained_move(self):
""" Let’s say two moves are chained: the first is done and the second is assigned.
Editing the move line of the first move should impact the reservation of the second one.
"""
picking_pick, picking_client = self.create_pick_ship()
location = self.env['stock.location'].browse(self.stock_location)
# make some stock
self.env['stock.quant']._increase_available_quantity(self.productA, location, 10.0)
picking_pick.action_assign()
picking_pick.move_lines[0].move_line_ids[0].qty_done = 10.0
picking_pick.action_done()
self.assertEqual(picking_pick.state, 'done', 'The state of the pick should be done')
self.assertEqual(picking_client.state, 'assigned', 'The state of the client should be assigned')
self.assertEqual(picking_pick.move_lines.quantity_done, 10.0, 'Wrong quantity_done for pick move')
self.assertEqual(picking_client.move_lines.product_qty, 10.0, 'Wrong initial demand for client move')
self.assertEqual(picking_client.move_lines.reserved_availability, 10.0, 'Wrong quantity already reserved for client move')
picking_pick.move_lines[0].move_line_ids[0].qty_done = 5.0
self.assertEqual(picking_pick.state, 'done', 'The state of the pick should be done')
self.assertEqual(picking_client.state, 'partially_available', 'The state of the client should be partially available')
self.assertEqual(picking_pick.move_lines.quantity_done, 5.0, 'Wrong quantity_done for pick move')
self.assertEqual(picking_client.move_lines.product_qty, 10.0, 'Wrong initial demand for client move')
self.assertEqual(picking_client.move_lines.reserved_availability, 5.0, 'Wrong quantity already reserved for client move')
# Check if run action_assign does not crash
picking_client.action_assign()
def test_edit_done_chained_move_with_lot(self):
""" Let’s say two moves are chained: the first is done and the second is assigned.
Editing the lot on the move line of the first move should impact the reservation of the second one.
"""
self.productA.tracking = 'lot'
lot1 = self.env['stock.production.lot'].create({
'name': 'lot1',
'product_id': self.productA.id,
})
lot2 = self.env['stock.production.lot'].create({
'name': 'lot2',
'product_id': self.productA.id,
})
picking_pick, picking_client = self.create_pick_ship()
location = self.env['stock.location'].browse(self.stock_location)
# make some stock
self.env['stock.quant']._increase_available_quantity(self.productA, location, 10.0)
picking_pick.action_assign()
picking_pick.move_lines[0].move_line_ids[0].write({
'qty_done': 10.0,
'lot_id': lot1.id,
})
picking_pick.action_done()
self.assertEqual(picking_pick.state, 'done', 'The state of the pick should be done')
self.assertEqual(picking_client.state, 'assigned', 'The state of the client should be assigned')
self.assertEqual(picking_pick.move_lines.quantity_done, 10.0, 'Wrong quantity_done for pick move')
self.assertEqual(picking_client.move_lines.product_qty, 10.0, 'Wrong initial demand for client move')
self.assertEqual(picking_client.move_lines.move_line_ids.lot_id, lot1, 'Wrong lot for client move line')
self.assertEqual(picking_client.move_lines.reserved_availability, 10.0, 'Wrong quantity already reserved for client move')
picking_pick.move_lines[0].move_line_ids[0].lot_id = lot2.id
self.assertEqual(picking_pick.state, 'done', 'The state of the pick should be done')
self.assertEqual(picking_client.state, 'assigned', 'The state of the client should be partially available')
self.assertEqual(picking_pick.move_lines.quantity_done, 10.0, 'Wrong quantity_done for pick move')
self.assertEqual(picking_client.move_lines.product_qty, 10.0, 'Wrong initial demand for client move')
self.assertEqual(picking_client.move_lines.move_line_ids.lot_id, lot2, 'Wrong lot for client move line')
self.assertEqual(picking_client.move_lines.reserved_availability, 10.0, 'Wrong quantity already reserved for client move')
# Check if run action_assign does not crash
picking_client.action_assign()
class TestSinglePicking(TestStockCommon):
def test_backorder_1(self):
""" Check the good behavior of creating a backorder for an available stock move.
"""
delivery_order = self.env['stock.picking'].create({
'location_id': self.pack_location,
'location_dest_id': self.customer_location,
'partner_id': self.partner_delta_id,
'picking_type_id': self.picking_type_out,
})
self.MoveObj.create({
'name': self.productA.name,
'product_id': self.productA.id,
'product_uom_qty': 2,
'product_uom': self.productA.uom_id.id,
'picking_id': delivery_order.id,
'location_id': self.pack_location,
'location_dest_id': self.customer_location,
})
# make some stock
pack_location = self.env['stock.location'].browse(self.pack_location)
self.env['stock.quant']._increase_available_quantity(self.productA, pack_location, 2)
# assign
delivery_order.action_confirm()
delivery_order.action_assign()
self.assertEqual(delivery_order.state, 'assigned')
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location), 0.0)
# valid with backorder creation
delivery_order.move_lines[0].pack_operation_ids[0].qty_done = 1
delivery_order.do_transfer()
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location), 0.0)
backorder = self.env['stock.picking'].search([('backorder_id', '=', delivery_order.id)])
self.assertEqual(backorder.state, 'assigned')
def test_backorder_2(self):
""" Check the good behavior of creating a backorder for a partially available stock move.
"""
delivery_order = self.env['stock.picking'].create({
'location_id': self.pack_location,
'location_dest_id': self.customer_location,
'partner_id': self.partner_delta_id,
'picking_type_id': self.picking_type_out,
})
self.MoveObj.create({
'name': self.productA.name,
'product_id': self.productA.id,
'product_uom_qty': 2,
'product_uom': self.productA.uom_id.id,
'picking_id': delivery_order.id,
'location_id': self.pack_location,
'location_dest_id': self.customer_location,
})
# make some stock
pack_location = self.env['stock.location'].browse(self.pack_location)
self.env['stock.quant']._increase_available_quantity(self.productA, pack_location, 1)
# assign to partially available
delivery_order.action_confirm()
delivery_order.action_assign()
self.assertEqual(delivery_order.state, 'partially_available')
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location), 0.0)
# valid with backorder creation
delivery_order.move_lines[0].pack_operation_ids[0].qty_done = 1
delivery_order.do_transfer()
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location), 0.0)
backorder = self.env['stock.picking'].search([('backorder_id', '=', delivery_order.id)])
self.assertEqual(backorder.state, 'confirmed')
def test_extra_move_1(self):
""" Check the good behavior of creating an extra move in a delivery order. This usecase
simulates the delivery of 2 item while the initial stock move had to move 1 and there's
only 1 in stock.
"""
delivery_order = self.env['stock.picking'].create({
'location_id': self.pack_location,
'location_dest_id': self.customer_location,
'partner_id': self.partner_delta_id,
'picking_type_id': self.picking_type_out,
})
move1 = self.MoveObj.create({
'name': self.productA.name,
'product_id': self.productA.id,
'product_uom_qty': 1,
'product_uom': self.productA.uom_id.id,
'picking_id': delivery_order.id,
'location_id': self.pack_location,
'location_dest_id': self.customer_location,
})
# make some stock
pack_location = self.env['stock.location'].browse(self.pack_location)
self.env['stock.quant']._increase_available_quantity(self.productA, pack_location, 1)
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location), 1.0)
# assign to available
delivery_order.action_confirm()
delivery_order.action_assign()
self.assertEqual(delivery_order.state, 'assigned')
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location), 0.0)
# valid with backorder creation
delivery_order.move_lines[0].pack_operation_ids[0].qty_done = 2
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location), 0.0)
delivery_order.with_context(debug=True).do_transfer()
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location), -1.0)
extra_move = delivery_order.move_lines - move1
extra_move_line = extra_move.pack_operation_ids[0]
# self.assertEqual(move1.product_qty, 1.0)
# self.assertEqual(move1.quantity_done, 1.0)
self.assertEqual(move1.reserved_availability, 1.0)
self.assertEqual(move1.pack_operation_ids.product_qty, 1.0) # should keep the reservation
self.assertEqual(move1.pack_operation_ids.qty_done, 1.0)
self.assertEqual(move1.state, 'done')
self.assertEqual(extra_move.product_qty, 1.0)
self.assertEqual(extra_move.quantity_done, 1.0)
self.assertEqual(extra_move.reserved_availability, 0.0)
self.assertEqual(extra_move_line.product_qty, 0.0) # should not be able to reserve
self.assertEqual(extra_move_line.qty_done, 1.0)
self.assertEqual(extra_move.state, 'done')
def test_extra_move_2(self):
""" Check the good behavior of creating an extra move in a delivery order. This usecase
simulates the delivery of 3 item while the initial stock move had to move 1 and there's
only 1 in stock.
"""
delivery_order = self.env['stock.picking'].create({
'location_id': self.pack_location,
'location_dest_id': self.customer_location,
'partner_id': self.partner_delta_id,
'picking_type_id': self.picking_type_out,
})
move1 = self.MoveObj.create({
'name': self.productA.name,
'product_id': self.productA.id,
'product_uom_qty': 1,
'product_uom': self.productA.uom_id.id,
'picking_id': delivery_order.id,
'location_id': self.pack_location,
'location_dest_id': self.customer_location,
})
# make some stock
pack_location = self.env['stock.location'].browse(self.pack_location)
self.env['stock.quant']._increase_available_quantity(self.productA, pack_location, 1)
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location), 1.0)
# assign to available
delivery_order.action_confirm()
delivery_order.action_assign()
self.assertEqual(delivery_order.state, 'assigned')
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location), 0.0)
# valid with backorder creation
delivery_order.move_lines[0].pack_operation_ids[0].qty_done = 3
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location), 0.0)
delivery_order.do_transfer()
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location), -2.0)
extra_move = delivery_order.move_lines - move1
extra_move_line = extra_move.pack_operation_ids[0]
self.assertEqual(move1.product_qty, 1.0)
self.assertEqual(move1.quantity_done, 1.0)
self.assertEqual(move1.reserved_availability, 1.0)
self.assertEqual(move1.pack_operation_ids.product_qty, 1.0) # should keep the reservation
self.assertEqual(move1.pack_operation_ids.qty_done, 1.0)
self.assertEqual(move1.state, 'done')
self.assertEqual(extra_move.product_qty, 2.0)
self.assertEqual(extra_move.quantity_done, 2.0)
self.assertEqual(extra_move.reserved_availability, 0.0)
self.assertEqual(extra_move_line.product_qty, 0.0) # should not be able to reserve
self.assertEqual(extra_move_line.qty_done, 2.0)
self.assertEqual(extra_move.state, 'done')
def test_extra_move_3(self):
""" Check the good behavior of creating an extra move in a receipt. This usecase simulates
the receipt of 2 item while the initial stock move had to move 1.
"""
receipt = self.env['stock.picking'].create({
'location_id': self.supplier_location,
'location_dest_id': self.stock_location,
'partner_id': self.partner_delta_id,
'picking_type_id': self.picking_type_in,
})
move1 = self.MoveObj.create({
'name': self.productA.name,
'product_id': self.productA.id,
'product_uom_qty': 1,
'product_uom': self.productA.uom_id.id,
'picking_id': receipt.id,
'location_id': self.supplier_location,
'location_dest_id': self.stock_location,
})
stock_location = self.env['stock.location'].browse(self.stock_location)
# assign to available
receipt.action_confirm()
receipt.action_assign()
self.assertEqual(receipt.state, 'assigned')
# valid with backorder creation
receipt.move_lines[0].pack_operation_ids[0].qty_done = 2
receipt.with_context(debug=True).do_transfer()
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, stock_location), 2.0)
extra_move = receipt.move_lines - move1
extra_move_line = extra_move.pack_operation_ids[0]
self.assertEqual(move1.product_qty, 1.0)
self.assertEqual(move1.quantity_done, 1.0)
self.assertEqual(move1.reserved_availability, 1.0)
self.assertEqual(move1.pack_operation_ids.product_qty, 1.0) # should keep the reservation
self.assertEqual(move1.pack_operation_ids.qty_done, 1.0)
self.assertEqual(move1.state, 'done')
self.assertEqual(extra_move.product_qty, 1.0)
self.assertEqual(extra_move.quantity_done, 1.0)
self.assertEqual(extra_move.reserved_availability, 0.0)
self.assertEqual(extra_move_line.product_qty, 0.0) # should not be able to reserve
self.assertEqual(extra_move_line.qty_done, 1.0)
self.assertEqual(extra_move.state, 'done')
def test_recheck_availability_1(self):
""" Check the good behavior of check availability. I create a DO for 2 unit with
only one in stock. After the first check availability, I should have 1 reserved
product with one move line. After adding a second unit in stock and recheck availability.
The DO should have 2 reserved unit, be in available state and have only one move line.
"""
self.env['stock.quant']._increase_available_quantity(self.productA, self.env['stock.location'].browse(self.stock_location), 1.0)
delivery_order = self.env['stock.picking'].create({
'location_id': self.stock_location,
'location_dest_id': self.customer_location,
'partner_id': self.partner_delta_id,
'picking_type_id': self.picking_type_out,
})
move1 = self.MoveObj.create({
'name': self.productA.name,
'product_id': self.productA.id,
'product_uom_qty': 2,
'product_uom': self.productA.uom_id.id,
'picking_id': delivery_order.id,
'location_id': self.stock_location,
'location_dest_id': self.customer_location,
})
delivery_order.action_confirm()
delivery_order.action_assign()
# Check State
self.assertEqual(delivery_order.state, 'partially_available')
self.assertEqual(move1.state, 'partially_available')
# Check reserved quantity
self.assertEqual(move1.reserved_availability, 1.0)
self.assertEqual(len(move1.pack_operation_ids), 1)
self.assertEqual(move1.pack_operation_ids.product_qty, 1)
inventory = self.env['stock.inventory'].create({
'name': 'remove product1',
'filter': 'product',
'location_id': self.stock_location,
'product_id': self.productA.id,
})
inventory.prepare_inventory()
inventory.line_ids.product_qty = 2
inventory.action_done()
delivery_order.action_assign()
self.assertEqual(delivery_order.state, 'assigned')
self.assertEqual(move1.state, 'assigned')
# Check reserved quantity
self.assertEqual(move1.reserved_availability, 2.0)
self.assertEqual(len(move1.pack_operation_ids), 1)
self.assertEqual(move1.pack_operation_ids.product_qty, 2)
def test_recheck_availability_2(self):
""" Same check than test_recheck_availability_1 but with lot this time.
If the new product has the same lot that already reserved one, the move lines
reserved quantity should be updated.
Otherwise a new move lines with the new lot should be added.
"""
self.productA.tracking = 'lot'
lot1 = self.env['stock.production.lot'].create({
'name': 'lot1',
'product_id': self.productA.id,
})
stock_location = self.env['stock.location'].browse(self.stock_location)
self.env['stock.quant']._increase_available_quantity(self.productA, stock_location, 1.0, lot_id=lot1)
delivery_order = self.env['stock.picking'].create({
'location_id': self.stock_location,
'location_dest_id': self.customer_location,
'partner_id': self.partner_delta_id,
'picking_type_id': self.picking_type_out,
})
move1 = self.MoveObj.create({
'name': self.productA.name,
'product_id': self.productA.id,
'product_uom_qty': 2,
'product_uom': self.productA.uom_id.id,
'picking_id': delivery_order.id,
'location_id': self.stock_location,
'location_dest_id': self.customer_location,
})
delivery_order.action_confirm()
delivery_order.action_assign()
# Check State
self.assertEqual(delivery_order.state, 'partially_available')
self.assertEqual(move1.state, 'partially_available')
# Check reserved quantity
self.assertEqual(move1.reserved_availability, 1.0)
self.assertEqual(len(move1.pack_operation_ids), 1)
self.assertEqual(move1.pack_operation_ids.product_qty, 1)
inventory = self.env['stock.inventory'].create({
'name': 'remove product1',
'filter': 'product',
'location_id': self.stock_location,
'product_id': self.productA.id,
})
inventory.prepare_inventory()
inventory.line_ids.prod_lot_id = lot1
inventory.line_ids.product_qty = 2
inventory.action_done()
delivery_order.action_assign()
self.assertEqual(delivery_order.state, 'assigned')
self.assertEqual(move1.state, 'assigned')
# Check reserved quantity
self.assertEqual(move1.reserved_availability, 2.0)
self.assertEqual(len(move1.pack_operation_ids), 1)
self.assertEqual(move1.pack_operation_ids.lot_id.id, lot1.id)
self.assertEqual(move1.pack_operation_ids.product_qty, 2)
def test_recheck_availability_3(self):
""" Same check than test_recheck_availability_2 but with different lots.
"""
self.productA.tracking = 'lot'
lot1 = self.env['stock.production.lot'].create({
'name': 'lot1',
'product_id': self.productA.id,
})
lot2 = self.env['stock.production.lot'].create({
'name': 'lot2',
'product_id': self.productA.id,
})
stock_location = self.env['stock.location'].browse(self.stock_location)
self.env['stock.quant']._increase_available_quantity(self.productA, stock_location, 1.0, lot_id=lot1)
delivery_order = self.env['stock.picking'].create({
'location_id': self.stock_location,
'location_dest_id': self.customer_location,
'partner_id': self.partner_delta_id,
'picking_type_id': self.picking_type_out,
})
move1 = self.MoveObj.create({
'name': self.productA.name,
'product_id': self.productA.id,
'product_uom_qty': 2,
'product_uom': self.productA.uom_id.id,
'picking_id': delivery_order.id,
'location_id': self.stock_location,
'location_dest_id': self.customer_location,
})
delivery_order.action_confirm()
delivery_order.action_assign()
# Check State
self.assertEqual(delivery_order.state, 'partially_available')
self.assertEqual(move1.state, 'partially_available')
# Check reserved quantity
self.assertEqual(move1.reserved_availability, 1.0)
self.assertEqual(len(move1.pack_operation_ids), 1)
self.assertEqual(move1.pack_operation_ids.product_qty, 1)
inventory = self.env['stock.inventory'].create({
'name': 'remove product1',
'filter': 'product',
'location_id': self.stock_location,
'product_id': self.productA.id,
})
inventory.prepare_inventory()
self.env['stock.inventory.line'].create({
'inventory_id': inventory.id,
'location_id': inventory.location_id.id,
'partner_id': inventory.partner_id.id,
'prod_lot_id': lot2.id,
'product_id': self.productA.id,
'product_qty': 1,
})
inventory.action_done()
delivery_order.action_assign()
self.assertEqual(delivery_order.state, 'assigned')
self.assertEqual(move1.state, 'assigned')
# Check reserved quantity
self.assertEqual(move1.reserved_availability, 2.0)
self.assertEqual(len(move1.pack_operation_ids), 2)
self.assertEqual(move1.pack_operation_ids[0].lot_id.id, lot1.id)
self.assertEqual(move1.pack_operation_ids[1].lot_id.id, lot2.id)
def test_recheck_availability_4(self):
""" Same check than test_recheck_availability_2 but with serial number this time.
Serial number reservation should always create a new move line.
"""
self.productA.tracking = 'serial'
serial1 = self.env['stock.production.lot'].create({
'name': 'serial1',
'product_id': self.productA.id,
})
serial2 = self.env['stock.production.lot'].create({
'name': 'serial2',
'product_id': self.productA.id,
})
stock_location = self.env['stock.location'].browse(self.stock_location)
self.env['stock.quant']._increase_available_quantity(self.productA, stock_location, 1.0, lot_id=serial1)
delivery_order = self.env['stock.picking'].create({
'location_id': self.stock_location,
'location_dest_id': self.customer_location,
'partner_id': self.partner_delta_id,
'picking_type_id': self.picking_type_out,
})
move1 = self.MoveObj.create({
'name': self.productA.name,
'product_id': self.productA.id,
'product_uom_qty': 2,
'product_uom': self.productA.uom_id.id,
'picking_id': delivery_order.id,
'location_id': self.stock_location,
'location_dest_id': self.customer_location,
})
delivery_order.action_confirm()
delivery_order.action_assign()
# Check State
self.assertEqual(delivery_order.state, 'partially_available')
self.assertEqual(move1.state, 'partially_available')
# Check reserved quantity
self.assertEqual(move1.reserved_availability, 1.0)
self.assertEqual(len(move1.pack_operation_ids), 1)
self.assertEqual(move1.pack_operation_ids.product_qty, 1)
inventory = self.env['stock.inventory'].create({
'name': 'remove product1',
'filter': 'product',
'location_id': self.stock_location,
'product_id': self.productA.id,
})
inventory.prepare_inventory()
self.env['stock.inventory.line'].create({
'inventory_id': inventory.id,
'location_id': inventory.location_id.id,
'partner_id': inventory.partner_id.id,
'prod_lot_id': serial2.id,
'product_id': self.productA.id,
'product_qty': 1,
})
inventory.action_done()
delivery_order.action_assign()
self.assertEqual(delivery_order.state, 'assigned')
self.assertEqual(move1.state, 'assigned')
# Check reserved quantity
self.assertEqual(move1.reserved_availability, 2.0)
self.assertEqual(len(move1.pack_operation_ids), 2)
self.assertEqual(move1.pack_operation_ids[0].lot_id.id, serial1.id)
self.assertEqual(move1.pack_operation_ids[1].lot_id.id, serial2.id)
+564
View File
@@ -0,0 +1,564 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase
from odoo.exceptions import AccessError, UserError
class StockQuant(TransactionCase):
def setUp(self):
super(StockQuant, self).setUp()
Users = self.env['res.users'].with_context({'no_reset_password': True, 'mail_create_nosubscribe': True})
self.demo_user = Users.create({
'name': 'Pauline Poivraisselle',
'login': 'pauline',
'email': 'p.p@example.com',
'notification_type': 'inbox',
'groups_id': [(6, 0, [self.env.ref('base.group_user').id])]
})
self.stock_user = Users.create({
'name': 'Pauline Poivraisselle',
'login': 'pauline2',
'email': 'p.p@example.com',
'notification_type': 'inbox',
'groups_id': [(6, 0, [self.env.ref('stock.group_stock_user').id])]
})
def test_get_available_quantity_1(self):
""" Quantity availability with only one quant in a location.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 1.0,
})
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 1.0)
def test_get_available_quantity_2(self):
""" Quantity availability with multiple quants in a location.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
for i in range(3):
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 1.0,
})
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 3.0)
def test_get_available_quantity_3(self):
""" Quantity availability with multiple quants (including negatives ones) in a location.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
for i in range(3):
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 1.0,
})
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': -3.0,
})
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0)
def test_get_available_quantity_4(self):
""" Quantity availability with no quants in a location.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0)
def test_get_available_quantity_5(self):
""" Quantity availability with multiple partially reserved quants in a location.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 10.0,
'reserved_quantity': 9.0,
})
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 1.0,
'reserved_quantity': 1.0,
})
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 1.0)
def test_get_available_quantity_6(self):
""" Quantity availability with multiple partially reserved quants in a location.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 10.0,
'reserved_quantity': 20.0,
})
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 5.0,
'reserved_quantity': 0.0,
})
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), -5.0)
def test_get_available_quantity_7(self):
""" Quantity availability with only one tracked quant in a location.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
'tracking': 'lot',
})
lot1 = self.env['stock.production.lot'].create({
'name': 'lot1',
'product_id': product1.id,
})
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 10.0,
'reserved_quantity': 20.0,
'lot_id': lot1.id,
})
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location, lot_id=lot1), -10.0)
def test_get_available_quantity_8(self):
""" Quantity availability with a consumable product.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'consu',
})
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0)
self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 0)
with self.assertRaises(ValidationError):
self.env['stock.quant']._increase_available_quantity(product1, stock_location, 1.0)
def test_get_available_quantity_9(self):
""" Quantity availability by a demo user with access rights/rules.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 1.0,
})
self.env = self.env(user=self.env.ref('base.user_demo'))
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 1.0)
def test_increase_available_quantity_1(self):
""" Increase the available quantity when no quants are already in a location.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
self.env['stock.quant']._increase_available_quantity(product1, stock_location, 1.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 1.0)
def test_increase_available_quantity_2(self):
""" Increase the available quantity when multiple quants are already in a location.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
for i in range(2):
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 1.0,
})
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 2.0)
self.env['stock.quant']._increase_available_quantity(product1, stock_location, 1.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 3.0)
self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 2)
def test_increase_available_quantity_3(self):
""" Increase the available quantity when a concurrent transaction is already increasing
the reserved quanntity for the same product.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product = self.env.ref('stock.test_quant_product')
product.type = 'product' # product 12 is a consumable by default
self.assertEqual(self.env['stock.quant']._get_available_quantity(product, stock_location), 10.0)
# opens a new cursor and SELECT FOR UPDATE the quant, to simulate another concurrent reserved
# quantity increase
cr2 = self.registry.cursor()
cr2.execute("SELECT id FROM stock_quant WHERE product_id=%s AND location_id=%s", (product.id, stock_location.id))
quant_id = cr2.fetchone()
cr2.execute("SELECT 1 FROM stock_quant WHERE id=%s FOR UPDATE", quant_id)
self.env['stock.quant']._increase_available_quantity(product, stock_location, 1.0)
cr2.rollback()
cr2.close()
self.assertEqual(self.env['stock.quant']._get_available_quantity(product, stock_location), 11.0)
self.assertEqual(len(self.env['stock.quant']._gather(product, stock_location)), 2)
def test_increase_available_quantity_4(self):
""" Increase the available quantity when no quants are already in a location with a user without access right.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
self.env = self.env(user=self.env.ref('base.user_demo'))
self.env['stock.quant']._increase_available_quantity(product1, stock_location, 1.0)
def test_decrease_available_quantity_1(self):
""" Decrease the available quantity when no quants are already in a location.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
self.env['stock.quant']._decrease_available_quantity(product1, stock_location, 1.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), -1.0)
def test_decrease_available_quantity_2(self):
""" Decrease the available quantity when multiple quants are already in a location.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
for i in range(2):
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 1.0,
})
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 2.0)
self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 2)
self.env['stock.quant']._decrease_available_quantity(product1, stock_location, 1.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 1.0)
self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 1)
def test_decrease_available_quantity_3(self):
""" Decrease the available quantity when a concurrent transaction is already increasing
the reserved quanntity for the same product.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product = self.env.ref('stock.test_quant_product')
self.assertEqual(self.env['stock.quant']._get_available_quantity(product, stock_location), 10.0)
quants = self.env['stock.quant']._gather(product, stock_location)
self.assertEqual(len(quants), 1)
# opens a new cursor and SELECT FOR UPDATE the quant, to simulate another concurrent reserved
# quantity increase
cr2 = self.registry.cursor()
cr2.execute("SELECT 1 FROM stock_quant WHERE id = %s FOR UPDATE", quants.ids)
self.env['stock.quant']._decrease_available_quantity(product, stock_location, 1.0)
cr2.rollback()
cr2.close()
self.assertEqual(self.env['stock.quant']._get_available_quantity(product, stock_location), 9.0)
self.assertEqual(len(self.env['stock.quant']._gather(product, stock_location)), 2)
def test_decrease_available_quantity_4(self):
""" Decrease the available quantity that delete the quant. The active user should have
read,write and unlink rights
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 1.0,
})
self.env = self.env(user=self.demo_user)
self.env['stock.quant']._decrease_available_quantity(product1, stock_location, 1.0)
self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 0)
def test_increase_reserved_quantity_1(self):
""" Increase the reserved quantity of quantity x when there's a single quant in a given
location which has an available quantity of x.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 10.0,
})
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 10.0)
self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 1)
self.env['stock.quant']._increase_reserved_quantity(product1, stock_location, 10.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0)
self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 1)
def test_increase_reserved_quantity_2(self):
""" Increase the reserved quantity of quantity x when there's two quants in a given
location which have an available quantity of x together.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
for i in range(2):
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 5.0,
})
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 10.0)
self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 2)
self.env['stock.quant']._increase_reserved_quantity(product1, stock_location, 10.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0)
self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 2)
def test_increase_reserved_quantity_3(self):
""" Increase the reserved quantity of quantity x when there's multiple quants in a given
location which have an available quantity of x together.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 5.0,
'reserved_quantity': 2.0,
})
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 10.0,
'reserved_quantity': 12.0,
})
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 8.0,
'reserved_quantity': 3.0,
})
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 35.0,
'reserved_quantity': 12.0,
})
# total quantity: 58
# total reserved quantity: 29
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 29.0)
self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 4)
self.env['stock.quant']._increase_reserved_quantity(product1, stock_location, 10.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 19.0)
self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 4)
def test_increase_reserved_quantity_4(self):
""" Increase the reserved quantity of quantity x when there's multiple quants in a given
location which have an available quantity of x together.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 5.0,
'reserved_quantity': 7.0,
})
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 12.0,
'reserved_quantity': 10.0,
})
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0)
self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 2)
with self.assertRaises(UserError):
self.env['stock.quant']._increase_reserved_quantity(product1, stock_location, 10.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0)
def test_increase_reserved_quantity_5(self):
""" Decrease the available quantity when no quant are in a location.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
with self.assertRaises(UserError):
self.env['stock.quant']._increase_reserved_quantity(product1, stock_location, 1.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0)
def test_decrease_reserved_quantity_1(self):
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 10.0,
'reserved_quantity': 10.0,
})
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0)
self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 1)
self.env['stock.quant']._decrease_reserved_quantity(product1, stock_location, 10.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 10.0)
self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 1)
def test_increase_decrease_reserved_quantity_1(self):
""" Decrease then increase reserved quantity when no quant are in a location.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
with self.assertRaises(UserError):
self.env['stock.quant']._increase_reserved_quantity(product1, stock_location, 1.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0)
with self.assertRaises(UserError):
self.env['stock.quant']._decrease_reserved_quantity(product1, stock_location, 1.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0)
def test_action_done_1(self):
stock_location = self.env.ref('stock.stock_location_stock')
pack_location = self.env.ref('stock.location_pack_zone')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
self.env['stock.quant']._increase_available_quantity(product1, stock_location, 2.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 2.0)
self.env['stock.quant']._increase_reserved_quantity(product1, stock_location, 2.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0)
self.env['stock.quant']._decrease_reserved_quantity(product1, stock_location, 2.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 2.0)
self.env['stock.quant']._decrease_available_quantity(product1, stock_location, 2.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0)
self.env['stock.quant']._increase_available_quantity(product1, pack_location, 2.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, pack_location), 2.0)
def test_mix_tracked_untracked_1(self):
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
'tracking': 'serial',
})
lot1 = self.env['stock.production.lot'].create({
'name': 'lot1',
'product_id': product1.id,
})
# add one tracked, one untracked
self.env['stock.quant']._increase_available_quantity(product1, stock_location, 1.0)
self.env['stock.quant']._increase_available_quantity(product1, stock_location, 1.0, lot_id=lot1)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 2.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location, strict=True), 1.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location, lot_id=lot1), 1.0)
self.env['stock.quant']._increase_reserved_quantity(product1, stock_location, 1.0, lot_id=lot1, strict=True)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 1.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location, strict=True), 1.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location, lot_id=lot1), 0.0)
self.env['stock.quant']._decrease_reserved_quantity(product1, stock_location, 1.0, lot_id=lot1, strict=True)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 2.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location, strict=True), 1.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location, lot_id=lot1), 1.0)
with self.assertRaises(UserError):
self.env['stock.quant']._decrease_reserved_quantity(product1, stock_location, 1.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 2.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location, strict=True), 1.0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location, lot_id=lot1), 1.0)
def test_access_rights_1(self):
""" Directly update the quant with a user with or without stock access rights sould raise
an AccessError.
"""
stock_location = self.env.ref('stock.stock_location_stock')
product1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
})
quant = self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 1.0,
})
self.env = self.env(user=self.demo_user)
with self.assertRaises(AccessError):
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 1.0,
})
with self.assertRaises(AccessError):
quant.sudo(self.demo_user).write({'quantity': 2.0})
with self.assertRaises(AccessError):
quant.sudo(self.demo_user).unlink()
self.env = self.env(user=self.stock_user)
with self.assertRaises(AccessError):
self.env['stock.quant'].create({
'product_id': product1.id,
'location_id': stock_location.id,
'quantity': 1.0,
})
with self.assertRaises(AccessError):
quant.sudo(self.demo_user).write({'quantity': 2.0})
with self.assertRaises(AccessError):
quant.sudo(self.demo_user).unlink()