diff --git a/stock_available_immediately/product.py b/stock_available_immediately/product.py index 05d8ad2e7..491e44d1d 100644 --- a/stock_available_immediately/product.py +++ b/stock_available_immediately/product.py @@ -19,18 +19,15 @@ # ############################################################################## -from openerp import models, fields, api +from openerp import models -class ProductTemplate(models.Model): +class Product(models.Model): """Subtract incoming qty from immediately_usable_qty""" - _inherit = 'product.template' + _inherit = 'product.product' - @api.depends('virtual_available') - def _product_available(self): + def _immediately_usable_qty(self): """Ignore the incoming goods in the quantity available to promise""" - super(ProductTemplate, self)._product_available() + super(Product, self)._immediately_usable_qty() for product in self: product.immediately_usable_qty -= product.incoming_qty - - immediately_usable_qty = fields.Float(compute='_product_available') diff --git a/stock_available_immediately/tests/__init__.py b/stock_available_immediately/tests/__init__.py new file mode 100644 index 000000000..84148ecde --- /dev/null +++ b/stock_available_immediately/tests/__init__.py @@ -0,0 +1 @@ +from . import test_stock_available_immediately diff --git a/stock_available_immediately/tests/test_stock_available_immediately.py b/stock_available_immediately/tests/test_stock_available_immediately.py new file mode 100644 index 000000000..2c46f6460 --- /dev/null +++ b/stock_available_immediately/tests/test_stock_available_immediately.py @@ -0,0 +1,120 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Therp BV +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +from openerp.tests.common import TransactionCase + + +class testStockLogisticsWarehouse(TransactionCase): + + def test01_stock_levels(self): + """checking that immediately_usable_qty actually reflects \ +the variations in stock, both on product and template""" + moveObj = self.env['stock.move'] + productObj = self.env['product.product'] + templateObj = self.env['product.template'] + supplier_location = self.env.ref('stock.stock_location_suppliers') + stock_location = self.env.ref('stock.stock_location_stock') + customer_location = self.env.ref('stock.stock_location_customers') + uom_unit = self.env.ref('product.product_uom_unit') + + # Create product template + templateAB = templateObj.create( + {'name': 'templAB', + 'uom_id': uom_unit.id, + }) + + # Create product A and B + productA = productObj.create( + {'name': 'product A', + 'standard_price': 1, + 'type': 'product', + 'uom_id': uom_unit.id, + 'default_code': 'A', + 'product_tmpl_id': templateAB.id, + }) + + productB = productObj.create( + {'name': 'product B', + 'standard_price': 1, + 'type': 'product', + 'uom_id': uom_unit.id, + 'default_code': 'B', + 'product_tmpl_id': templateAB.id, + }) + + # Create a stock move from INCOMING to STOCK + stockMoveInA = moveObj.create( + {'location_id': supplier_location.id, + 'location_dest_id': stock_location.id, + 'name': 'MOVE INCOMING -> STOCK ', + 'product_id': productA.id, + 'product_uom': productA.uom_id.id, + 'product_uom_qty': 2, + }) + + stockMoveInB = moveObj.create( + {'location_id': supplier_location.id, + 'location_dest_id': stock_location.id, + 'name': 'MOVE INCOMING -> STOCK ', + 'product_id': productB.id, + 'product_uom': productB.uom_id.id, + 'product_uom_qty': 3, + }) + + def compare_product_usable_qty(product, value): + # Refresh, because the function field is not recalculated between + # transactions + product.refresh() + self.assertEqual(product.immediately_usable_qty, value) + + compare_product_usable_qty(productA, 0) + compare_product_usable_qty(templateAB, 0) + + stockMoveInA.action_confirm() + compare_product_usable_qty(productA, 0) + compare_product_usable_qty(templateAB, 0) + + stockMoveInA.action_assign() + compare_product_usable_qty(productA, 0) + compare_product_usable_qty(templateAB, 0) + + stockMoveInA.action_done() + compare_product_usable_qty(productA, 2) + compare_product_usable_qty(templateAB, 2) + + # will directly trigger action_done on productB + stockMoveInB.action_done() + compare_product_usable_qty(productA, 2) + compare_product_usable_qty(productB, 3) + compare_product_usable_qty(templateAB, 5) + + # Create a stock move from STOCK to CUSTOMER + stockMoveOutA = moveObj.create( + {'location_id': stock_location.id, + 'location_dest_id': customer_location.id, + 'name': ' STOCK --> CUSTOMER ', + 'product_id': productA.id, + 'product_uom': productA.uom_id.id, + 'product_uom_qty': 1, + 'state': 'confirmed', + }) + + stockMoveOutA.action_done() + compare_product_usable_qty(productA, 1) + compare_product_usable_qty(templateAB, 4)