diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 85af75c9cd0..4bd984b6558 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -2644,14 +2644,6 @@ class stock_inventory(osv.osv): self.pool.get('stock.inventory.line').write(cr, uid, line_ids, {'product_qty': 0}) return True - def _inventory_line_hook(self, cr, uid, inventory_line, move_vals): - """ Creates a stock move from an inventory line - @param inventory_line: - @param move_vals: - @return: - """ - return self.pool.get('stock.move').create(cr, uid, move_vals) - def action_done(self, cr, uid, ids, context=None): """ Finish the inventory @return: True @@ -2670,35 +2662,7 @@ class stock_inventory(osv.osv): #as they will be moved to inventory loss, and other quants will be created to the encoded quant location. This is a normal behavior #as quants cannot be reuse from inventory location (users can still manually move the products before/after the inventory if they want). move_obj = self.pool.get('stock.move') - move_obj.action_done(cr, uid, [x.id for x in inv.move_ids], context=context) - - 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') - inventory_location_id = product_obj.browse(cr, uid, todo_line['product_id'], context=context).property_stock_inventory.id - vals = { - 'name': _('INV:') + (inventory.name or ''), - 'product_id': todo_line['product_id'], - 'product_uom': todo_line['product_uom_id'], - 'date': inventory.date, - '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: - #found more than expected - vals['location_id'] = inventory_location_id - vals['location_dest_id'] = todo_line['location_id'] - vals['product_uom_qty'] = -todo_line['product_qty'] - else: - #found less than expected - vals['location_id'] = todo_line['location_id'] - vals['location_dest_id'] = inventory_location_id - vals['product_uom_qty'] = todo_line['product_qty'] - return stock_move_obj.create(cr, uid, vals, context=context) + move_obj.action_done(cr, uid, [x.id for x in inv.move_ids if x.state != 'done'], context=context) def action_check(self, cr, uid, ids, context=None): """ Checks the inventory and computes the stock move to do @@ -2712,13 +2676,14 @@ class stock_inventory(osv.osv): stock_move_obj.unlink(cr, uid, move_ids, context=context) for line in inventory.line_ids: #compare the checked quantities on inventory lines to the theorical one - inventory_line_obj._resolve_inventory_line(cr, uid, line, context=context) + stock_move = inventory_line_obj._resolve_inventory_line(cr, uid, line, context=context) def action_cancel_draft(self, cr, uid, ids, context=None): """ Cancels the stock move and change inventory state to draft. @return: True """ for inv in self.browse(cr, uid, ids, context=context): + self.write(cr, uid, [inv.id], {'line_ids': [(5,)]}, context=context) self.pool.get('stock.move').action_cancel(cr, uid, [x.id for x in inv.move_ids], context=context) self.write(cr, uid, [inv.id], {'state': 'draft'}, context=context) return True @@ -2869,6 +2834,7 @@ class stock_inventory_line(osv.osv): def _resolve_inventory_line(self, cr, uid, inventory_line, context=None): stock_move_obj = self.pool.get('stock.move') + quant_obj = self.pool.get('stock.quant') diff = inventory_line.theoretical_qty - inventory_line.product_qty if not diff: return @@ -2895,7 +2861,24 @@ class stock_inventory_line(osv.osv): vals['location_id'] = inventory_line.location_id.id vals['location_dest_id'] = inventory_location_id vals['product_uom_qty'] = diff - return stock_move_obj.create(cr, uid, vals, context=context) + move_id = stock_move_obj.create(cr, uid, vals, context=context) + move = stock_move_obj.browse(cr, uid, move_id, context=context) + if diff > 0: + domain = [('qty', '>', 0.0), ('package_id', '=', inventory_line.package_id.id), ('lot_id', '=', inventory_line.prod_lot_id.id)] + preferred_domain_list = [[('reservation_id', '=', False)], [('reservation_id.inventory_id', '!=', inventory_line.inventory_id.id)]] + quants = quant_obj.quants_get_prefered_domain(cr, uid, move.location_id, move.product_id, move.product_qty, domain=domain, prefered_domain_list=preferred_domain_list, restrict_partner_id=move.restrict_partner_id.id, context=context) + quant_obj.quants_reserve(cr, uid, quants, move, context=context) + elif inventory_line.package_id: + stock_move_obj.action_done(cr, uid, move_id, context=context) + quants = [x.id for x in move.quant_ids] + quant_obj.write(cr, uid, quants, {'package_id': inventory_line.package_id.id}, context=context) + res = quant_obj.search(cr, uid, [('qty', '<', 0.0), ('product_id', '=', move.product_id.id), + ('location_id', '=', move.location_dest_id.id), ('package_id', '!=', False)], limit=1, context=context) + if res: + for quant in move.quant_ids: + if quant.location_id.id == move.location_dest_id.id: #To avoid we take a quant that was reconcile already + quant_obj._quant_reconcile_negative(cr, uid, quant, move, context=context) + return move_id # Should be left out in next version def restrict_change(self, cr, uid, ids, theoretical_qty, context=None): diff --git a/addons/stock/tests/test_stock_flow.py b/addons/stock/tests/test_stock_flow.py index 32c9e5e3eb0..bd3302b5be9 100644 --- a/addons/stock/tests/test_stock_flow.py +++ b/addons/stock/tests/test_stock_flow.py @@ -1095,3 +1095,55 @@ class TestStockFlow(TestStockCommon): total_qty = [quant.qty for quant in quants] self.assertEqual(sum(total_qty), 4000, 'Expecting 4000 kg , got %.4f on location stock!' % (sum(total_qty))) self.assertEqual(productKG.qty_available, 4000, 'Expecting 4000 kg , got %.4f of quantity available!' % (productKG.qty_available)) + + + #-------------------------------------------------------- + # TEST PARTIAL INVENTORY WITH PACKS and LOTS + #--------------------------------------------------------- + + packproduct = self.ProductObj.create({'name': 'Pack Product', 'uom_id': self.uom_unit.id, 'uom_po_id': self.uom_unit.id}) + lotproduct = self.ProductObj.create({'name': 'Lot Product', 'uom_id': self.uom_unit.id, 'uom_po_id': self.uom_unit.id}) + inventory = self.InvObj.create({'name': 'Test Partial and Pack', + 'filter': 'partial', + 'location_id': self.stock_location}) + inventory.prepare_inventory() + pack_obj = self.env['stock.quant.package'] + lot_obj = self.env['stock.production.lot'] + pack1 = pack_obj.create({'name': 'PACK00TEST1'}) + pack2 = pack_obj.create({'name': 'PACK00TEST2'}) + lot1 = lot_obj.create({'name': 'Lot001', 'product_id': lotproduct.id}) + move = self.MoveObj.search([('product_id', '=', productKG.id), ('inventory_id', '=', inventory.id)], limit=1) + self.assertEqual(len(move), 0, "Partial filter should not create a lines upon prepare") + + line_vals = [] + line_vals += [{'location_id': self.stock_location, 'product_id': packproduct.id, 'product_qty': 10, 'product_uom_id': packproduct.uom_id.id}] + line_vals += [{'location_id': self.stock_location, 'product_id': packproduct.id, 'product_qty': 20, 'product_uom_id': packproduct.uom_id.id, 'package_id': pack1.id}] + line_vals += [{'location_id': self.stock_location, 'product_id': lotproduct.id, 'product_qty': 30, 'product_uom_id': lotproduct.uom_id.id, 'prod_lot_id': lot1.id}] + line_vals += [{'location_id': self.stock_location, 'product_id': lotproduct.id, 'product_qty': 25, 'product_uom_id': lotproduct.uom_id.id, 'prod_lot_id': False}] + inventory.write({'line_ids': [(0, 0, x) for x in line_vals]}) + inventory.action_done() + self.assertEqual(packproduct.qty_available, 30, "Wrong qty available for packproduct") + self.assertEqual(lotproduct.qty_available, 55, "Wrong qty available for lotproduct") + quants = self.StockQuantObj.search([('product_id', '=', packproduct.id), ('location_id', '=', self.stock_location), ('package_id', '=', pack1.id)]) + total_qty = sum([quant.qty for quant in quants]) + self.assertEqual(total_qty, 20, 'Expecting 20 units on package 1 of packproduct, but we got %.4f on location stock!' % (total_qty)) + + #Create an inventory that will put the lots without lot to 0 and check that taking without pack will not take it from the pack + inventory2 = self.InvObj.create({'name': 'Test Partial Lot and Pack2', + 'filter': 'partial', + 'location_id': self.stock_location}) + inventory2.prepare_inventory() + line_vals = [] + line_vals += [{'location_id': self.stock_location, 'product_id': packproduct.id, 'product_qty': 20, 'product_uom_id': packproduct.uom_id.id}] + line_vals += [{'location_id': self.stock_location, 'product_id': lotproduct.id, 'product_qty': 0, 'product_uom_id': lotproduct.uom_id.id, 'prod_lot_id': False}] + line_vals += [{'location_id': self.stock_location, 'product_id': lotproduct.id, 'product_qty': 10, 'product_uom_id': lotproduct.uom_id.id, 'prod_lot_id': lot1.id}] + inventory2.write({'line_ids': [(0, 0, x) for x in line_vals]}) + inventory2.action_done() + self.assertEqual(packproduct.qty_available, 40, "Wrong qty available for packproduct") + self.assertEqual(lotproduct.qty_available, 10, "Wrong qty available for lotproduct") + quants = self.StockQuantObj.search([('product_id', '=', lotproduct.id), ('location_id', '=', self.stock_location), ('lot_id', '=', lot1.id)]) + total_qty = sum([quant.qty for quant in quants]) + self.assertEqual(total_qty, 10, 'Expecting 0 units lot of lotproduct, but we got %.4f on location stock!' % (total_qty)) + quants = self.StockQuantObj.search([('product_id', '=', lotproduct.id), ('location_id', '=', self.stock_location), ('lot_id', '=', False)]) + total_qty = sum([quant.qty for quant in quants]) + self.assertEqual(total_qty, 0, 'Expecting 0 units lot of lotproduct, but we got %.4f on location stock!' % (total_qty)) \ No newline at end of file