2018-01-16 06:58:15 +01:00
# -*- coding: utf-8 -*-
2018-01-16 11:34:37 +01:00
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
2018-01-16 06:58:15 +01:00
2018-01-16 11:34:37 +01:00
from flectra . addons . stock . tests . common import TestStockCommon
from flectra . exceptions import UserError
from flectra import api , registry
from flectra . tests . common import TransactionCase
2018-01-16 06:58:15 +01:00
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 ' ,
' procure_method ' : ' make_to_order ' ,
} )
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 create_pick_pack_ship ( self ) :
picking_ship = 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 ,
} )
ship = 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 ' : picking_ship . id ,
' location_id ' : self . output_location ,
' location_dest_id ' : self . customer_location ,
} )
picking_pack = 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 ,
} )
pack = 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 ' : picking_pack . id ,
' location_id ' : self . pack_location ,
' location_dest_id ' : self . output_location ,
' move_dest_ids ' : [ ( 4 , ship . id ) ] ,
} )
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 ' : 1 ,
' 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 , pack . id ) ] ,
' state ' : ' confirmed ' ,
} )
return picking_pick , picking_pack , picking_ship
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 ' ] . _update_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 . 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 ] . move_line_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 ' ] . _update_available_quantity ( self . productA , stock_location , 10.0 )
pack_location = self . env [ ' stock.location ' ] . browse ( self . pack_location )
self . env [ ' stock.quant ' ] . _update_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 . move_line_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 ' ] . _update_available_quantity ( self . productA , stock_location , 10.0 )
picking_pick . action_assign ( )
picking_pick . move_lines [ 0 ] . move_line_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 ] . move_line_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 ' )
2018-07-06 14:58:06 +02:00
def test_mto_moves_return_return ( self ) :
picking_pick , picking_client = self . create_pick_ship ( )
stock_location = self . env [ ' stock.location ' ] . browse ( self . stock_location )
lot = self . env [ ' stock.production.lot ' ] . create ( {
' product_id ' : self . productA . id ,
' name ' : ' 123456789 '
} )
self . env [ ' stock.quant ' ] . _update_available_quantity ( self . productA , stock_location , 10.0 , lot_id = lot )
picking_pick . action_assign ( )
picking_pick . move_lines [ 0 ] . move_line_ids [ 0 ] . qty_done = 10.0
picking_pick . button_validate ( )
self . assertEqual ( picking_pick . state , ' done ' )
self . assertEqual ( picking_client . state , ' assigned ' )
# return this picking
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 = 10.0
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 ] . move_line_ids [ 0 ] . write ( {
' qty_done ' : 10.0 ,
' lot_id ' : lot . id ,
} )
return_pick . button_validate ( )
# return this return of this picking
stock_return_picking = self . env [ ' stock.return.picking ' ] \
. with_context ( active_id = return_pick . id ) \
. create ( { } )
stock_return_picking . product_return_moves . quantity = 10.0
stock_return_picking_action = stock_return_picking . create_returns ( )
return_return_pick = self . env [ ' stock.picking ' ] . browse ( stock_return_picking_action [ ' res_id ' ] )
return_return_pick . move_lines [ 0 ] . move_line_ids [ 0 ] . write ( {
' qty_done ' : 10.0 ,
' lot_id ' : lot . id ,
} )
return_return_pick . button_validate ( )
# test computation of traceability
vals = {
' line_id ' : 1 ,
' model_name ' : ' stock.move.line ' ,
' level ' : 11 ,
' parent_quant ' : False ,
}
lines = self . env [ ' stock.traceability.report ' ] . get_lines (
model_id = return_return_pick . move_line_ids [ 0 ] . id ,
stream = ' upstream ' ,
* * vals
)
self . assertEqual (
[ l . get ( ' res_id ' ) for l in lines ] ,
[ return_return_pick . id , return_pick . id , picking_pick . id ] ,
" Upstream computation from return of return worked "
)
lines = self . env [ ' stock.traceability.report ' ] . get_lines (
model_id = picking_pick . move_line_ids [ 0 ] . id ,
stream = ' downstream ' ,
* * vals
)
self . assertEqual (
[ l . get ( ' res_id ' ) for l in lines ] ,
[ picking_pick . id , return_pick . id , return_return_pick . id ] ,
" Downstream computation from original picking worked "
)
2018-04-05 10:25:40 +02:00
def test_mto_resupply_cancel_ship ( self ) :
""" This test simulates a pick pack ship with a resupply route
set . Pick and pack are validated , ship is cancelled . This test
ensure that new picking are not created from the cancelled
ship after the scheduler task . The supply route is only set in
order to make the scheduler run without mistakes ( no next
activity ) .
"""
picking_pick , picking_pack , picking_ship = self . create_pick_pack_ship ( )
stock_location = self . env [ ' stock.location ' ] . browse ( self . stock_location )
warehouse_1 = self . env [ ' stock.warehouse ' ] . search ( [ ( ' company_id ' , ' = ' , self . env . user . id ) ] , limit = 1 )
warehouse_1 . write ( { ' delivery_steps ' : ' pick_pack_ship ' } )
warehouse_2 = self . env [ ' stock.warehouse ' ] . create ( {
' name ' : ' Small Warehouse ' ,
' code ' : ' SWH '
} )
warehouse_1 . write ( {
' default_resupply_wh_id ' : warehouse_2 . id ,
' resupply_wh_ids ' : [ ( 6 , 0 , [ warehouse_2 . id ] ) ]
} )
resupply_route = self . env [ ' stock.location.route ' ] . search ( [ ( ' supplier_wh_id ' , ' = ' , warehouse_2 . id ) , ( ' supplied_wh_id ' , ' = ' , warehouse_1 . id ) ] )
self . assertTrue ( resupply_route )
self . productA . write ( { ' route_ids ' : [ ( 4 , resupply_route . id ) , ( 4 , self . env . ref ( ' stock.route_warehouse0_mto ' ) . id ) ] } )
self . env [ ' stock.quant ' ] . _update_available_quantity ( self . productA , stock_location , 10.0 )
picking_pick . action_assign ( )
picking_pick . move_lines [ 0 ] . move_line_ids [ 0 ] . qty_done = 10.0
picking_pick . action_done ( )
picking_pack . action_assign ( )
picking_pack . move_lines [ 0 ] . move_line_ids [ 0 ] . qty_done = 10.0
picking_pack . action_done ( )
picking_ship . action_cancel ( )
picking_ship . move_lines . write ( { ' procure_method ' : ' make_to_order ' } )
self . env [ ' procurement.group ' ] . run_scheduler ( )
next_activity = self . env [ ' mail.activity ' ] . search ( [ ( ' res_model ' , ' = ' , ' product.template ' ) , ( ' res_id ' , ' = ' , self . productA . product_tmpl_id . id ) ] )
self . assertEqual ( picking_ship . state , ' cancel ' )
self . assertFalse ( next_activity , ' If a next activity has been created if means that scheduler failed \
and the end of this test do not have sense . ' )
self . assertEqual ( len ( picking_ship . move_lines . mapped ( ' move_orig_ids ' ) ) , 0 ,
' Scheduler should not create picking pack and pick since ship has been manually cancelled. ' )
2018-01-16 06:58:15 +01:00
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 ' ] . _update_available_quantity ( self . productA , location , 10.0 )
picking_pick . action_assign ( )
picking_pick . move_lines [ 0 ] . move_line_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 . move_line_ids . product_qty , 5.0 )
self . assertEqual ( picking_client . state , ' assigned ' )
# cancel the backorder
picking_pick_backorder . action_cancel ( )
self . assertEqual ( picking_client . state , ' assigned ' )
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 ' ] . _update_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 , ' assigned ' , ' 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 ' ] . _update_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 ( )
def test_chained_move_with_uom ( self ) :
""" Create pick ship with a different uom than the once used for quant.
Check that reserved quantity and flow work correctly .
"""
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 . gB . name ,
' product_id ' : self . gB . id ,
' product_uom_qty ' : 5 ,
' product_uom ' : self . uom_kg . 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 . gB . name ,
' product_id ' : self . gB . id ,
' product_uom_qty ' : 5 ,
' product_uom ' : self . uom_kg . 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 ' ,
} )
location = self . env [ ' stock.location ' ] . browse ( self . stock_location )
pack_location = self . env [ ' stock.location ' ] . browse ( self . pack_location )
# make some stock
self . env [ ' stock.quant ' ] . _update_available_quantity ( self . gB , location , 10000.0 )
self . assertEqual ( self . env [ ' stock.quant ' ] . _get_available_quantity ( self . gB , pack_location ) , 0.0 )
picking_pick . action_assign ( )
picking_pick . move_lines [ 0 ] . move_line_ids [ 0 ] . qty_done = 5.0
picking_pick . action_done ( )
self . assertEqual ( self . env [ ' stock.quant ' ] . _get_available_quantity ( self . gB , location ) , 5000.0 )
self . assertEqual ( self . env [ ' stock.quant ' ] . _gather ( self . gB , pack_location ) . quantity , 5000.0 )
self . assertEqual ( self . env [ ' stock.quant ' ] . _get_available_quantity ( self . gB , pack_location ) , 0.0 )
self . assertEqual ( picking_client . state , ' assigned ' )
self . assertEqual ( picking_client . move_lines . reserved_availability , 5.0 )
def test_pick_ship_return ( self ) :
""" Create pick and ship. Bring it ot the customer and then return
it to stock . This test check the state and the quantity after each move in
order to ensure that it is correct .
"""
picking_pick , picking_ship = self . create_pick_ship ( )
stock_location = self . env [ ' stock.location ' ] . browse ( self . stock_location )
pack_location = self . env [ ' stock.location ' ] . browse ( self . pack_location )
customer_location = self . env [ ' stock.location ' ] . browse ( self . customer_location )
self . productA . tracking = ' lot '
lot = self . env [ ' stock.production.lot ' ] . create ( {
' product_id ' : self . productA . id ,
' name ' : ' 123456789 '
} )
self . env [ ' stock.quant ' ] . _update_available_quantity ( self . productA , stock_location , 10.0 , lot_id = lot )
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 ' )
self . assertEqual ( picking_ship . state , ' assigned ' )
picking_ship . action_assign ( )
picking_ship . move_lines [ 0 ] . move_line_ids [ 0 ] . qty_done = 10.0
picking_ship . action_done ( )
customer_quantity = self . env [ ' stock.quant ' ] . _get_available_quantity ( self . productA , customer_location , lot_id = lot )
self . assertEqual ( customer_quantity , 10 , ' It should be one product in customer ' )
""" First we create the return picking for pick pinking.
Since we do not have created the return between customer and
output . This return should not be available and should only have
picking pick as origin move .
"""
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 = 10.0
stock_return_picking_action = stock_return_picking . create_returns ( )
return_pick_picking = self . env [ ' stock.picking ' ] . browse ( stock_return_picking_action [ ' res_id ' ] )
self . assertEqual ( return_pick_picking . state , ' waiting ' )
stock_return_picking = self . env [ ' stock.return.picking ' ] \
. with_context ( active_ids = picking_ship . ids , active_id = picking_ship . ids [ 0 ] ) \
. create ( { } )
stock_return_picking . product_return_moves . quantity = 10.0
stock_return_picking_action = stock_return_picking . create_returns ( )
return_ship_picking = self . env [ ' stock.picking ' ] . browse ( stock_return_picking_action [ ' res_id ' ] )
self . assertEqual ( return_ship_picking . state , ' assigned ' , ' Return ship picking should automatically be assigned ' )
""" We created the return for ship picking. The origin/destination
link between return moves should have been created during return creation .
"""
self . assertTrue ( return_ship_picking . move_lines in return_pick_picking . move_lines . mapped ( ' move_orig_ids ' ) ,
' The pick return picking \' s moves should have the ship return picking \' s moves as origin ' )
self . assertTrue ( return_pick_picking . move_lines in return_ship_picking . move_lines . mapped ( ' move_dest_ids ' ) ,
' The ship return picking \' s moves should have the pick return picking \' s moves as destination ' )
return_ship_picking . move_lines [ 0 ] . move_line_ids [ 0 ] . write ( {
' qty_done ' : 10.0 ,
' lot_id ' : lot . id ,
} )
return_ship_picking . action_done ( )
self . assertEqual ( return_ship_picking . state , ' done ' )
self . assertEqual ( return_pick_picking . state , ' assigned ' )
customer_quantity = self . env [ ' stock.quant ' ] . _get_available_quantity ( self . productA , customer_location , lot_id = lot )
self . assertEqual ( customer_quantity , 0 , ' It should be one product in customer ' )
pack_quantity = self . env [ ' stock.quant ' ] . _get_available_quantity ( self . productA , pack_location , lot_id = lot )
self . assertEqual ( pack_quantity , 0 , ' It should be one product in pack location but is reserved ' )
# Should use previous move lot.
return_pick_picking . move_lines [ 0 ] . move_line_ids [ 0 ] . qty_done = 10.0
return_pick_picking . action_done ( )
self . assertEqual ( return_pick_picking . state , ' done ' )
stock_quantity = self . env [ ' stock.quant ' ] . _get_available_quantity ( self . productA , stock_location , lot_id = lot )
self . assertEqual ( stock_quantity , 10 , ' The product is not back in stock ' )
def test_pick_pack_ship_return ( self ) :
""" This test do a pick pack ship delivery to customer and then
return it to stock . Once everything is done , this test will check
if all the link orgini / destination between moves are correct .
"""
picking_pick , picking_pack , picking_ship = self . create_pick_pack_ship ( )
stock_location = self . env [ ' stock.location ' ] . browse ( self . stock_location )
self . productA . tracking = ' serial '
lot = self . env [ ' stock.production.lot ' ] . create ( {
' product_id ' : self . productA . id ,
' name ' : ' 123456789 '
} )
self . env [ ' stock.quant ' ] . _update_available_quantity ( self . productA , stock_location , 1.0 , lot_id = lot )
picking_pick . action_assign ( )
picking_pick . move_lines [ 0 ] . move_line_ids [ 0 ] . qty_done = 1.0
picking_pick . action_done ( )
picking_pack . action_assign ( )
picking_pack . move_lines [ 0 ] . move_line_ids [ 0 ] . qty_done = 1.0
picking_pack . action_done ( )
picking_ship . action_assign ( )
picking_ship . move_lines [ 0 ] . move_line_ids [ 0 ] . qty_done = 1.0
picking_ship . action_done ( )
stock_return_picking = self . env [ ' stock.return.picking ' ] \
. with_context ( active_ids = picking_ship . ids , active_id = picking_ship . ids [ 0 ] ) \
. create ( { } )
stock_return_picking . product_return_moves . quantity = 1.0
stock_return_picking_action = stock_return_picking . create_returns ( )
return_ship_picking = self . env [ ' stock.picking ' ] . browse ( stock_return_picking_action [ ' res_id ' ] )
return_ship_picking . move_lines [ 0 ] . move_line_ids [ 0 ] . write ( {
' qty_done ' : 1.0 ,
' lot_id ' : lot . id ,
} )
return_ship_picking . action_done ( )
stock_return_picking = self . env [ ' stock.return.picking ' ] \
. with_context ( active_ids = picking_pack . ids , active_id = picking_pack . ids [ 0 ] ) \
. create ( { } )
stock_return_picking . product_return_moves . quantity = 1.0
stock_return_picking_action = stock_return_picking . create_returns ( )
return_pack_picking = self . env [ ' stock.picking ' ] . browse ( stock_return_picking_action [ ' res_id ' ] )
return_pack_picking . move_lines [ 0 ] . move_line_ids [ 0 ] . qty_done = 1.0
return_pack_picking . action_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 = 1.0
stock_return_picking_action = stock_return_picking . create_returns ( )
return_pick_picking = self . env [ ' stock.picking ' ] . browse ( stock_return_picking_action [ ' res_id ' ] )
return_pick_picking . move_lines [ 0 ] . move_line_ids [ 0 ] . qty_done = 1.0
return_pick_picking . action_done ( )
# Now that everything is returned we will check if the return moves are correctly linked between them.
# +--------------------------------------------------------------------------------------------------------+
# | -- picking_pick(1) --> -- picking_pack(2) --> -- picking_ship(3) -->
# | Stock Pack Output Customer
# | <--- return pick(6) -- <--- return pack(5) -- <--- return ship(4) --
# +--------------------------------------------------------------------------------------------------------+
# Recaps of final link (MO = move_orig_ids, MD = move_dest_ids)
# picking_pick(1) : MO = (), MD = (2,6)
# picking_pack(2) : MO = (1), MD = (3,5)
# picking ship(3) : MO = (2), MD = (4)
# return ship(4) : MO = (3), MD = (5)
# return pack(5) : MO = (2, 4), MD = (6)
# return pick(6) : MO = (1, 5), MD = ()
self . assertEqual ( len ( picking_pick . move_lines . move_orig_ids ) , 0 , ' Picking pick should not have origin moves ' )
self . assertEqual ( set ( picking_pick . move_lines . move_dest_ids . ids ) , set ( ( picking_pack . move_lines | return_pick_picking . move_lines ) . ids ) )
self . assertEqual ( set ( picking_pack . move_lines . move_orig_ids . ids ) , set ( picking_pick . move_lines . ids ) )
self . assertEqual ( set ( picking_pack . move_lines . move_dest_ids . ids ) , set ( ( picking_ship . move_lines | return_pack_picking . move_lines ) . ids ) )
self . assertEqual ( set ( picking_ship . move_lines . move_orig_ids . ids ) , set ( picking_pack . move_lines . ids ) )
self . assertEqual ( set ( picking_ship . move_lines . move_dest_ids . ids ) , set ( return_ship_picking . move_lines . ids ) )
self . assertEqual ( set ( return_ship_picking . move_lines . move_orig_ids . ids ) , set ( picking_ship . move_lines . ids ) )
self . assertEqual ( set ( return_ship_picking . move_lines . move_dest_ids . ids ) , set ( return_pack_picking . move_lines . ids ) )
self . assertEqual ( set ( return_pack_picking . move_lines . move_orig_ids . ids ) , set ( ( picking_pack . move_lines | return_ship_picking . move_lines ) . ids ) )
self . assertEqual ( set ( return_pack_picking . move_lines . move_dest_ids . ids ) , set ( return_pick_picking . move_lines . ids ) )
self . assertEqual ( set ( return_pick_picking . move_lines . move_orig_ids . ids ) , set ( ( picking_pick . move_lines | return_pack_picking . move_lines ) . ids ) )
self . assertEqual ( len ( return_pick_picking . move_lines . move_dest_ids ) , 0 )
def test_put_in_pack ( self ) :
""" In a pick pack ship scenario, create two packs in pick and check that
they are correctly recognised and handled by the pack and ship picking .
Along this test , we ' ll use action_toggle_processed to process a pack
from the entire_package_ids one2many and we ' ll directly fill the move
lines , the latter is the behavior when the user did not enable the display
of entire packs on the picking type .
"""
picking_pick , picking_pack , picking_ship = self . create_pick_pack_ship ( )
ship_move = self . env [ ' stock.move ' ] . create ( {
' name ' : self . productB . name ,
' product_id ' : self . productB . id ,
' product_uom_qty ' : 4 ,
' product_uom ' : self . productB . uom_id . id ,
' picking_id ' : picking_ship . id ,
' location_id ' : self . output_location ,
' location_dest_id ' : self . customer_location ,
} )
pack_move = self . env [ ' stock.move ' ] . create ( {
' name ' : self . productB . name ,
' product_id ' : self . productB . id ,
' product_uom_qty ' : 4 ,
' product_uom ' : self . productB . uom_id . id ,
' picking_id ' : picking_pack . id ,
' location_id ' : self . pack_location ,
' location_dest_id ' : self . output_location ,
' move_dest_ids ' : [ ( 4 , ship_move . id ) ] ,
} )
self . env [ ' stock.move ' ] . create ( {
' name ' : self . productB . name ,
' product_id ' : self . productB . id ,
' product_uom_qty ' : 4 ,
' product_uom ' : self . productB . uom_id . id ,
' picking_id ' : picking_pick . id ,
' location_id ' : self . stock_location ,
' location_dest_id ' : self . pack_location ,
' move_dest_ids ' : [ ( 4 , pack_move . id ) ] ,
' state ' : ' confirmed ' ,
} )
stock_location = self . env [ ' stock.location ' ] . browse ( self . stock_location )
self . env [ ' stock.quant ' ] . _update_available_quantity ( self . productA , stock_location , 1.0 )
self . env [ ' stock.quant ' ] . _update_available_quantity ( self . productB , stock_location , 4.0 )
picking_pick . action_assign ( )
picking_pick . move_line_ids . filtered ( lambda ml : ml . product_id == self . productA ) . qty_done = 1.0
picking_pick . move_line_ids . filtered ( lambda ml : ml . product_id == self . productB ) . qty_done = 2.0
first_pack = picking_pick . put_in_pack ( )
picking_pick . move_line_ids . filtered ( lambda ml : ml . product_id == self . productB and ml . qty_done == 0.0 ) . qty_done = 2.0
second_pack = picking_pick . put_in_pack ( )
picking_pick . button_validate ( )
self . assertEqual ( len ( first_pack . quant_ids ) , 2 )
self . assertEqual ( len ( second_pack . quant_ids ) , 1 )
picking_pack . action_assign ( )
self . assertEqual ( len ( picking_pack . entire_package_ids ) , 2 )
output_sub_location = self . env [ ' stock.location ' ] . create ( { ' name ' : ' sub1 ' , ' location_id ' : self . output_location } )
picking_pack . entire_package_ids [ 0 ] . with_context (
{ ' picking_id ' : picking_pack . id , ' destination_location ' : output_sub_location . id } ) . action_toggle_processed ( )
picking_pack . entire_package_ids [ 1 ] . with_context (
{ ' picking_id ' : picking_pack . id , ' destination_location ' : output_sub_location . id } ) . action_toggle_processed ( )
self . assertEqual ( picking_pack . move_line_ids [ : 1 ] . location_dest_id , output_sub_location )
picking_pack . button_validate ( )
self . assertEqual ( first_pack . location_id , output_sub_location )
self . assertEqual ( second_pack . location_id , output_sub_location )
self . assertEqual ( len ( picking_pack . entire_package_ids ) , 2 )
picking_ship . action_assign ( )
self . assertEqual ( picking_ship . move_line_ids [ : 1 ] . location_id , output_sub_location )
for move_line in picking_ship . move_line_ids :
move_line . qty_done = move_line . product_uom_qty
picking_ship . button_validate ( )
quants_of_products_ab = self . env [ ' stock.quant ' ] . search ( [ ( ' product_id ' , ' in ' , ( self . productA . id , self . productB . id ) ) ] )
quants_of_product_a = quants_of_products_ab . filtered ( lambda q : q . product_id == self . productA )
quants_of_product_b = quants_of_products_ab . filtered ( lambda q : q . product_id == self . productB )
self . assertEqual ( quants_of_products_ab . mapped ( ' location_id.id ' ) , [ self . customer_location ] )
self . assertEqual ( len ( quants_of_product_a ) , 1 )
self . assertEqual ( len ( quants_of_product_b ) , 2 )
def test_merge_move_mto_mts ( self ) :
""" Create 2 moves of the same product in the same picking with
one in ' MTO ' and the other one in ' MTS ' . The moves shouldn ' t be merged
"""
picking_pick , picking_client = self . create_pick_ship ( )
self . MoveObj . create ( {
' name ' : self . productA . name ,
' product_id ' : self . productA . id ,
' product_uom_qty ' : 3 ,
' product_uom ' : self . productA . uom_id . id ,
' picking_id ' : picking_client . id ,
' location_id ' : self . stock_location ,
' location_dest_id ' : self . customer_location ,
' origin ' : ' MPS ' ,
' procure_method ' : ' make_to_stock ' ,
} )
picking_client . action_confirm ( )
self . assertEqual ( len ( picking_client . move_lines ) , 2 , ' Moves should not be merged ' )
def test_mto_cancel_move_line ( self ) :
""" Create a pick ship situation. Then process the pick picking
with a backorder . Then try to unlink the move line created on
the ship and check if the picking and move state are updated .
Then validate the backorder and unlink the ship move lines in
order to check again if the picking and state are updated .
"""
picking_pick , picking_client = self . create_pick_ship ( )
location = self . env [ ' stock.location ' ] . browse ( self . stock_location )
# make some stock
self . env [ ' stock.quant ' ] . _update_available_quantity ( self . productA , location , 10.0 )
picking_pick . move_lines . quantity_done = 5.0
backorder_wizard_values = picking_pick . button_validate ( )
backorder_wizard = self . env [ ( backorder_wizard_values . get ( ' res_model ' ) ) ] . browse ( backorder_wizard_values . get ( ' res_id ' ) )
backorder_wizard . process ( )
self . assertTrue ( picking_client . move_line_ids , ' A move line should be created. ' )
self . assertEqual ( picking_client . move_line_ids . product_uom_qty , 5 , ' The move line should have 5 unit reserved. ' )
# Directly delete the move lines on the picking. (Use show detail operation on picking type)
# Should do the same behavior than unreserve
picking_client . move_line_ids . unlink ( )
self . assertEqual ( picking_client . move_lines . state , ' waiting ' , ' The move state should be waiting since nothing is reserved and another origin move still in progess. ' )
self . assertEqual ( picking_client . state , ' waiting ' , ' The picking state should not be ready anymore. ' )
picking_client . action_assign ( )
back_order = self . env [ ' stock.picking ' ] . search ( [ ( ' backorder_id ' , ' = ' , picking_pick . id ) ] )
back_order . move_lines . quantity_done = 5
back_order . button_validate ( )
self . assertEqual ( picking_client . move_lines . reserved_availability , 10 , ' The total quantity should be reserved since everything is available. ' )
picking_client . move_line_ids . unlink ( )
self . assertEqual ( picking_client . move_lines . state , ' confirmed ' , ' The move should be confirmed since all the origin moves are processed. ' )
self . assertEqual ( picking_client . state , ' confirmed ' , ' The picking should be confirmed since all the moves are confirmed. ' )
def test_unreserve ( self ) :
picking_pick , picking_client = self . create_pick_ship ( )
self . assertEqual ( picking_pick . state , ' confirmed ' )
picking_pick . do_unreserve ( )
self . assertEqual ( picking_pick . state , ' confirmed ' )
location = self . env [ ' stock.location ' ] . browse ( self . stock_location )
self . env [ ' stock.quant ' ] . _update_available_quantity ( self . productA , location , 10.0 )
picking_pick . action_assign ( )
self . assertEqual ( picking_pick . state , ' assigned ' )
picking_pick . do_unreserve ( )
self . assertEqual ( picking_pick . state , ' confirmed ' )
self . assertEqual ( picking_client . state , ' waiting ' )
picking_client . do_unreserve ( )
self . assertEqual ( picking_client . state , ' waiting ' )
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 ' ] . _update_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 ] . move_line_ids [ 0 ] . qty_done = 1
delivery_order . do_transfer ( )
self . assertNotEqual ( delivery_order . date_done , False )
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 ' ] . _update_available_quantity ( self . productA , pack_location , 1 )
# assign to partially 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 ] . move_line_ids [ 0 ] . qty_done = 1
delivery_order . do_transfer ( )
self . assertNotEqual ( delivery_order . date_done , False )
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 ' )
2018-04-05 10:25:40 +02:00
def test_backorder_3 ( self ) :
""" Check the good behavior of creating a backorder for an available move on a picking with
two available moves .
"""
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 ,
} )
self . MoveObj . create ( {
' name ' : self . productA . name ,
' product_id ' : self . productB . id ,
' product_uom_qty ' : 2 ,
' product_uom ' : self . productB . 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 ' ] . _update_available_quantity ( self . productA , pack_location , 2 )
self . env [ ' stock.quant ' ] . _update_available_quantity ( self . productA , pack_location , 2 )
# assign to partially available
delivery_order . action_confirm ( )
delivery_order . action_assign ( )
self . assertEqual ( delivery_order . state , ' assigned ' )
delivery_order . move_lines [ 0 ] . move_line_ids [ 0 ] . qty_done = 2
delivery_order . do_transfer ( )
backorder = self . env [ ' stock.picking ' ] . search ( [ ( ' backorder_id ' , ' = ' , delivery_order . id ) ] )
self . assertEqual ( backorder . state , ' confirmed ' )
2018-01-16 06:58:15 +01:00
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 ' ] . _update_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 ] . move_line_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 ) , 0.0 )
self . assertEqual ( self . env [ ' stock.quant ' ] . _get_available_quantity ( self . productA , pack_location , allow_negative = True ) , - 1.0 )
self . assertEqual ( move1 . product_qty , 2.0 )
self . assertEqual ( move1 . quantity_done , 2.0 )
self . assertEqual ( move1 . reserved_availability , 0.0 )
self . assertEqual ( move1 . move_line_ids . product_qty , 0.0 ) # change reservation to 0 for done move
self . assertEqual ( sum ( move1 . move_line_ids . mapped ( ' qty_done ' ) ) , 2.0 )
self . assertEqual ( move1 . 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 ' ] . _update_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 ] . move_line_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 ) , 0.0 )
self . assertEqual ( self . env [ ' stock.quant ' ] . _get_available_quantity ( self . productA , pack_location , allow_negative = True ) , - 2.0 )
self . assertEqual ( move1 . product_qty , 3.0 )
self . assertEqual ( move1 . quantity_done , 3.0 )
self . assertEqual ( move1 . reserved_availability , 0.0 )
self . assertEqual ( move1 . move_line_ids . product_qty , 0.0 ) # change reservation to 0 for done move
self . assertEqual ( sum ( move1 . move_line_ids . mapped ( ' qty_done ' ) ) , 3.0 )
self . assertEqual ( move1 . 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 ] . move_line_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 )
self . assertEqual ( move1 . product_qty , 2.0 )
self . assertEqual ( move1 . quantity_done , 2.0 )
self . assertEqual ( move1 . reserved_availability , 0.0 )
self . assertEqual ( move1 . move_line_ids . product_qty , 0.0 ) # change reservation to 0 for done move
self . assertEqual ( sum ( move1 . move_line_ids . mapped ( ' qty_done ' ) ) , 2.0 )
self . assertEqual ( move1 . state , ' done ' )
2018-07-06 14:58:06 +02:00
def test_extra_move_4 ( self ) :
""" Create a picking with similar moves (created after
confirmation ) . Action done should propagate all the extra
quantity and only merge extra moves in their original moves .
"""
delivery = 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 ,
} )
self . MoveObj . create ( {
' name ' : self . productA . name ,
' product_id ' : self . productA . id ,
' product_uom_qty ' : 5 ,
' quantity_done ' : 10 ,
' product_uom ' : self . productA . uom_id . id ,
' picking_id ' : delivery . id ,
' location_id ' : self . stock_location ,
' location_dest_id ' : self . customer_location ,
} )
stock_location = self . env [ ' stock.location ' ] . browse ( self . stock_location )
self . env [ ' stock.quant ' ] . _update_available_quantity ( self . productA , stock_location , 5 )
delivery . action_confirm ( )
delivery . action_assign ( )
delivery . write ( {
' move_lines ' : [ ( 0 , 0 , {
' name ' : self . productA . name ,
' product_id ' : self . productA . id ,
' product_uom_qty ' : 0 ,
' quantity_done ' : 10 ,
' state ' : ' assigned ' ,
' product_uom ' : self . productA . uom_id . id ,
' picking_id ' : delivery . id ,
' location_id ' : self . stock_location ,
' location_dest_id ' : self . customer_location ,
} ) ]
} )
delivery . action_done ( )
self . assertEqual ( len ( delivery . move_lines ) , 2 , ' Move should not be merged together ' )
for move in delivery . move_lines :
self . assertEqual ( move . quantity_done , move . product_uom_qty , ' Initial demand should be equals to quantity done ' )
def test_extra_move_5 ( self ) :
""" Create a picking a move that is problematic with
rounding ( 5.95 - 5.5 = 0.4500000000000002 ) . Ensure that
initial demand is corrct afer action_done and backoder
are not created .
"""
delivery = 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 ,
} )
self . MoveObj . create ( {
' name ' : self . productA . name ,
' product_id ' : self . productA . id ,
' product_uom_qty ' : 5.5 ,
' quantity_done ' : 5.95 ,
' product_uom ' : self . productA . uom_id . id ,
' picking_id ' : delivery . id ,
' location_id ' : self . stock_location ,
' location_dest_id ' : self . customer_location ,
} )
stock_location = self . env [ ' stock.location ' ] . browse ( self . stock_location )
self . env [ ' stock.quant ' ] . _update_available_quantity ( self . productA , stock_location , 5.5 )
delivery . action_confirm ( )
delivery . action_assign ( )
delivery . action_done ( )
self . assertEqual ( delivery . move_lines . product_uom_qty , 5.95 , ' Move initial demand should be 5.95 ' )
back_order = self . env [ ' stock.picking ' ] . search ( [ ( ' backorder_id ' , ' = ' , delivery . id ) ] )
self . assertFalse ( back_order , ' There should be no back order ' )
2018-01-16 06:58:15 +01:00
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 ' ] . _update_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 , ' assigned ' )
self . assertEqual ( move1 . state , ' partially_available ' )
# Check reserved quantity
self . assertEqual ( move1 . reserved_availability , 1.0 )
self . assertEqual ( len ( move1 . move_line_ids ) , 1 )
self . assertEqual ( move1 . move_line_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 . action_start ( )
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 . move_line_ids ) , 1 )
self . assertEqual ( move1 . move_line_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 ' ] . _update_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 , ' assigned ' )
self . assertEqual ( move1 . state , ' partially_available ' )
# Check reserved quantity
self . assertEqual ( move1 . reserved_availability , 1.0 )
self . assertEqual ( len ( move1 . move_line_ids ) , 1 )
self . assertEqual ( move1 . move_line_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 . action_start ( )
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 . move_line_ids ) , 1 )
self . assertEqual ( move1 . move_line_ids . lot_id . id , lot1 . id )
self . assertEqual ( move1 . move_line_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 ' ] . _update_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 , ' assigned ' )
self . assertEqual ( move1 . state , ' partially_available ' )
# Check reserved quantity
self . assertEqual ( move1 . reserved_availability , 1.0 )
self . assertEqual ( len ( move1 . move_line_ids ) , 1 )
self . assertEqual ( move1 . move_line_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 . action_start ( )
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 . move_line_ids ) , 2 )
self . assertEqual ( move1 . move_line_ids [ 0 ] . lot_id . id , lot1 . id )
self . assertEqual ( move1 . move_line_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 ' ] . _update_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 , ' assigned ' )
self . assertEqual ( move1 . state , ' partially_available ' )
# Check reserved quantity
self . assertEqual ( move1 . reserved_availability , 1.0 )
self . assertEqual ( len ( move1 . move_line_ids ) , 1 )
self . assertEqual ( move1 . move_line_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 . action_start ( )
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 . move_line_ids ) , 2 )
self . assertEqual ( move1 . move_line_ids [ 0 ] . lot_id . id , serial1 . id )
self . assertEqual ( move1 . move_line_ids [ 1 ] . lot_id . id , serial2 . id )
def test_add_move_when_picking_is_available_1 ( self ) :
""" Check that any move added in a picking once it ' s assigned is directly considered as
assigned and bypass the reservation .
"""
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 ' ] . _update_available_quantity ( self . productA , pack_location , 2 )
# assign
delivery_order . action_confirm ( )
delivery_order . action_assign ( )
self . assertEqual ( delivery_order . state , ' assigned ' )
# add a move
move2 = self . MoveObj \
. with_context ( default_picking_id = delivery_order . id ) \
. create ( {
' name ' : self . productA . name ,
' product_id ' : self . productB . 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 ,
} )
self . assertEqual ( move2 . state , ' assigned ' )
self . assertEqual ( delivery_order . state , ' assigned ' )
def test_use_create_lot_use_existing_lot_1 ( self ) :
""" Check the behavior of a picking when `use_create_lot` and `use_existing_lot` are
set to False and there ' s a move for a tracked product.
"""
self . env [ ' stock.picking.type ' ] \
. browse ( self . picking_type_out ) \
. write ( {
' use_create_lots ' : False ,
' use_existing_lots ' : False ,
} )
self . productA . tracking = ' lot '
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 ,
' picking_type_id ' : self . picking_type_out ,
' location_id ' : self . pack_location ,
' location_dest_id ' : self . customer_location ,
} )
delivery_order . action_confirm ( )
delivery_order . force_assign ( )
delivery_order . move_lines . quantity_done = 2
# do not set a lot_id or lot_name, it should work
delivery_order . action_done ( )
def test_use_create_lot_use_existing_lot_2 ( self ) :
""" Check the behavior of a picking when `use_create_lot` and `use_existing_lot` are
set to True and there ' s a move for a tracked product.
"""
self . env [ ' stock.picking.type ' ] \
. browse ( self . picking_type_out ) \
. write ( {
' use_create_lots ' : True ,
' use_existing_lots ' : True ,
} )
self . productA . tracking = ' lot '
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 ,
' picking_type_id ' : self . picking_type_out ,
' location_id ' : self . pack_location ,
' location_dest_id ' : self . customer_location ,
} )
delivery_order . action_confirm ( )
delivery_order . force_assign ( )
delivery_order . move_lines . quantity_done = 2
move_line = delivery_order . move_lines . move_line_ids
# not lot_name set, should raise
with self . assertRaises ( UserError ) :
delivery_order . action_done ( )
# enter a new lot name, should work
move_line . lot_name = ' newlot '
delivery_order . action_done ( )
def test_use_create_lot_use_existing_lot_3 ( self ) :
""" Check the behavior of a picking when `use_create_lot` is set to True and
` use_existing_lot ` is set to False and there ' s a move for a tracked product.
"""
self . env [ ' stock.picking.type ' ] \
. browse ( self . picking_type_out ) \
. write ( {
' use_create_lots ' : True ,
' use_existing_lots ' : False ,
} )
self . productA . tracking = ' lot '
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 ,
' picking_type_id ' : self . picking_type_out ,
' location_id ' : self . pack_location ,
' location_dest_id ' : self . customer_location ,
} )
delivery_order . action_confirm ( )
delivery_order . force_assign ( )
delivery_order . move_lines . quantity_done = 2
move_line = delivery_order . move_lines . move_line_ids
# not lot_name set, should raise
with self . assertRaises ( UserError ) :
delivery_order . action_done ( )
# enter a new lot name, should work
move_line . lot_name = ' newlot '
delivery_order . action_done ( )
def test_use_create_lot_use_existing_lot_4 ( self ) :
""" Check the behavior of a picking when `use_create_lot` is set to False and
` use_existing_lot ` is set to True and there ' s a move for a tracked product.
"""
self . env [ ' stock.picking.type ' ] \
. browse ( self . picking_type_out ) \
. write ( {
' use_create_lots ' : False ,
' use_existing_lots ' : True ,
} )
self . productA . tracking = ' lot '
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 ,
' picking_type_id ' : self . picking_type_out ,
' location_id ' : self . pack_location ,
' location_dest_id ' : self . customer_location ,
} )
delivery_order . action_confirm ( )
delivery_order . force_assign ( )
delivery_order . move_lines . quantity_done = 2
move_line = delivery_order . move_lines . move_line_ids
# not lot_name set, should raise
with self . assertRaises ( UserError ) :
delivery_order . action_done ( )
# creating a lot from the view should raise
with self . assertRaises ( UserError ) :
self . env [ ' stock.production.lot ' ] \
. with_context ( active_picking_id = delivery_order . id ) \
. create ( {
' name ' : ' lot1 ' ,
' product_id ' : self . productA . id ,
} )
# enter an existing lot_id, should work
lot1 = self . env [ ' stock.production.lot ' ] . create ( {
' name ' : ' lot1 ' ,
' product_id ' : self . productA . id ,
} )
move_line . lot_id = lot1
delivery_order . action_done ( )
def test_merge_moves_1 ( self ) :
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 ,
} )
self . MoveObj . create ( {
' name ' : self . productA . name ,
' product_id ' : self . productA . id ,
' product_uom_qty ' : 3 ,
' product_uom ' : self . productA . uom_id . id ,
' picking_id ' : receipt . id ,
' location_id ' : self . supplier_location ,
' location_dest_id ' : self . stock_location ,
} )
self . MoveObj . create ( {
' name ' : self . productA . name ,
' product_id ' : self . productA . id ,
' product_uom_qty ' : 5 ,
' product_uom ' : self . productA . uom_id . id ,
' picking_id ' : receipt . id ,
' location_id ' : self . supplier_location ,
' location_dest_id ' : self . stock_location ,
} )
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 ,
} )
self . MoveObj . create ( {
' name ' : self . productB . name ,
' product_id ' : self . productB . id ,
' product_uom_qty ' : 5 ,
' product_uom ' : self . productB . uom_id . id ,
' picking_id ' : receipt . id ,
' location_id ' : self . supplier_location ,
' location_dest_id ' : self . stock_location ,
} )
receipt . action_confirm ( )
self . assertEqual ( len ( receipt . move_lines ) , 2 , ' Moves were not merged ' )
self . assertEqual ( receipt . move_lines . filtered ( lambda m : m . product_id == self . productA ) . product_uom_qty , 9 , ' Merged quantity is not correct ' )
self . assertEqual ( receipt . move_lines . filtered ( lambda m : m . product_id == self . productB ) . product_uom_qty , 5 , ' Merge should not impact product B reserved quantity ' )
def test_merge_moves_2 ( self ) :
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 ,
} )
self . MoveObj . create ( {
' name ' : self . productA . name ,
' product_id ' : self . productA . id ,
' product_uom_qty ' : 3 ,
' product_uom ' : self . productA . uom_id . id ,
' picking_id ' : receipt . id ,
' location_id ' : self . supplier_location ,
' location_dest_id ' : self . stock_location ,
' origin ' : ' MPS '
} )
self . MoveObj . create ( {
' name ' : self . productA . name ,
' product_id ' : self . productA . id ,
' product_uom_qty ' : 5 ,
' product_uom ' : self . productA . uom_id . id ,
' picking_id ' : receipt . id ,
' location_id ' : self . supplier_location ,
' location_dest_id ' : self . stock_location ,
' origin ' : ' PO0001 '
} )
self . MoveObj . create ( {
' name ' : self . productA . name ,
' product_id ' : self . productA . id ,
' product_uom_qty ' : 3 ,
' product_uom ' : self . productA . uom_id . id ,
' picking_id ' : receipt . id ,
' location_id ' : self . supplier_location ,
' location_dest_id ' : self . stock_location ,
' origin ' : ' MPS '
} )
receipt . action_confirm ( )
self . assertEqual ( len ( receipt . move_lines ) , 1 , ' Moves were not merged ' )
self . assertEqual ( receipt . move_lines . origin . count ( ' MPS ' ) , 1 , ' Origin not merged together or duplicated ' )
self . assertEqual ( receipt . move_lines . origin . count ( ' PO0001 ' ) , 1 , ' Origin not merged together or duplicated ' )
def test_merge_moves_3 ( self ) :
""" Create 2 moves without initial_demand and already a
quantity done . Check that we still have only 2 moves after
validation .
"""
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 ,
} )
move_1 = self . MoveObj . create ( {
' name ' : self . productA . name ,
' product_id ' : self . productA . id ,
' product_uom_qty ' : 0 ,
' product_uom ' : self . productA . uom_id . id ,
' picking_id ' : receipt . id ,
' location_id ' : self . supplier_location ,
' location_dest_id ' : self . stock_location ,
' origin ' : ' MPS '
} )
move_2 = self . MoveObj . create ( {
' name ' : self . productB . name ,
' product_id ' : self . productB . id ,
' product_uom_qty ' : 0 ,
' product_uom ' : self . productB . uom_id . id ,
' picking_id ' : receipt . id ,
' location_id ' : self . supplier_location ,
' location_dest_id ' : self . stock_location ,
' origin ' : ' PO0001 '
} )
move_1 . quantity_done = 5
move_2 . quantity_done = 5
receipt . button_validate ( )
self . assertEqual ( len ( receipt . move_lines ) , 2 , ' Moves were not merged ' )
def test_merge_chained_moves ( self ) :
""" Imagine multiple step delivery. Two different receipt picking for the same product should only generate
1 picking from input to QC and another from QC to stock . The link at the end should follow this scheme .
Move receipt 1 \
Move Input - > QC - Move QC - > Stock
Move receipt 2 /
"""
2018-01-18 10:57:39 +01:00
branch_id = self . env . ref ( ' base_branch_company.data_branch_1 ' )
2018-01-16 06:58:15 +01:00
warehouse = self . env [ ' stock.warehouse ' ] . create ( {
2018-01-18 10:57:39 +01:00
' name ' : ' TEST WAREHOUSE ' , ' branch_id ' : branch_id . id ,
2018-01-16 06:58:15 +01:00
' code ' : ' TEST1 ' ,
' reception_steps ' : ' three_steps ' ,
} )
receipt1 = self . env [ ' stock.picking ' ] . create ( {
' location_id ' : self . supplier_location ,
' location_dest_id ' : warehouse . wh_input_stock_loc_id . id ,
' partner_id ' : self . partner_delta_id ,
' picking_type_id ' : warehouse . in_type_id . id ,
2018-01-18 10:57:39 +01:00
' branch_id ' : branch_id . id
2018-01-16 06:58:15 +01:00
} )
move_receipt_1 = self . MoveObj . create ( {
' name ' : self . productA . name ,
' product_id ' : self . productA . id ,
' product_uom_qty ' : 5 ,
' product_uom ' : self . productA . uom_id . id ,
' picking_id ' : receipt1 . id ,
' location_id ' : self . supplier_location ,
' location_dest_id ' : warehouse . wh_input_stock_loc_id . id ,
} )
receipt2 = self . env [ ' stock.picking ' ] . create ( {
' location_id ' : self . supplier_location ,
' location_dest_id ' : warehouse . wh_input_stock_loc_id . id ,
' partner_id ' : self . partner_delta_id ,
' picking_type_id ' : warehouse . in_type_id . id ,
} )
move_receipt_2 = self . MoveObj . create ( {
' name ' : self . productA . name ,
' product_id ' : self . productA . id ,
' product_uom_qty ' : 3 ,
' product_uom ' : self . productA . uom_id . id ,
' picking_id ' : receipt2 . id ,
' location_id ' : self . supplier_location ,
' location_dest_id ' : warehouse . wh_input_stock_loc_id . id ,
} )
receipt1 . action_confirm ( )
receipt2 . action_confirm ( )
# Check following move has been created and grouped in one picking.
self . assertTrue ( move_receipt_1 . move_dest_ids , ' No move created from push rules ' )
self . assertTrue ( move_receipt_2 . move_dest_ids , ' No move created from push rules ' )
self . assertEqual ( move_receipt_1 . move_dest_ids . picking_id , move_receipt_2 . move_dest_ids . picking_id , ' Destination moves should be in the same picking ' )
# Check link for input move are correct.
input_move = move_receipt_2 . move_dest_ids
self . assertEqual ( len ( input_move . move_dest_ids ) , 1 )
self . assertEqual ( set ( input_move . move_orig_ids . ids ) , set ( ( move_receipt_2 | move_receipt_1 ) . ids ) ,
' Move from input to QC should be merged and have the two receipt moves as origin. ' )
self . assertEqual ( move_receipt_1 . move_dest_ids , input_move )
self . assertEqual ( move_receipt_2 . move_dest_ids , input_move )
# Check link for quality check move are also correct.
qc_move = input_move . move_dest_ids
self . assertEqual ( len ( qc_move ) , 1 )
self . assertTrue ( qc_move . move_orig_ids == input_move , ' Move between QC and stock should only have the input move as origin ' )
def test_empty_moves_validation_1 ( self ) :
""" Use button validate on a picking that contains only moves
without initial demand and without quantity done should be
impossible and raise a usererror .
"""
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 ,
} )
self . MoveObj . create ( {
' name ' : self . productA . name ,
' product_id ' : self . productA . id ,
' product_uom_qty ' : 0 ,
' product_uom ' : self . productA . uom_id . id ,
' picking_id ' : delivery_order . id ,
' location_id ' : self . stock_location ,
' location_dest_id ' : self . customer_location ,
} )
self . MoveObj . create ( {
' name ' : self . productB . name ,
' product_id ' : self . productB . id ,
' product_uom_qty ' : 0 ,
' product_uom ' : self . productB . 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 ( )
with self . assertRaises ( UserError ) :
delivery_order . button_validate ( )
def test_empty_moves_validation_2 ( self ) :
""" Use button validate on a picking that contains only moves
without initial demand but at least one with a quantity done
should process the move with quantity done and cancel the
other .
"""
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 ,
} )
move_a = self . MoveObj . create ( {
' name ' : self . productA . name ,
' product_id ' : self . productA . id ,
' product_uom_qty ' : 0 ,
' product_uom ' : self . productA . uom_id . id ,
' picking_id ' : delivery_order . id ,
' location_id ' : self . stock_location ,
' location_dest_id ' : self . customer_location ,
} )
move_b = self . MoveObj . create ( {
' name ' : self . productB . name ,
' product_id ' : self . productB . id ,
' product_uom_qty ' : 0 ,
' product_uom ' : self . productB . 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 ( )
move_a . quantity_done = 1
delivery_order . button_validate ( )
self . assertEqual ( move_a . state , ' done ' )
self . assertEqual ( move_b . state , ' cancel ' )
back_order = self . env [ ' stock.picking ' ] . search ( [ ( ' backorder_id ' , ' = ' , delivery_order . id ) ] )
self . assertFalse ( back_order , ' There should be no back order ' )
class TestStockUOM ( TestStockCommon ) :
def setUp ( self ) :
super ( TestStockUOM , self ) . setUp ( )
2018-04-05 10:25:40 +02:00
dp = self . env . ref ( ' product.decimal_product_uom ' )
dp . digits = 7
# Trick: invoke the method 'precision_get' with the current environment.
# This fills in the cache of the method with the right value. If we
# don't do that, the registry will access the corresponding precision
# with a new cursor (LazyCursor), and get a different value!
self . assertEqual ( dp . precision_get ( dp . name ) , 7 )
2018-01-16 06:58:15 +01:00
def test_pickings_transfer_with_different_uom_and_back_orders ( self ) :
""" Picking transfer with diffrent unit of meassure. """
# weight category
categ_test = self . env [ ' product.uom.categ ' ] . create ( { ' name ' : ' Bigger than tons ' } )
T_LBS = self . env [ ' product.uom ' ] . create ( {
' name ' : ' T-LBS ' ,
' category_id ' : categ_test . id ,
' uom_type ' : ' reference ' ,
' rounding ' : 0.01
} )
T_GT = self . env [ ' product.uom ' ] . create ( {
' name ' : ' T-GT ' ,
' category_id ' : categ_test . id ,
' uom_type ' : ' bigger ' ,
' rounding ' : 0.0000001 ,
' factor_inv ' : 2240.00 ,
} )
T_TEST = self . env [ ' product.product ' ] . create ( {
' name ' : ' T_TEST ' ,
' type ' : ' product ' ,
' uom_id ' : T_LBS . id ,
' uom_po_id ' : T_LBS . id ,
' tracking ' : ' lot ' ,
} )
picking_in = self . env [ ' stock.picking ' ] . create ( {
' partner_id ' : self . partner_delta_id ,
' picking_type_id ' : self . picking_type_in ,
' location_id ' : self . supplier_location ,
' location_dest_id ' : self . stock_location
} )
move = self . env [ ' stock.move ' ] . create ( {
' name ' : ' First move with 60 GT ' ,
' product_id ' : T_TEST . id ,
' product_uom_qty ' : 60 ,
' product_uom ' : T_GT . id ,
' picking_id ' : picking_in . id ,
' location_id ' : self . supplier_location ,
' location_dest_id ' : self . stock_location
} )
picking_in . action_confirm ( )
self . assertEqual ( move . product_uom_qty , 60.00 , ' Wrong T_GT quantity ' )
self . assertEqual ( move . product_qty , 134400.00 , ' Wrong T_LBS quantity ' )
lot = self . env [ ' stock.production.lot ' ] . create ( { ' name ' : ' Lot TEST ' , ' product_id ' : T_TEST . id } )
self . env [ ' stock.move.line ' ] . create ( {
' move_id ' : move . id ,
' product_id ' : T_TEST . id ,
' product_uom_id ' : T_LBS . id ,
' location_id ' : self . supplier_location ,
' location_dest_id ' : self . stock_location ,
' qty_done ' : 42760.00 ,
' lot_id ' : lot . id ,
} )
picking_in . action_done ( )
back_order_in = self . env [ ' stock.picking ' ] . search ( [ ( ' backorder_id ' , ' = ' , picking_in . id ) ] )
self . assertEqual ( len ( back_order_in ) , 1.00 , ' There should be one back order created ' )
self . assertEqual ( back_order_in . move_lines . product_qty , 91640.00 , ' There should be one back order created ' )
class TestRoutes ( TransactionCase ) :
def test_pick_ship_1 ( self ) :
""" Enable the pick ship route, force a procurement group on the
pick . When a second move is added , make sure the ` partner_id ` and
` origin ` fields are erased .
"""
product1 = self . env [ ' product.product ' ] . create ( {
' name ' : ' product a ' ,
' type ' : ' product ' ,
' categ_id ' : self . env . ref ( ' product.product_category_all ' ) . id ,
} )
uom_unit = self . env . ref ( ' product.product_uom_unit ' )
wh = self . env [ ' stock.warehouse ' ] . search ( [ ( ' company_id ' , ' = ' , self . env . user . id ) ] , limit = 1 )
# create and get back the pick ship route
wh . write ( { ' delivery_steps ' : ' pick_ship ' } )
pick_ship_route = wh . route_ids . filtered ( lambda r : ' Pick + Ship ' in r . name )
# create a procurement group and set in on the pick procurement rule
procurement_group0 = self . env [ ' procurement.group ' ] . create ( { } )
pick_rule = pick_ship_route . pull_ids . filtered ( lambda rule : ' Stock -> Output ' in rule . name )
push_rule = pick_ship_route . pull_ids - pick_rule
pick_rule . write ( {
' group_propagation_option ' : ' fixed ' ,
' group_id ' : procurement_group0 . id ,
} )
stock_location = pick_rule . location_src_id
ship_location = pick_rule . location_id
customer_location = push_rule . location_id
partners = self . env [ ' res.partner ' ] . search ( [ ] , limit = 2 )
partner0 = partners [ 0 ]
partner1 = partners [ 1 ]
procurement_group1 = self . env [ ' procurement.group ' ] . create ( { ' partner_id ' : partner0 . id } )
procurement_group2 = self . env [ ' procurement.group ' ] . create ( { ' partner_id ' : partner1 . id } )
move1 = self . env [ ' stock.move ' ] . create ( {
' name ' : ' first out move ' ,
' procure_method ' : ' make_to_order ' ,
' location_id ' : ship_location . id ,
' location_dest_id ' : customer_location . id ,
' product_id ' : product1 . id ,
' product_uom ' : uom_unit . id ,
' product_uom_qty ' : 1.0 ,
' warehouse_id ' : wh . id ,
' group_id ' : procurement_group1 . id ,
' origin ' : ' origin1 ' ,
} )
move2 = self . env [ ' stock.move ' ] . create ( {
' name ' : ' second out move ' ,
' procure_method ' : ' make_to_order ' ,
' location_id ' : ship_location . id ,
' location_dest_id ' : customer_location . id ,
' product_id ' : product1 . id ,
' product_uom ' : uom_unit . id ,
' product_uom_qty ' : 1.0 ,
' warehouse_id ' : wh . id ,
' group_id ' : procurement_group2 . id ,
' origin ' : ' origin2 ' ,
} )
# first out move, the "pick" picking should have a partner and an origin
move1 . _action_confirm ( )
picking_pick = move1 . move_orig_ids . picking_id
self . assertEqual ( picking_pick . partner_id . id , procurement_group1 . partner_id . id )
self . assertEqual ( picking_pick . origin , move1 . group_id . name )
# second out move, the "pick" picking should have lost its partner and origin
move2 . _action_confirm ( )
self . assertEqual ( picking_pick . partner_id . id , False )
self . assertEqual ( picking_pick . origin , False )