[ADD] stock: bunch of tests
This commit is contained in:
@@ -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',
|
||||
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user