From e202c84b27140bc2aac9e93f6190f1ae73ea1964 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Tue, 18 Mar 2014 12:57:46 +0100 Subject: [PATCH] [REF] stock: assign picking by batch on confirmation of stock moves. This new version will work for confirmed move from elsewhere than the sale order bzr revid: qdp-launchpad@openerp.com-20140318115746-fixnxghkrlth38ze --- addons/purchase/purchase.py | 9 ++-- addons/sale/sale.py | 10 +---- addons/sale_stock/sale_stock.py | 15 ------- addons/stock/procurement.py | 18 ++++++-- addons/stock/stock.py | 74 +++++++++------------------------ 5 files changed, 40 insertions(+), 86 deletions(-) diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index 56eb12147c7..c68c8f42755 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -31,7 +31,6 @@ import openerp.addons.decimal_precision as dp from openerp.osv.orm import browse_record, browse_null from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT, DATETIME_FORMATS_MAP - class purchase_order(osv.osv): def _amount_all(self, cr, uid, ids, field_name, arg, context=None): @@ -164,11 +163,11 @@ class purchase_order(osv.osv): """ cr.execute(query, (tuple(ids), )) picks = cr.fetchall() - for pick in picks: - if not res.get(pick[1]): - res[pick[1]] = [pick[0]] + for pick_id, po_id in picks: + if not res.get(po_id): + res[po_id] = [pick_id] else: - res[pick[1]].append(pick[0]) + res[po_id].append(pick_id) return res STATE_SELECTION = [ diff --git a/addons/sale/sale.py b/addons/sale/sale.py index ebd9a6ac39a..9d50f868231 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -677,8 +677,6 @@ class sale_order(osv.osv): :return: True """ - if not context: - context = {} procurement_obj = self.pool.get('procurement.order') sale_line_obj = self.pool.get('sale.order.line') for order in self.browse(cr, uid, ids, context=context): @@ -704,11 +702,7 @@ class sale_order(osv.osv): proc_ids.append(proc_id) #Confirm procurement order such that rules will be applied on it #note that the workflow normally ensure proc_ids isn't an empty list - ctx = context.copy() - ctx["no_picking_assign"] = True - procurement_obj.run(cr, uid, proc_ids, context=ctx) - #Check all moves associated and do the picking_assign - procurement_obj.group_picking_assign(cr, uid, proc_ids, context=context) + procurement_obj.run(cr, uid, proc_ids, context=context) #if shipping was in exception and the user choose to recreate the delivery order, write the new status of SO if order.state == 'shipping_except': @@ -1177,5 +1171,3 @@ class procurement_order(osv.osv): 'sale_line_id': fields.many2one('sale.order.line', string='Sale Order Line'), } - def group_picking_assign(self, cr, uid, proc_ids, context=None): - return True diff --git a/addons/sale_stock/sale_stock.py b/addons/sale_stock/sale_stock.py index 37dcd1ad8b1..dbe64465047 100644 --- a/addons/sale_stock/sale_stock.py +++ b/addons/sale_stock/sale_stock.py @@ -453,18 +453,3 @@ class stock_picking(osv.osv): created_lines = sale_line_obj.invoice_line_create(cr, uid, sale_line_ids, context=context) invoice_line_obj.write(cr, uid, created_lines, {'invoice_id': invoice_id}, context=context) return invoice_id - - -class procurement_order(osv.osv): - _inherit = 'procurement.order' - - def group_picking_assign(self, cr, uid, proc_ids, context=None): - moves = [] - procurements = proc_ids - while procurements: - related_moves = [] - for proc in self.browse(cr, uid, procurements, context=context): - related_moves += proc.move_ids - procurements = self.search(cr, uid, [('move_dest_id', 'in', [x.id for x in related_moves])], context=context) - moves += related_moves - self.pool.get("stock.move")._group_picking_assign(cr, uid, moves, context=context) diff --git a/addons/stock/procurement.py b/addons/stock/procurement.py index d9e018f1cb0..79b5c3a827f 100644 --- a/addons/stock/procurement.py +++ b/addons/stock/procurement.py @@ -215,11 +215,23 @@ class procurement_order(osv.osv): return False move_obj = self.pool.get('stock.move') move_dict = self._run_move_create(cr, uid, procurement, context=context) - move_id = move_obj.create(cr, uid, move_dict, context=context) + move_obj.create(cr, uid, move_dict, context=context) self.message_post(cr, uid, [procurement.id], body=_("Supply Move created"), context=context) - move_obj.action_confirm(cr, uid, [move_id], context=context) return True - return super(procurement_order, self)._run(cr, uid, procurement, context) + return super(procurement_order, self)._run(cr, uid, procurement, context=context) + + def run(self, cr, uid, ids, context=None): + move_obj = self.pool.get('stock.move') + res = super(procurement_order, self).run(cr, uid, ids, context=context) + #after all the procurements are run, check if some created a draft stock move that needs to be confirmed + #(we do that in batch because it fasten the picking assignation and the picking state computation) + move_to_confirm_ids = [] + for procurement in self.browse(cr, uid, ids, context=context): + if procurement.state == "running" and procurement.rule_id and procurement.rule_id.action == "move": + move_to_confirm_ids += [m.id for m in procurement.move_ids if m.state == 'draft'] + if move_to_confirm_ids: + move_obj.action_confirm(cr, uid, move_to_confirm_ids, context=context) + return res def _check(self, cr, uid, procurement, context=None): ''' Implement the procurement checking for rules of type 'move'. The procurement will be satisfied only if all related diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 50452632c48..dd81a8e879d 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -946,13 +946,11 @@ class stock_picking(osv.osv): self.action_assign(cr, uid, picking_ids, context=context) self.do_prepare_partial(cr, uid, picking_ids, context=context) - def _picking_putaway_resolution(self, cr, uid, picking, product, putaway, context=None): if putaway.method == 'fixed' and putaway.location_spec_id: return putaway.location_spec_id.id return False - def _get_top_level_packages(self, cr, uid, quants_suggested_locations, context=None): """This method searches for the higher level packages that can be moved as a single operation, given a list of quants to move and their suggested destination, and returns the list of matching packages. @@ -1559,7 +1557,6 @@ class stock_move(osv.osv): res += [x.id for x in picking.move_lines] return res - _columns = { 'name': fields.char('Description', required=True, select=True), 'priority': fields.selection([('0', 'Not urgent'), ('1', 'Urgent')], 'Priority'), @@ -1923,25 +1920,20 @@ class stock_move(osv.osv): result['location_dest_id'] = loc_dest_id return {'value': result} - def _picking_assign(self, cr, uid, move, context=None): - if not context: - context = {} - if context.get("no_picking_assign") and context['no_picking_assign']: - return False - if move.picking_id or not move.picking_type_id: - return False - context = context or {} + def _picking_assign(self, cr, uid, move_ids, procurement_group, location_from, location_to, context=None): + """Assign a picking on the given move_ids, which is a list of move supposed to share the same procurement_group, location_from and location_to + (and company). Those attributes are also given as parameters. + """ pick_obj = self.pool.get("stock.picking") - picks = [] - group = move.group_id and move.group_id.id or False picks = pick_obj.search(cr, uid, [ - ('group_id', '=', group), - ('location_id', '=', move.location_id.id), - ('location_dest_id', '=', move.location_dest_id.id), + ('group_id', '=', procurement_group), + ('location_id', '=', location_from), + ('location_dest_id', '=', location_to), ('state', 'in', ['draft', 'confirmed', 'waiting'])], context=context) if picks: pick = picks[0] else: + move = self.browse(cr, uid, move_ids, context=context)[0] values = { 'origin': move.origin, 'company_id': move.company_id and move.company_id.id or False, @@ -1950,42 +1942,7 @@ class stock_move(osv.osv): 'picking_type_id': move.picking_type_id and move.picking_type_id.id or False, } pick = pick_obj.create(cr, uid, values, context=context) - move.write({'picking_id': pick}) - return True - - def _group_picking_assign(self, cr, uid, moves, context=None): - if not context: - context = {} - if context.get("no_picking_assign"): - return False - move_dict = {} - for move in moves: - group_by = (move.location_id, move.location_dest_id, move.group_id) - if not move_dict.get(group_by, False): - move_dict[group_by] = [move] - else: - move_dict[group_by].append(move) - pick_obj = self.pool.get("stock.picking") - for to_compare in move_dict.keys(): - picks = pick_obj.search(cr, uid, [ - ('group_id', '=', to_compare[2].id), - ('location_id', '=', to_compare[0].id), - ('location_dest_id', '=', to_compare[1].id), - ('state', 'in', ['draft', 'confirmed', 'waiting']), - ], context=context) - if picks: - pick = picks[0] - else: - move = move_dict[to_compare][0] - values = { - 'origin': move.origin, - 'company_id': move.company_id and move.company_id.id or False, - 'move_type': move.group_id and move.group_id.move_type or 'one', - 'partner_id': move.group_id and move.group_id.partner_id and move.group_id.partner_id.id or False, - 'picking_type_id': move.picking_type_id and move.picking_type_id.id or False, - } - pick = pick_obj.create(cr, uid, values, context=context) - self.write(cr, uid, [x.id for x in move_dict[to_compare]], {'picking_id': pick}, context=context) + return self.write(cr, uid, move_ids, {'picking_id': pick}, context=context) def onchange_date(self, cr, uid, ids, date, date_expected, context=None): """ On change of Scheduled Date gives a Move date. @@ -2007,6 +1964,7 @@ class stock_move(osv.osv): 'confirmed': [], 'waiting': [] } + to_assign = {} for move in self.browse(cr, uid, ids, context=context): state = 'confirmed' #if the move is preceeded, then it's waiting (if preceeding move is done, then action_assign has been called already and its state is already available) @@ -2019,9 +1977,13 @@ class stock_move(osv.osv): if move2.move_orig_ids: state = 'waiting' move2 = move2.split_from - states[state].append(move.id) - self._picking_assign(cr, uid, move, context=context) + + if not move.picking_id and move.picking_type_id: + key = (move.group_id.id, move.location_id.id, move.location_dest_id.id) + if key not in to_assign: + to_assign[key] = [] + to_assign[key].append(move.id) for move in self.browse(cr, uid, states['confirmed'], context=context): if move.procure_method == 'make_to_order': @@ -2032,6 +1994,10 @@ class stock_move(osv.osv): for state, write_ids in states.items(): if len(write_ids): self.write(cr, uid, write_ids, {'state': state}) + #assign picking in batch for all confirmed move that share the same details + for key, move_ids in to_assign.items(): + procurement_group, location_from, location_to = key + self._picking_assign(cr, uid, move_ids, procurement_group, location_from, location_to, context=context) moves = self.browse(cr, uid, ids, context=context) self._push_apply(cr, uid, moves, context=context) return ids