[MERGE] from upstream
bzr revid: fva@openerp.com-20130628163349-4erq76zp1ddkuufj
This commit is contained in:
@@ -226,7 +226,7 @@ function openerp_picking_widgets(instance){
|
||||
var self = this;
|
||||
console.log('Done');
|
||||
new instance.web.Model('stock.picking')
|
||||
.call('action_done_from_packing_ui',[[self.picking.id]])
|
||||
.call('action_done_from_packing_ui',[self.picking.id])
|
||||
.then(function(new_picking_id){
|
||||
console.log('New picking id:',new_picking_id);
|
||||
//return self.refresh_ui(new_picking_id);
|
||||
|
||||
+126
-48
@@ -1027,7 +1027,7 @@ class stock_picking(osv.osv):
|
||||
# TODO: Check locations to see if in the same location ?
|
||||
return True
|
||||
|
||||
def check_assign(self, cr, uid, ids, *args):
|
||||
def action_assign(self, cr, uid, ids, *args):
|
||||
""" Changes state of picking to available if all moves are confirmed.
|
||||
@return: True
|
||||
"""
|
||||
@@ -1088,8 +1088,6 @@ class stock_picking(osv.osv):
|
||||
""" Changes picking state to assigned.
|
||||
@return: True
|
||||
"""
|
||||
for picking in self.browse(cr, uid, ids, context=context):
|
||||
self.pool.get('stock.move').action_assign(cr, uid, [move.id for move in picking.move_lines])
|
||||
self.write(cr, uid, ids, {'state': 'assigned'})
|
||||
return True
|
||||
|
||||
@@ -1480,8 +1478,57 @@ class stock_picking(osv.osv):
|
||||
|
||||
return super(stock_picking, self).unlink(cr, uid, ids, context=context)
|
||||
|
||||
#TODO move this in another class?
|
||||
def get_done_reserved_quants(self, cr, uid, picking_id, move, context=None):
|
||||
stock_operation_obj = self.pool.get('stock.pack.operation')
|
||||
quant_obj = self.pool.get('stock.quant')
|
||||
possible_quants = [x.id for x in move.reserved_quant_ids]
|
||||
operation_ids = stock_operation_obj.find_packaging_op_from_product(cr, uid, move.product_id, picking_id, context=context)
|
||||
todo_later = []
|
||||
possible_quants = [quant.id for quant in move.reserved_quant_ids]
|
||||
done_reserved_quants = set()
|
||||
for op in stock_operation_obj.browse(cr, uid, operation_ids, context=context):
|
||||
if op.product_id:
|
||||
#TODO: document me
|
||||
todo_later += [op.id]
|
||||
elif op.quant_id:
|
||||
#split for partial and take care of reserved quants
|
||||
quant_tuples = quant_obj._get_quant_tuples(cr, uid, [op.quant_id.id], op.product_qty, context=context)
|
||||
quant_obj.real_split_quants(cr, uid, quant_tuples, context=context)
|
||||
done_reserved_quants = done_reserved_quants.union(set([qt[O] for qt in quant_tuples]))
|
||||
elif op.package_id:
|
||||
#moving a package never splits quants but we need to take care of the reserved_quant_ids
|
||||
all_children_quants = self.pool.get('stock.quant.package').find_all_quants(cr, uid, op.package_id, context=context)
|
||||
done_reserved_quants = done_reserved_quants.union(set(all_chilren_quants))
|
||||
|
||||
#finish the partial split by operation that leaves the choice of quant to move
|
||||
for op in stock_operation_obj.browse(cr, uid, todo_later, context=context):
|
||||
quant_tuples = quant_obj._get_quant_tuples(cr, uid, possible_quants, op.product_qty, context=context)
|
||||
quant_obj.real_split_quants(cr, uid, quant_tuples, context=context)
|
||||
done_reserved_quants = done_reserved_quants.union(set([qt[O] for qt in quant_tuples]))
|
||||
|
||||
return done_reserved_quants
|
||||
|
||||
#TODO move this in another class?
|
||||
def make_packaging(self, cr, uid, picking_id, move, possible_quants, context=None):
|
||||
stock_operation_obj = self.pool.get('stock.pack.operation')
|
||||
quant_obj = self.pool.get('stock.quant')
|
||||
operation_ids = stock_operation_obj.find_packaging_op_from_product(cr, uid, move.product_id, picking_id, context=context)
|
||||
for op in stock_operation_obj.browse(cr, uid, operation_ids, context=context):
|
||||
if not op.result_package_id:
|
||||
continue
|
||||
if op.product_id:
|
||||
quant_tuples = quant_obj._get_quant_tuples(cr, uid, possible_quants, op.product_qty, context=context)
|
||||
quant_obj.real_split_quants(cr, uid, quant_tuples, context=context)
|
||||
quant_obj.write(cr, uid, [qt[O] for qt in quant_tuples], {'package_id': op.result_package_id.id}, context=context)
|
||||
elif op.quant_id:
|
||||
quant_tuples = quant_obj._get_quant_tuples(cr, uid, [op.quant_id.id], op.product_qty, context=context)
|
||||
quant_obj.real_split_quants(cr, uid, quant_tuples, context=context)
|
||||
quant_obj.write(cr, uid, [qt[O] for qt in quant_tuples], {'package_id': op.result_package_id.id}, context=context)
|
||||
elif op.package_id:
|
||||
#pack existing packs
|
||||
self.pool.get('stock.quant.package').write(cr, uid, op.package_id.id, {'parent_id': op.result_package_id.id}, context=context)
|
||||
|
||||
|
||||
def do_partial(self, cr, uid, ids, partial_datas, context=None):
|
||||
""" Makes partial picking and moves done.
|
||||
@@ -1533,6 +1580,10 @@ class stock_picking(osv.osv):
|
||||
if not new_picking:
|
||||
#a backorder picking doesn't exist yet, create a new one
|
||||
new_picking_name = pick.name
|
||||
self.write(cr, uid, [pick.id],
|
||||
{'name': sequence_obj.get(cr, uid,
|
||||
'stock.picking.%s'%(pick.type)),
|
||||
})
|
||||
new_picking = self.copy(cr, uid, pick.id,
|
||||
{
|
||||
'name': new_picking_name,
|
||||
@@ -1542,15 +1593,16 @@ class stock_picking(osv.osv):
|
||||
#modify the existing picking (this trick is needed to keep the eventual workflows pointing on the first picking)
|
||||
unlink_operation_order = [(2, op.id) for op in pick.pack_operation_ids]
|
||||
self.write(cr, uid, [pick.id],
|
||||
{'name': sequence_obj.get(cr, uid,
|
||||
'stock.picking.%s'%(pick.type)),
|
||||
{
|
||||
'pack_operation_ids': unlink_operation_order
|
||||
})
|
||||
done_reserved_quants = set()
|
||||
if product_qty != 0:
|
||||
#take care of partial picking in reserved quants
|
||||
done_reserved_quants = self.get_done_reserved_quants(cr, uid, pick.id, move, context=context)
|
||||
#copy the stock move
|
||||
new_picking_record = self.browse(cr, uid, new_picking, context=context)
|
||||
possible_quants = move.reserved_quant_ids
|
||||
done_quant_ids
|
||||
|
||||
defaults = {
|
||||
'product_qty' : product_qty,
|
||||
'product_uos_qty': product_qty, #TODO: put correct uos_qty
|
||||
@@ -1559,20 +1611,22 @@ class stock_picking(osv.osv):
|
||||
'move_dest_id': False,
|
||||
'price_unit': product_price,
|
||||
'product_uom': product_uoms[move.id],
|
||||
'reserved_quant_ids': done_quant_ids
|
||||
'reserved_quant_ids': list(done_reserved_quants)
|
||||
}
|
||||
prodlot_id = prodlot_ids[move.id]
|
||||
if prodlot_id:
|
||||
defaults.update(prodlot_id=prodlot_id)
|
||||
move_obj.copy(cr, uid, move.id, defaults)
|
||||
backorder_move_id = move_obj.copy(cr, uid, move.id, defaults)
|
||||
self.make_packaging(cr, uid, pick.id, move_obj.browse(cr, uid, backorder_move_id, context=context), list(done_reserved_quants), context=context)
|
||||
#modify the existing stock move
|
||||
possible_quants = [x.id for x in move.reserved_quant_ids]
|
||||
move_obj.write(cr, uid, [move.id],
|
||||
{
|
||||
'product_qty': move.product_qty - partial_qty[move.id],
|
||||
'product_uos_qty': move.product_qty - partial_qty[move.id], #TODO: put correct uos_qty
|
||||
'prodlot_id': False,
|
||||
'tracking_id': False,
|
||||
'reserved_quant_ids': quant_ids
|
||||
'reserved_quant_ids': list(set(possible_quants) - done_reserved_quants),
|
||||
})
|
||||
|
||||
if new_picking:
|
||||
@@ -1584,24 +1638,10 @@ class stock_picking(osv.osv):
|
||||
move_obj.write(cr, uid, [move.id], defaults)
|
||||
|
||||
|
||||
#take care of packaging for completed moves
|
||||
possible_quants = [x.id for x in move.reserved_quant_ids]
|
||||
#TODO define find_packaing_op_from_product (returns all ops with a result_package_id that touch this product)
|
||||
stock_operation_obj = self.pool.get('stock.pack.operation')
|
||||
operation_ids = stock_operation_obj.find_packaging_op_from_product(cr, uid, move.product_id, picking_id, context=context)
|
||||
quant_obj = self.pool.get('stock.quant')
|
||||
for op in stock_operation_obj.browse(cr, uid, operation_ids, context=context):
|
||||
if op.product_id:
|
||||
quant_tuples = quant_obj._get_quant_tuples(cr, uid, possible_quants, op.product_qty, context=context)
|
||||
quant_obj.real_split_quants(cr, uid, quant_tuples, context=context)
|
||||
quant_obj.write(cr, uid, [qt[O] for qt in quant_tuples], {'package_id': op.result_package_id.id}, context=context)
|
||||
elif op.quant_id:
|
||||
quant_tuples = quant_obj._get_quant_tuples(cr, uid, [op.quant_id.id], op.product_qty, context=context)
|
||||
quant_obj.real_split_quants(cr, uid, quant_tuples, context=context)
|
||||
quant_obj.write(cr, uid, [qt[O] for qt in quant_tuples], {'package_id': op.result_package_id.id}, context=context)
|
||||
elif op.package_id:
|
||||
#pack existing packs
|
||||
self.pool.get('stock.quant.package').write(cr, uid, op.package_id.id, {'parent_id': op.result_package_id.id}, context=context)
|
||||
|
||||
|
||||
self.make_packaging(cr, uid, picking_id, move, possible_quants, context=context)
|
||||
|
||||
|
||||
|
||||
@@ -1619,6 +1659,8 @@ class stock_picking(osv.osv):
|
||||
defaults.update(picking_id=new_picking)
|
||||
move_obj.write(cr, uid, [move.id], defaults)
|
||||
|
||||
possible_quants = [x.id for x in move.reserved_quant_ids]
|
||||
self.make_packaging(cr, uid, picking_id, move, possible_quants, context=context)
|
||||
# At first we confirm the new picking (if necessary)
|
||||
if new_picking:
|
||||
self.signal_button_confirm(cr, uid, [new_picking])
|
||||
@@ -1657,7 +1699,8 @@ class stock_picking(osv.osv):
|
||||
return res and res[1] or False
|
||||
|
||||
def _get_picking_for_packing_ui(self, cr, uid, context=None):
|
||||
return self.search(cr, uid, [('state', '=', 'assigned')], limit=1, context=context)[0]
|
||||
res = self.search(cr, uid, [('state', '=', 'assigned')], limit=1, context=context)
|
||||
return res and res[0] or False # TODO: what to do if nothing is left to do?
|
||||
|
||||
def action_done_from_packing_ui(self, cr, uid, picking_id, context=None):
|
||||
if context is None:
|
||||
@@ -1730,6 +1773,7 @@ class stock_picking(osv.osv):
|
||||
return self._get_picking_for_packing_ui(cr, uid, context=context)
|
||||
|
||||
def action_pack(self, cr, uid, picking_id, context=None):
|
||||
#put all the operations of the picking that aren't yet assigned to a package to this new one
|
||||
stock_operation_obj = self.pool.get('stock.pack.operation')
|
||||
package_obj = self.pool.get('stock.quant.package')
|
||||
#create a new empty stock.quant.package
|
||||
@@ -2062,7 +2106,7 @@ class stock_move(osv.osv):
|
||||
'scrapped': fields.related('location_dest_id','scrap_location',type='boolean',relation='stock.location',string='Scrapped', readonly=True),
|
||||
'type': fields.related('picking_id', 'type', type='selection', selection=[('out', 'Sending Goods'), ('in', 'Getting Goods'), ('internal', 'Internal')], string='Shipping Type'),
|
||||
'reserved_quant_ids': fields.one2many('stock.quant', 'reservation_id', 'Reserved quants'),
|
||||
'remaining_qty': fields.float('Remaining Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), states={'done': [('readonly', True)]}), # to be used in pick/pack new interface
|
||||
'remaining_qty': fields.float('Remaining Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), states={'done': [('readonly', True)]}), # to be used in pick/pack new interface # TODO change this in a functional field to ease the handling
|
||||
}
|
||||
|
||||
def _check_location(self, cr, uid, ids, context=None):
|
||||
@@ -2595,13 +2639,25 @@ class stock_move(osv.osv):
|
||||
#Convert UoM qty -> check rounding now in product_reserver
|
||||
#Split for source locations
|
||||
qty = uom_obj._compute_qty(cr, uid, move.product_uom.id, move.product_qty, move.product_id.uom_id.id)
|
||||
res2 = quant_obj.choose_quants(cr, uid, move.location_id.id, move.product_id.id, qty, prodlot_id = move.prodlot_id.id, context=context)
|
||||
print "Choose quants:", res2
|
||||
if res2:
|
||||
quant_obj.split_and_assign_quants(cr, uid, res2, move, context=context)
|
||||
#self.write(cr, uid, [move.id], {'state':'assigned'})
|
||||
|
||||
# Check if this move has not been chained from another move
|
||||
moves_from = self.search(cr, uid, [('move_dest_id', '=', move.id)], context=context)
|
||||
if moves_from and len(moves_from) == 1:
|
||||
move_from = moves_from[0]
|
||||
quants = quant_obj.search(cr, uid, [('history_ids', 'in', move_from), ('location_id', '=', move.location_id.id), ('reservation_id', '=', False)], context=context)
|
||||
if quants:
|
||||
quant_obj.write(cr, uid, quants, {'reservation_id':move.id}, context=context)
|
||||
done.append(move.id)
|
||||
pickings[move.picking_id.id] = 1
|
||||
else:
|
||||
|
||||
res2 = quant_obj.choose_quants(cr, uid, move.location_id.id, move.product_id.id, qty, prodlot_id = move.prodlot_id.id, context=context)
|
||||
print "Choose quants:", res2
|
||||
if res2:
|
||||
quant_obj.split_and_assign_quants(cr, uid, res2, move, context=context)
|
||||
#self.write(cr, uid, [move.id], {'state':'assigned'})
|
||||
done.append(move.id)
|
||||
pickings[move.picking_id.id] = 1
|
||||
print "Reserved quants:", move.reserved_quant_ids
|
||||
if done:
|
||||
count += len(done)
|
||||
@@ -2845,10 +2901,13 @@ class stock_move(osv.osv):
|
||||
#Check if the entire quantity has been transformed in to quants
|
||||
if qty_from_move > product_qty:
|
||||
quant_tuples = quant_obj.choose_quants(cr, uid, move.location_id.id, move.product_id.id, qty_from_move - product_qty, prodlot_id = move.prodlot_id.id, context=context)
|
||||
print quant_tuples
|
||||
create_neg_quant = True
|
||||
if quant_tuples:
|
||||
quant_obj.split_and_assign_quants(cr, uid, quant_tuples, move, context=context)
|
||||
product_qty = 0.0
|
||||
#Reread move:
|
||||
move = self.browse(cr, uid, move.id, context=context)
|
||||
for quant in move.reserved_quant_ids:
|
||||
product_qty += quant.qty
|
||||
if qty_from_move <= product_qty:
|
||||
@@ -2893,6 +2952,7 @@ class stock_move(osv.osv):
|
||||
todo = []
|
||||
|
||||
uom_obj = self.pool.get("product.uom")
|
||||
quant_obj = self.pool.get("stock.quant")
|
||||
#Do price calc on move
|
||||
quants = {}
|
||||
for move in self.browse(cr, uid, ids, context=context):
|
||||
@@ -2904,11 +2964,12 @@ class stock_move(osv.osv):
|
||||
else:
|
||||
#move quants should resolve negative quants in destination
|
||||
self.check_total_qty(cr, uid, ids, context=context)
|
||||
move = self.browse(cr, uid, move.id, context=context)
|
||||
reconciled_quants = self.pool.get("stock.quant").move_quants(cr, uid, [x.id for x in move.reserved_quant_ids], move, context=context)
|
||||
quants[move.id] += reconciled_quants
|
||||
self.splitforputaway(cr, uid, ids, context=context)
|
||||
|
||||
#Do price calculation on move -> Should pass Quants here -> is a dictionary
|
||||
#Do price calculation on move -> Should pass reconciled Quants -> is a dictionary
|
||||
matchresults = self.price_calculation(cr, uid, ids, quants, context=context)
|
||||
|
||||
for move in self.browse(cr, uid, ids, context=context):
|
||||
@@ -2926,6 +2987,12 @@ class stock_move(osv.osv):
|
||||
self.write(cr, uid, [move.id], {'move_history_ids': [(4, move.move_dest_id.id)]})
|
||||
if move.move_dest_id.state in ('waiting', 'confirmed'):
|
||||
self.force_assign(cr, uid, [move.move_dest_id.id], context=context)
|
||||
#We can take over used quants in this move to be propagated to next move
|
||||
#TODO should take into account split quantities?
|
||||
quants = quant_obj.search(cr, uid, [('history_ids', 'in', move.id), ('location_id', '=', move.location_dest_id.id), ('reservation_id', '=', False)], context=context)
|
||||
if quants:
|
||||
print "PROPAGATE QUANTS: ", quants
|
||||
quant_obj.write(cr, uid, quants, {'reservation_id':move.move_dest_id.id}, context=context)
|
||||
if move.move_dest_id.picking_id:
|
||||
wf_service.trg_write(uid, 'stock.picking', move.move_dest_id.picking_id.id, cr)
|
||||
if move.move_dest_id.auto_validate:
|
||||
@@ -3802,23 +3869,33 @@ class stock_package(osv.osv):
|
||||
def action_copy(self, cr, uid, ids, context=None):
|
||||
quant_obj = self.pool.get('stock.quant')
|
||||
stock_operation_obj = self.pool.get('stock.pack.operation')
|
||||
#put all the operations of the picking that aren't yet assigned to a package to this new one
|
||||
#search all the operations of given package
|
||||
operation_ids = stock_operation_obj.search(cr, uid, [('result_package_id', 'in', ids)], context=context)
|
||||
#create a new empty stock.quant.package
|
||||
package_id = self.create(cr, uid, {}, context=context)
|
||||
new_ops = []
|
||||
#copy all operation and set the newly created package as result_package_id
|
||||
for op in operation_ids:
|
||||
new_ops += [stock_operation_obj.copy(cr, uid, op, {'result_package_id': package_id}, context=context)]
|
||||
for operation in stock_operation_obj.browse(cr, uid, new_ops, context=context):
|
||||
if operation.product_id:
|
||||
todo_on_moves, todo_on_operations = stock_operation_obj._search_and_increment(cr, uid, operation.picking_id.id, ('product_id', '=', operation.product_id.id), context=context)
|
||||
elif operation.quant_id:
|
||||
todo_on_moves, todo_on_operations = self._deal_with_quants(cr, uid, operation.picking_id, [operation.quant_id.id], context=context)
|
||||
elif operation.package_id:
|
||||
included_package_ids = self.search(cr, uid, [('parent_id', 'child_of', [operation.package_id.id])], context=context)
|
||||
included_quant_ids = quant_obj.search(cr, uid, [('package_id', 'in', included_package_ids)], context=context)
|
||||
todo_on_moves, todo_on_operations = self._deal_with_quants(cr, uid, operation.picking_id.id, included_quant_ids, context=context)
|
||||
return {'warnings': '', 'moves_to_update': todo_on_moves, 'operations_to_update': todo_on_operations}
|
||||
|
||||
# for operation in stock_operation_obj.browse(cr, uid, new_ops, context=context):
|
||||
# if operation.product_id:
|
||||
# todo_on_moves, todo_on_operations = stock_operation_obj._search_and_increment(cr, uid, operation.picking_id.id, ('product_id', '=', operation.product_id.id), context=context)
|
||||
# elif operation.quant_id:
|
||||
# todo_on_moves, todo_on_operations = self._deal_with_quants(cr, uid, operation.picking_id, [operation.quant_id.id], context=context)
|
||||
# elif operation.package_id:
|
||||
# included_package_ids = self.search(cr, uid, [('parent_id', 'child_of', [operation.package_id.id])], context=context)
|
||||
# included_quant_ids = quant_obj.search(cr, uid, [('package_id', 'in', included_package_ids)], context=context)
|
||||
# todo_on_moves, todo_on_operations = self._deal_with_quants(cr, uid, operation.picking_id.id, included_quant_ids, context=context)
|
||||
# return {'warnings': '', 'moves_to_update': todo_on_moves, 'operations_to_update': todo_on_operations}
|
||||
|
||||
def find_all_quants(self, cr, uid, package_record, context=None):
|
||||
''' find all the quants in the given package (browse record) recursively'''
|
||||
res = []
|
||||
for child in package_record.children_ids:
|
||||
res += self.find_all_quants(cr, uid, child, context=context)
|
||||
res += [qt.id for qt in package_record.quant_ids]
|
||||
return res
|
||||
|
||||
#def action_delete(self, cr, uid, ids, context=None):
|
||||
# #no need, we use unlink of ids and with the ondelete = cascade it will work flawlessly
|
||||
@@ -3854,9 +3931,11 @@ class stock_pack_operation(osv.osv):
|
||||
return [quant.product_id.id for quant in quant_obj.browse(cr, uid, included_quant_ids, context=context)]
|
||||
|
||||
def find_packaging_op_from_product(self, cr, uid, product_id, picking_id, context=None):
|
||||
#returns all ops that touches this product
|
||||
#TOCHECK: don't we need to take only the ops with a result_package_id != False ?
|
||||
res = []
|
||||
op_ids = self.search(cr, uid, [('picking_id', '=', picking_id)], context=context)
|
||||
for operation in self.browse(cr, uid, op_id, context=context):
|
||||
for operation in self.browse(cr, uid, op_ids, context=context):
|
||||
if operation.product_id and operation.product_id.id == product_id:
|
||||
res += [operation.id]
|
||||
if operation.quant_id and operation.quant_id.product_id.id == product_id:
|
||||
@@ -3865,7 +3944,6 @@ class stock_pack_operation(osv.osv):
|
||||
all_quants = self.pool.get('stock.quant.package').search(cr, uid, [('parent_id', 'child_of', [operation.package_id.id])], context=context)
|
||||
if any([self.pool.get('stock.quant').browse(cr, uid, quant, context=context).product_id.id == product_id for quant in all_quants]):
|
||||
res += [operation.id]
|
||||
|
||||
return res
|
||||
|
||||
def _search_and_increment(self, cr, uid, picking_id, key, context=None):
|
||||
|
||||
Reference in New Issue
Block a user