From 305816d6206c56ff7ae54fd9b244f7fe12f355a3 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 16 Sep 2013 09:52:08 +0200 Subject: [PATCH] [FIX] stock, inventory: rely on stock_move.action_assign() to assign/create the quants in order to make sure that a quant may be moved from an internal location to another in the inventory process (and thus make sure that there is no loss of information (like the cost or date) bzr revid: qdp-launchpad@openerp.com-20130916075208-8033yt2q51lrv8f9 --- addons/stock/stock.py | 43 +++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 9b647656a1f..7ca6a87c960 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -236,7 +236,7 @@ class stock_quant(osv.osv): self._quant_reconcile_negative(cr, uid, quant, context=context) return quant - def quants_get(self, cr, uid, location, product, qty, domain=None, prefered_order=False, reservedcontext=None, context=None): + def quants_get(self, cr, uid, location, product, qty, domain=None, prefered_order=False, reservedcontext=None, restrict_lot_id=False, restrict_partner_id=False, context=None): """ Use the removal strategies of product to search for the correct quants If you inherit, put the super at the end of your method. @@ -247,12 +247,16 @@ class stock_quant(osv.osv): :lot_id NOT USED YET ! """ result = [] - domain = domain or [('qty','>',0.0)] + domain = domain or [('qty', '>', 0.0)] + if restrict_partner_id: + domain += [('owner_id', '=', restrict_partner_id)] + if restrict_lot_id: + domain += [('lot_id', '=', restrict_lot_id)] if location: removal_strategy = self.pool.get('stock.location').get_removal_strategy(cr, uid, location, product, context=context) or 'fifo' - if removal_strategy=='fifo': + if removal_strategy == 'fifo': result += self._quants_get_fifo(cr, uid, location, product, qty, domain, prefered_order=prefered_order, context=context) - elif removal_strategy=='lifo': + elif removal_strategy == 'lifo': result += self._quants_get_lifo(cr, uid, location, product, qty, domain, prefered_order=prefered_order, context=context) else: raise osv.except_osv(_('Error!'), _('Removal strategy %s not implemented.' % (removal_strategy,))) @@ -1044,7 +1048,6 @@ class stock_production_lot(osv.osv): 'product_id': fields.many2one('product.product', 'Product', required=True, domain=[('type', '<>', 'service')]), 'quant_ids': fields.one2many('stock.quant', 'lot_id', 'Quants'), 'create_date': fields.datetime('Creation Date'), -# 'partner_id': fields.many2one('res.partner', 'Owner'), } _defaults = { 'name': lambda x, y, z, c: x.pool.get('ir.sequence').get(y, z, 'stock.lot.serial'), @@ -1250,6 +1253,8 @@ class stock_move(osv.osv): 'origin_returned_move_id': fields.many2one('stock.move', 'Origin return move', help='move that created the return move'), 'returned_move_ids': fields.one2many('stock.move', 'origin_returned_move_id', 'All returned moves', help='Optional: all returned moves created from this move'), 'availability': fields.function(_get_product_availability, type='float', string='Availability'), + 'restrict_lot_id': fields.many2one('stock.production.lot', 'Lot', help="Technical field used to depict a restriction on the lot of quants to consider when marking this move as 'done'"), + 'restrict_partner_id': fields.many2one('res.partner', 'Owner ', help="Technical field used to depict a restriction on the ownership of quants to consider when marking this move as 'done'"), } def copy(self, cr, uid, id, default=None, context=None): @@ -1544,7 +1549,7 @@ class stock_move(osv.osv): dp.append(str(q.id)) qty -= q.qty domain = ['|', ('reservation_id', '=', False), ('reservation_id', '=', move.id)] - quants = quant_obj.quants_get(cr, uid, move.location_id, move.product_id, qty, domain=domain, prefered_order = dp and ('id not in ('+','.join(dp)+')') or False, context=context) + quants = quant_obj.quants_get(cr, uid, move.location_id, move.product_id, qty, domain=domain, prefered_order = dp and ('id not in ('+','.join(dp)+')') or False, restrict_lot_id=move.restrict_lot_id.id, restrict_partner_id=move.restrict_partner_id.id, context=context) #Will only reserve physical quants, no negative quant_obj.quants_reserve(cr, uid, quants, move, context=context) # the total quantity is provided by existing quants @@ -1865,15 +1870,17 @@ class stock_inventory(osv.osv): if not inv.move_ids: self.action_check(cr, uid, [inv.id], context=context) inv.refresh() - move_obj.action_done(cr, uid, [x.id for x in inv.move_ids], context=context) + #the action_done on stock_move has to be done in 2 steps: + #first, we start moving the products from stock to inventory loss + move_obj.action_done(cr, uid, [x.id for x in inv.move_ids if x.location_id.usage == 'internal'], context=context) + #then, we move from inventory loss. This 2 steps process is needed because some moved quant may need to be put again in stock + move_obj.action_done(cr, uid, [x.id for x in inv.move_ids if x.location_id.usage != 'internal'], context=context) self.write(cr, uid, [inv.id], {'state': 'done', 'date_done': time.strftime('%Y-%m-%d %H:%M:%S')}, context=context) return True def _create_stock_move(self, cr, uid, inventory, todo_line, context=None): stock_move_obj = self.pool.get('stock.move') product_obj = self.pool.get('product.product') - quant_obj = self.pool.get('stock.quant') - location_obj = self.pool.get('stock.location') inventory_location_id = product_obj.browse(cr, uid, todo_line['product_id'], context=context).property_stock_inventory.id vals = { 'name': _('INV:') + (inventory.name or ''), @@ -1883,6 +1890,8 @@ class stock_inventory(osv.osv): 'company_id': inventory.company_id.id, 'inventory_id': inventory.id, 'state': 'assigned', + 'restrict_lot_id': todo_line.get('prod_lot_id'), + 'restrict_partner_id': todo_line.get('partner_id'), } if todo_line['product_qty'] < 0: @@ -1895,21 +1904,7 @@ class stock_inventory(osv.osv): vals['location_id'] = todo_line['location_id'] vals['location_dest_id'] = inventory_location_id vals['product_uom_qty'] = todo_line['product_qty'] - move_id = stock_move_obj.create(cr, uid, vals, context=context) - move = stock_move_obj.browse(cr, uid, move_id, context=context) - #create the quants, and set the quants on the move - source_location = location_obj.browse(cr, uid, vals['location_id'], context=context) - product = self.pool.get('product.product').browse(cr, uid, vals['product_id'], context=context) - dom = [('owner_id', '=', todo_line.get('partner_id')), ('lot_id', '=', todo_line.get('prod_lot_id')), ('qty', '>', 0)] - quant_ids = [] - for quant, qty in quant_obj.quants_get(cr, uid, source_location, product, vals['product_uom_qty'], domain=dom, context=context): - if quant: - #split - quant_obj._quant_split(cr, uid, quant, qty, context=context) - else: - quant = quant_obj._quant_create(cr, uid, qty, move, lot_id=todo_line.get('prod_lot_id'), owner_id=todo_line.get('partner_id'), force_location=move.location_id, context=context) - quant_ids.append(quant.id) - quant_obj.write(cr, uid, quant_ids, {'reservation_id': move_id}, context=context) + return stock_move_obj.create(cr, uid, vals, context=context) def action_check(self, cr, uid, ids, context=None): """ Checks the inventory and computes the stock move to do