diff --git a/addons/product/tests/__init__.py b/addons/product/tests/__init__.py index 7c05b1bf791..6af057825cd 100644 --- a/addons/product/tests/__init__.py +++ b/addons/product/tests/__init__.py @@ -1 +1 @@ -from . import test_uom, test_pricelist +from . import common, test_uom, test_pricelist diff --git a/addons/product/tests/common.py b/addons/product/tests/common.py new file mode 100644 index 00000000000..fac4c1dba74 --- /dev/null +++ b/addons/product/tests/common.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- + +from odoo.tests import common + + +class TestProductCommon(common.SavepointCase): + + @classmethod + def setUpClass(cls): + super(TestProductCommon, cls).setUpClass() + + # Customer related data + cls.partner_1 = cls.env['res.partner'].create({ + 'name': 'Julia Agrolait', + 'email': 'julia@agrolait.example.com', + }) + + # Product environment related data + Uom = cls.env['product.uom'] + categ_unit = cls.env.ref('product.product_uom_categ_unit') + weight_unit = cls.env.ref('product.product_uom_categ_kgm') + cls.uom_unit = Uom.create({ + 'name': 'TestUnit', + 'category_id': categ_unit.id, + 'factor_inv': 1.0, + 'factor': 1.0, + 'uom_type': 'reference', + 'rounding': 0.000001}) + cls.uom_kunit = Uom.create({ + 'name': 'KTestUnit', + 'category_id': categ_unit.id, + 'factor_inv': 1000.0, + 'factor': 0.001, + 'uom_type': 'bigger', + 'rounding': 0.001}) + cls.uom_munit = Uom.create({ + 'name': 'mTestUnit', + 'category_id': categ_unit.id, + 'factor_inv': 0.001, + 'factor': 1000.0, + 'uom_type': 'smaller', + 'rounding': 0.001}) + cls.uom_weight = Uom.create({ + 'name': 'TestWeight', + 'category_id': weight_unit.id, + 'factor_inv': 1.0, + 'factor': 1.0, + 'uom_type': 'reference', + 'rounding': 0.000001 + }) + Product = cls.env['product.product'] + cls.product_1 = Product.create({ + 'name': 'TestProduct 1', + 'uom_id': cls.uom_unit.id, + 'uom_po_id': cls.uom_unit.id}) + cls.product_2 = Product.create({ + 'name': 'TestProduct 2', + 'uom_id': cls.uom_unit.id, + 'uom_po_id': cls.uom_unit.id}) + cls.product_3 = Product.create({ + 'name': 'TestProduct 3 (KTestUnit)', + 'uom_id': cls.uom_kunit.id, + 'uom_po_id': cls.uom_kunit.id}) + cls.product_4 = Product.create({ + 'name': 'TestProduct 4 (mTestUnit)', + 'uom_id': cls.uom_munit.id, + 'uom_po_id': cls.uom_munit.id}) diff --git a/addons/stock/__openerp__.py b/addons/stock/__openerp__.py index 7169f2b610b..54f573fd9c6 100644 --- a/addons/stock/__openerp__.py +++ b/addons/stock/__openerp__.py @@ -77,11 +77,8 @@ Dashboard / Reports for Inventory Management will include: 'data/web_planner_data.xml', ], 'test': [ - 'test/inventory.yml', - 'test/move.yml', 'test/procrule.yml', 'test/stock_users.yml', - 'test/shipment.yml', 'test/packing.yml', 'test/packingneg.yml', 'test/wiseoperator.yml', diff --git a/addons/stock/test/inventory.yml b/addons/stock/test/inventory.yml deleted file mode 100644 index 4bfc70d3dd1..00000000000 --- a/addons/stock/test/inventory.yml +++ /dev/null @@ -1,93 +0,0 @@ -- - In order to test the inventory, I create a new product -- - !record {model: product.product, id: inventory_product}: - name: inventory prod - type: product -- - I create an inventory for this product only -- - !record {model: stock.inventory, id: inventory_test0}: - name: Test - filter: product - product_id: inventory_product -- - I confirm the inventory and check that my inventory has no line, as the product is a new one. -- - !python {model: stock.inventory}: | - self.prepare_inventory(cr, uid, [ref('inventory_test0')], context=context) - inv = self.browse(cr, uid, ref('inventory_test0'), context=context) - assert len(inv.line_ids) == 0, "Wrong number of inventory lines." -- - I add an inventory line and say i have 10 products in stock -- - !record {model: stock.inventory.line, id: inventory_testline0}: - inventory_id: stock.inventory_test0 - product_uom_id: product.product_uom_unit - product_id: inventory_product - product_qty: 10 - location_id: stock.stock_location_14 -- - I Validate this inventory -- - !python {model: stock.inventory}: | - self.action_done(cr, uid, [ref('inventory_test0')], context=context) -- - I check that this inventory has a stock.move and a quant -- - !python {model: stock.inventory}: | - inv = self.browse(cr, uid, ref('inventory_test0'), context=context) - assert len(inv.move_ids) >= 1, "No move created for the inventory." - assert len(inv.move_ids[0].quant_ids) >= 1, "No quant created for this inventory" -- - I check that the quantity on hand is 10 on the location and its parent. -- - !python {model: product.product}: | - context['location'] = ref('stock.stock_location_14') - product = self.browse(cr, uid, ref('inventory_product'), context=context) - assert product.qty_available == 10, 'Expecting 10 products, got %.2f on location stock_location_14!' % (product.qty_available,) - context['location'] = ref('stock.stock_location_stock') - product = self.browse(cr, uid, ref('inventory_product'), context=context) - assert product.qty_available == 10, 'Expecting 10 products, got %.2f on location stock_location_stock!' % (product.qty_available,) -- - I check that the quantity on hand is 0 on a brother location -- - !python {model: product.product}: | - context['location'] = ref('stock.stock_location_components') - product = self.browse(cr, uid, ref('inventory_product'), context=context) - assert product.qty_available == 0, 'Expecting 0 products, got %.2f on location stock_location_components!' % (product.qty_available,) -- - I create another inventory -- - !record {model: stock.inventory, id: inventory_test1}: - name: second test inventory - filter: product - product_id: inventory_product -- - I confirm the inventory and check that my inventory has one line, with a quantity of 10. -- - !python {model: stock.inventory}: | - self.prepare_inventory(cr, uid, [ref('inventory_test1')], context=context) - inv = self.browse(cr, uid, ref('inventory_test1'), context=context) - assert inv.line_ids and len(inv.line_ids) == 1, "Wrong number of inventory lines." - assert inv.line_ids[0].product_qty == 10, "Wrong quantity in inventory line." - assert inv.line_ids[0].product_id.id == ref('inventory_product'), "Wrong product in inventory line." -- - I modify the inventory line and set the quantity to 20 product on this new inventory -- - !python {model: stock.inventory}: | - inv = self.browse(cr, uid, ref('inventory_test1'), context=context) - self.pool.get('stock.inventory.line').write(cr, uid, inv.line_ids[0].id, {'product_qty': 20}) -- - I Validate this inventory -- - !python {model: stock.inventory}: | - self.action_done(cr, uid, [ref('inventory_test1')], context=context) -- - I check that the quantity on hand is 20 on the location and it's parent. -- - !python {model: product.product}: | - context['location'] = ref('stock.stock_location_14') - product = self.browse(cr, uid, ref('inventory_product'), context=context) - assert product.qty_available == 20, 'Expecting 20 products, got %.2f on location stock_location_14!' % (product.qty_available,) - diff --git a/addons/stock/test/move.yml b/addons/stock/test/move.yml deleted file mode 100644 index c03a77e23b8..00000000000 --- a/addons/stock/test/move.yml +++ /dev/null @@ -1,108 +0,0 @@ -- - I first create a new product -- - !record {model: product.product, id: move_product}: - name: move prod - type: product -- - In order to test the negative quants, I create a move of 5 products from stock to customer -- - !record {model: stock.move, id: move_test0}: - name: Move Products - product_id: move_product - product_uom_qty: 5 - product_uom: product.product_uom_unit - location_id: stock.stock_location_stock - location_dest_id: stock.stock_location_customers -- - I confirm the move to be processed in the future -- - !python {model: stock.move}: | - self.action_confirm(cr, uid, [ref('move_test0')], context=context) -- - I check that the quantity on hand is 0 and virtual is -5 -- - !python {model: product.product}: | - context['location'] = False - product = self.browse(cr, uid, ref('move_product'), context=context) - assert product.qty_available == 0, 'Expecting 0 products in stock, got %.2f!' % (product.qty_available,) - assert product.virtual_available == -5.0, 'Expecting -5 products in virtual stock, got %.2f!' % (product.virtual_available,) -- - I validate the move -- - !python {model: stock.move}: | - self.action_done(cr, uid, [ref('move_test0')], context=context) -- - I check that the quantity on hand is -5 and 5 products are at customer location -- - !python {model: product.product}: | - context['location'] = False - product = self.browse(cr, uid, ref('move_product'), context=context) - assert product.qty_available == -5, 'Expecting -5 products in stock, got %.2f!' % (product.qty_available,) - - context['location'] = ref('stock.stock_location_customers') - product = self.browse(cr, uid, ref('move_product'), context=context) - assert product.qty_available == 5, 'Expecting 5 products in customer location, got %.2f!' % (product.qty_available,) -- - To compensate negative quants, I will receive 15 products from the supplier -- - !record {model: stock.move, id: move_test2}: - name: Move 15 Products - product_id: move_product - product_uom_qty: 15 - product_uom: product.product_uom_unit - location_id: stock.stock_location_suppliers - location_dest_id: stock.stock_location_stock -- - I confirm and validate the move -- - !python {model: stock.move}: | - self.action_confirm(cr, uid, [ref('move_test2')], context=context) - self.action_done(cr, uid, [ref('move_test2')], context=context) -- - I check that the quantity on hand is 10 -- - !python {model: product.product}: | - context['location'] = False - product = self.browse(cr, uid, ref('move_product'), context=context) - assert product.qty_available == 10, 'Expecting 10 products in stock, got %.2f!' % (product.qty_available,) - assert product.virtual_available == 10.0, 'Expecting 10 products in virtual stock, got %.2f!' % (product.virtual_available,) -- - I create a move of 2 products from stock to customer -- - !record {model: stock.move, id: move_test1}: - name: Move Products - product_id: move_product - product_uom_qty: 2 - product_uom: product.product_uom_unit - location_id: stock.stock_location_stock - location_dest_id: stock.stock_location_customers -- - I confirm the move to be processed in the future -- - !python {model: stock.move}: | - self.action_confirm(cr, uid, [ref('move_test1')], context=context) -- - I check that the quantity on hand is 10 and virtual is 8 -- - !python {model: product.product}: | - context['location'] = False - product = self.browse(cr, uid, ref('move_product'), context=context) - assert product.qty_available == 10, 'Expecting 10 products in stock, got %.2f!' % (product.qty_available,) - assert product.virtual_available == 8.0, 'Expecting 8 products in virtual stock, got %.2f!' % (product.virtual_available,) -- - I validate the move -- - !python {model: stock.move}: | - self.action_done(cr, uid, [ref('move_test1')], context=context) -- - I check that the quantity on hand is 8 and 7 products are at customer location -- - !python {model: product.product}: | - context['location'] = False - product = self.browse(cr, uid, ref('move_product'), context=context) - assert product.qty_available == 8, 'Expecting 10 products in stock, got %.2f!' % (product.qty_available,) - - context['location'] = ref('stock.stock_location_customers') - product = self.browse(cr, uid, ref('move_product'), context=context) - assert product.qty_available == 7, 'Expecting 7 products in customer location, got %.2f!' % (product.qty_available,) diff --git a/addons/stock/test/shipment.yml b/addons/stock/test/shipment.yml deleted file mode 100644 index ed670d69caf..00000000000 --- a/addons/stock/test/shipment.yml +++ /dev/null @@ -1,66 +0,0 @@ -- - Stock manager can only test whole process related to Shipment, so we check data with stock manager. -- - !context - uid: 'res_users_stock_manager' -- - I confirm incoming move of 50 kgm Ice-cream -- - !python {model: stock.move}: | - incoming_move = self.browse(cr, uid, ref("incomming_shipment_icecream")) - self.action_confirm(cr, uid, [incoming_move.id]) -- - I receive 40kgm Ice-cream so It will make backorder of incomming shipment for 10 kgm. -- - !python {model: stock.picking}: | - pick = self.browse(cr, uid, ref("incomming_shipment"), context=context) - newid = self.pool.get('stock.pack.operation').create(cr, uid, { - 'picking_id': pick.id, - 'product_id': ref('product_icecream'), - 'product_uom_id': ref('product.product_uom_kgm'), - 'product_qty': 40, - 'qty_done': 40, - 'location_id': ref('stock.stock_location_suppliers'), - 'location_dest_id': ref('stock.stock_location_14') - }) - context.update({'active_model': 'stock.picking', 'active_id': ref('incomming_shipment'), 'active_ids': [ref('incomming_shipment')]}) - pick = self.browse(cr, uid, pick.id, context=context) - pick.do_transfer() -- - I check backorder shipment after received partial shipment and check remaining shipment. -- - !python {model: stock.picking}: | - shipment = self.browse(cr, uid, ref("incomming_shipment")) - for move_line in shipment.move_lines: - assert move_line.product_qty == 40, "Qty in shipment does not correspond." - assert move_line.state == 'done', "Move line of shipment should be closed." - backorder_id = self.search(cr, uid, [('backorder_id', '=', ref("incomming_shipment"))],context=context) - backorder = self.browse(cr, uid, backorder_id)[0] - for move_line in backorder.move_lines: - assert move_line.product_qty == 10, "Qty in backorder does not correspond." - assert (move_line.state == 'assigned' or move_line.state == 'waiting' or move_line.state == 'confirmed'), "Move line of backorder should be assigned, confirmed or waiting." - context.update({'active_model': 'stock.picking', 'active_id': backorder_id[0], 'active_ids': backorder_id}) -- - I receive the remaining 10kgm Ice-cream from the backorder. -- - !python {model: stock.picking}: | - backorder_id = self.search(cr, uid, [('backorder_id', '=', ref("incomming_shipment"))],context=context) - backorder = self.browse(cr, uid, backorder_id, context=context)[0] - self.pool.get('stock.pack.operation').create(cr, uid, { - 'picking_id': backorder.id, - 'product_id': ref('product_icecream'), - 'product_uom_id': ref('product.product_uom_kgm'), - 'product_qty': 10, - 'qty_done': 10, - 'location_id': ref('stock.stock_location_suppliers'), - 'location_dest_id': ref('stock.stock_location_14') - }) - backorder.do_transfer() -- - I check incomming shipment after receipt. -- - !python {model: stock.picking}: | - shipment = self.browse(cr, uid, self.search(cr, uid, [('backorder_id', '=', ref("incomming_shipment"))]))[0] - assert shipment.state == 'done', "shipment should be close after received." - for move_line in shipment.move_lines: - assert move_line.state == 'done', "Move line should be closed." diff --git a/addons/stock/tests/__init__.py b/addons/stock/tests/__init__.py index c372f3c8fb5..e51047f6353 100644 --- a/addons/stock/tests/__init__.py +++ b/addons/stock/tests/__init__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from . import test_stock_flow -from . import test_owner_available -from . import test_resupply +import test_product +# import test_warehouse +# import test_shipment diff --git a/addons/stock/tests/common2.py b/addons/stock/tests/common2.py new file mode 100644 index 00000000000..4204b88afe5 --- /dev/null +++ b/addons/stock/tests/common2.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- + +from odoo.addons.product.tests import common + + +class TestStockCommon(common.TestProductCommon): + + def _create_pack_operation(self, product, product_qty, picking_id, **values): + PackOperation = self.env['stock.pack.operation'].sudo(self.user_stock_manager) + vals = PackOperation.product_id_change(product.id, False, product_qty)['value'] + vals.update({ + 'picking_id': picking_id.id, + 'product_id': product.id, + 'product_qty': product_qty, + 'qty_done': product_qty}) + vals.update(**values) + return PackOperation.create(vals) + + def _create_picking_in(self, warehouse): + Picking = self.env['stock.picking'] + picking_values = { + 'picking_type_id': warehouse.in_type_id.id, + 'location_id': self.env.ref('stock.stock_location_suppliers').id, + 'location_dest_id': warehouse.lot_stock_id.id, + } + return Picking.create(picking_values) + + def _create_move(self, product, src_location, dst_location, **values): + # TDE FIXME: user as parameter + Move = self.env['stock.move'].sudo(self.user_stock_manager) + # simulate create + onchange + move_values = Move.onchange_product_id(product.id, src_location.id, dst_location.id)['value'] + move_values.update(product_id=product.id) + move_values.update(**values) + return Move.create(move_values) + + def _create_move_in(self, product, warehouse, picking=None, create_picking=False, **values): + if not picking and create_picking: + picking = self._create_picking_in(warehouse) + if picking: + values['picking_id'] = picking.id + # TDE FIXME: shouldn't location come from picking ?? + return self._create_move(product, self.env.ref('stock.stock_location_suppliers'), warehouse.lot_stock_id, **values) + + @classmethod + def setUpClass(cls): + super(TestStockCommon, cls).setUpClass() + + # Fetch stock-related user groups + user_group_employee = cls.env.ref('base.group_user') + user_group_stock_user = cls.env.ref('stock.group_stock_user') + user_group_stock_manager = cls.env.ref('stock.group_stock_manager') + + # User Data: stock user and stock manager + Users = cls.env['res.users'].with_context({'no_reset_password': True, 'mail_create_nosubscribe': True}) + cls.user_stock_user = Users.create({ + 'name': 'Pauline Poivraisselle', + 'login': 'pauline', + 'email': 'p.p@example.com', + 'notify_email': 'none', + 'groups_id': [(6, 0, [user_group_stock_user.id])]}) + cls.user_stock_manager = Users.create({ + 'name': 'Julie Tablier', + 'login': 'julie', + 'email': 'j.j@example.com', + 'notify_email': 'none', + 'groups_id': [(6, 0, [user_group_stock_manager.id])]}) + + # Warehouses + cls.warehouse_1 = cls.env['stock.warehouse'].create({ + 'name': 'Base Warehouse', + 'reception_steps': 'one_step', + 'delivery_steps': 'ship_only', + 'code': 'BWH'}) + + # Locations + cls.location_1 = cls.env['stock.location'].create({ + 'name': 'TestLocation1', + 'posx': 3, + 'location_id': cls.warehouse_1.lot_stock_id.id, + }) + # Existing data + cls.existing_inventories = cls.env['stock.inventory'].search([]) + cls.existing_quants = cls.env['stock.quant'].search([]) + + # Inventory + inventory_wizard = cls.env['stock.change.product.qty'].create({ + 'product_id': cls.product_1.id, + 'new_quantity': 50.0, + 'location_id': cls.warehouse_1.lot_stock_id.id, + }) + inventory_wizard.change_product_qty() diff --git a/addons/stock/tests/test_owner_available.py b/addons/stock/tests/test_owner_available.py deleted file mode 100644 index 7aa1e30d2e4..00000000000 --- a/addons/stock/tests/test_owner_available.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -# Author: Leonardo Pistone -# Copyright 2015 Camptocamp SA - -from openerp.addons.stock.tests.common import TestStockCommon - - -class TestVirtualAvailable(TestStockCommon): - - def setUp(self): - super(TestVirtualAvailable, self).setUp() - - self.env['stock.quant'].create({ - 'product_id': self.productA.id, - 'location_id': self.stock_location, - 'qty': 30.0, - }) - - self.env['stock.quant'].create({ - 'product_id': self.productA.id, - 'location_id': self.stock_location, - 'qty': 10.0, - 'owner_id': self.ref('base.res_partner_4'), - }) - - self.picking_out = self.env['stock.picking'].create({ - 'picking_type_id': self.ref('stock.picking_type_out'), - 'location_id': self.stock_location, - 'location_dest_id': self.customer_location}) - self.env['stock.move'].create({ - 'name': 'a move', - 'product_id': self.productA.id, - 'product_uom_qty': 3.0, - 'product_uom': self.productA.uom_id.id, - 'picking_id': self.picking_out.id, - 'location_id': self.stock_location, - 'location_dest_id': self.customer_location - }) - - self.picking_out_2 = self.env['stock.picking'].create({ - 'picking_type_id': self.ref('stock.picking_type_out'), - 'location_id': self.stock_location, - 'location_dest_id': self.customer_location}) - self.env['stock.move'].create({ - 'restrict_partner_id': self.ref('base.res_partner_4'), - 'name': 'another move', - 'product_id': self.productA.id, - 'product_uom_qty': 5.0, - 'product_uom': self.productA.uom_id.id, - 'picking_id': self.picking_out_2.id, - 'location_id': self.stock_location, - 'location_dest_id': self.customer_location - }) - - - def test_without_owner(self): - self.assertAlmostEqual(40.0, self.productA.virtual_available) - self.picking_out.action_assign() - self.picking_out_2.action_assign() - - self.assertAlmostEqual(32.0, self.productA.virtual_available) - - def test_with_owner(self): - prod_context = self.productA.with_context( - owner_id=self.ref('base.res_partner_4') - ) - self.assertAlmostEqual(10.0, prod_context.virtual_available) - self.picking_out.action_assign() - self.picking_out_2.action_assign() - self.assertAlmostEqual(5.0, prod_context.virtual_available) diff --git a/addons/stock/tests/test_product.py b/addons/stock/tests/test_product.py new file mode 100644 index 00000000000..5c67553585b --- /dev/null +++ b/addons/stock/tests/test_product.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +# Author: Leonardo Pistone +# Copyright 2015 Camptocamp SA + +from openerp.addons.stock.tests.common2 import TestStockCommon + + +class TestVirtualAvailable(TestStockCommon): + + def setUp(self): + super(TestVirtualAvailable, self).setUp() + + self.env['stock.quant'].create({ + 'product_id': self.product_3.id, + 'location_id': self.env.ref('stock.stock_location_stock').id, + 'qty': 30.0}) + + self.env['stock.quant'].create({ + 'product_id': self.product_3.id, + 'location_id': self.env.ref('stock.stock_location_stock').id, + 'qty': 10.0, + 'owner_id': self.user_stock_user.partner_id.id}) + + self.picking_out = self.env['stock.picking'].create({ + 'picking_type_id': self.ref('stock.picking_type_out'), + 'location_id': self.env.ref('stock.stock_location_stock').id, + 'location_dest_id': self.env.ref('stock.stock_location_customers').id}) + self.env['stock.move'].create({ + 'name': 'a move', + 'product_id': self.product_3.id, + 'product_uom_qty': 3.0, + 'product_uom': self.product_3.uom_id.id, + 'picking_id': self.picking_out.id, + 'location_id': self.env.ref('stock.stock_location_stock').id, + 'location_dest_id': self.env.ref('stock.stock_location_customers').id}) + + self.picking_out_2 = self.env['stock.picking'].create({ + 'picking_type_id': self.ref('stock.picking_type_out'), + 'location_id': self.env.ref('stock.stock_location_stock').id, + 'location_dest_id': self.env.ref('stock.stock_location_customers').id}) + self.env['stock.move'].create({ + 'restrict_partner_id': self.user_stock_user.partner_id.id, + 'name': 'another move', + 'product_id': self.product_3.id, + 'product_uom_qty': 5.0, + 'product_uom': self.product_3.uom_id.id, + 'picking_id': self.picking_out_2.id, + 'location_id': self.env.ref('stock.stock_location_stock').id, + 'location_dest_id': self.env.ref('stock.stock_location_customers').id}) + + def test_without_owner(self): + self.assertAlmostEqual(40.0, self.product_3.virtual_available) + self.picking_out.action_assign() + self.picking_out_2.action_assign() + self.assertAlmostEqual(32.0, self.product_3.virtual_available) + + def test_with_owner(self): + prod_context = self.product_3.with_context(owner_id=self.user_stock_user.partner_id.id) + self.assertAlmostEqual(10.0, prod_context.virtual_available) + self.picking_out.action_assign() + self.picking_out_2.action_assign() + self.assertAlmostEqual(5.0, prod_context.virtual_available) diff --git a/addons/stock/tests/test_resupply.py b/addons/stock/tests/test_resupply.py deleted file mode 100644 index 79ecbf456b7..00000000000 --- a/addons/stock/tests/test_resupply.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- coding: utf-8 -*- - -from openerp.addons.stock.tests.common import TestStockCommon -from openerp.tools import mute_logger, float_round - - -class TestResupply(TestStockCommon): - def setUp(self): - super(TestResupply, self).setUp() - self.Warehouse = self.env['stock.warehouse'] - # create 2 WH, BIG and SMALL - # SMALL resupplies from BIG - self.bigwh = self.Warehouse.create({'name': 'BIG', 'code': 'B'}) - self.smallwh = self.Warehouse.create({'name': 'SMALL', 'code': 'S', - 'default_resupply_wh_id': self.bigwh.id, - 'resupply_wh_ids': [(6, 0, [self.bigwh.id])], - }) - # minimum stock rule for Product A on SMALL - Orderpoint = self.env['stock.warehouse.orderpoint'] - Orderpoint.create({'warehouse_id': self.smallwh.id, - 'location_id': self.smallwh.lot_stock_id.id, - 'product_id': self.productA.id, - 'product_min_qty': 100, - 'product_max_qty': 200, - 'product_uom': self.uom_unit.id, - }) - # create some stock on BIG - Wiz = self.env['stock.change.product.qty'] - wiz = Wiz.create({'product_id': self.productA.id, - 'new_quantity': 1000, - 'location_id': self.bigwh.lot_stock_id.id, - }) - wiz.change_product_qty() - - def test_resupply_from_wh(self): - sched = self.env['procurement.order'] - sched.run_scheduler() - # we generated 2 procurements for product A: one on small wh and the - # other one on the transit location - procs = sched.search([('product_id', '=', self.productA.id)]) - self.assertEqual(len(procs), 2) - proc1 = sched.search([('product_id', '=', self.productA.id), - ('warehouse_id', '=', self.smallwh.id)]) - self.assertEqual(proc1.state, 'running') - proc2 = sched.search([('product_id', '=', self.productA.id), - ('warehouse_id', '=', self.bigwh.id)]) - self.assertEqual(proc2.location_id.usage, 'transit') - self.assertNotEqual(proc2.state, 'exception') - proc2.run() - self.assertEqual(proc2.state, 'running') - self.assertTrue(proc2.rule_id) diff --git a/addons/stock/tests/test_shipment.py b/addons/stock/tests/test_shipment.py new file mode 100644 index 00000000000..98eb9f66d02 --- /dev/null +++ b/addons/stock/tests/test_shipment.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- + +from odoo.addons.stock.tests.common2 import TestStockCommon + + +class TestInventory(TestStockCommon): + + def test_shipment(self): + # TDE NOTE: this test replaces test/shipment.yml present until saas-10 + # TDE TODO + # pickign.action_confirm -> confirm moves + # picking.do_prepare_partial, should create pack ops, write on it ? + + # create and confirm an incoming move of product 3 + incoming_move = self._create_move_in(self.product_3, self.warehouse_1, create_picking=True, product_uom_qty=50) + incoming_move.action_confirm() + + # receive only 40 units of products; this will create a backorder of incoming shipment for the remaining 10 + pack_operation = self._create_pack_operation( + self.product_3, 40.0, incoming_move.picking_id, + location_id=self.env.ref('stock.stock_location_suppliers').id, # TDE FIXME: locations + location_dest_id=self.location_1.id) + + incoming_move.picking_id.with_context(active_model='stock.picking', active_id=incoming_move.picking_id.id, active_ids=[incoming_move.picking_id.id]).do_transfer() + + # check backorder shipment after receiving partial shipment and check remaining shipment + for move_line in incoming_move.picking_id.move_lines: + self.assertEqual(move_line.product_qty, 40) + self.assertEqual(move_line.state, 'done') + backorder = self.env['stock.picking'].search([('backorder_id', '=', incoming_move.picking_id.id)]) + for move_line in backorder.move_lines: + self.assertEqual(move_line.product_qty, 10) + self.assertIn(move_line.state, ['assigned', 'waiting', 'confirmed']) + + backorder.with_context(active_model='stock.picking', active_id=backorder.id, active_ids=[backorder.id]) + + # receive the remaining 10 units from the backorder + pack_operation = self._create_pack_operation( + self.product_3, 10.0, backorder, + location_id=self.env.ref('stock.stock_location_suppliers').id, # TDE FIXME: locations + location_dest_id=self.location_1.id) + + backorder.do_transfer() + + # check the incoming shipment after receipt + backorder = self.env['stock.picking'].search([('backorder_id', '=', incoming_move.picking_id.id)]) + self.assertEqual(backorder.state, 'done') + for move_line in backorder.move_lines: + self.assertEqual(move_line.state, 'done') diff --git a/addons/stock/tests/test_warehouse.py b/addons/stock/tests/test_warehouse.py new file mode 100644 index 00000000000..048392f5085 --- /dev/null +++ b/addons/stock/tests/test_warehouse.py @@ -0,0 +1,145 @@ +# -*- coding: utf-8 -*- + +from odoo.addons.stock.tests.common2 import TestStockCommon + + +class TestInventory(TestStockCommon): + + def test_inventory_product(self): + # TDE NOTE: replaces test/inventory.yml present until saas-10 + inventory = self.env['stock.inventory'].sudo(self.user_stock_manager).create({ + 'name': 'Starting for product_1', + 'filter': 'product', + 'location_id': self.warehouse_1.lot_stock_id.id, + 'product_id': self.product_1.id, + }) + inventory.prepare_inventory() + + # As done in common.py, there is already an inventory line existing + self.assertEqual(len(inventory.line_ids), 1) + self.assertEqual(inventory.line_ids.theoretical_qty, 50.0) + self.assertEqual(inventory.line_ids.product_id, self.product_1) + self.assertEqual(inventory.line_ids.product_uom_id, self.uom_unit) + + # Update the line, set to 35 + inventory.line_ids.write({'product_qty': 35.0}) + inventory.action_done() + + # Check related move and quants + self.assertIn(inventory.name, inventory.move_ids.name) + self.assertEqual(inventory.move_ids.product_qty, 15.0) + self.assertEqual(inventory.move_ids.location_id, self.warehouse_1.lot_stock_id) + self.assertEqual(inventory.move_ids.location_dest_id, self.env.ref('stock.location_inventory')) # Inventory loss + self.assertEqual(inventory.move_ids.state, 'done') + self.assertEqual(inventory.move_ids.quant_ids.location_id, self.env.ref('stock.location_inventory')) # Inventory loss + self.assertEqual(inventory.move_ids.quant_ids.qty, 15.0) + self.assertEqual(inventory.move_ids.quant_ids.history_ids[0].product_qty, 50.0) + + # Check quantity of product in various locations: current, its parent, brother and other + self.assertEqual(self.product_1.with_context(location=self.warehouse_1.lot_stock_id.id).qty_available, 35.0) + self.assertEqual(self.product_1.with_context(location=self.warehouse_1.lot_stock_id.location_id.id).qty_available, 35.0) + self.assertEqual(self.product_1.with_context(location=self.warehouse_1.view_location_id.id).qty_available, 35.0) + self.assertEqual(self.product_1.with_context(location=self.warehouse_1.wh_input_stock_loc_id.id).qty_available, 0.0) + self.assertEqual(self.product_1.with_context(location=self.env.ref('stock.stock_location_stock').id).qty_available, 0.0) + + def test_inventory_wizard(self): + # Check inventory performed in setup was effectivley performed + self.assertEqual(self.product_1.virtual_available, 50.0) + self.assertEqual(self.product_1.qty_available, 50.0) + + # Check inventory obj details (1 inventory with 1 line, because 1 product change) + inventory = self.env['stock.inventory'].search([('id', 'not in', self.existing_inventories.ids)]) + self.assertEqual(len(inventory), 1) + self.assertIn('INV: %s' % self.product_1.name, inventory.name) + self.assertEqual(len(inventory.line_ids), 1) + self.assertEqual(inventory.line_ids.product_id, self.product_1) + self.assertEqual(inventory.line_ids.product_qty, 50.0) + + # Check associated quants: 1 quant for the product and the quantity + quant = self.env['stock.quant'].search([('id', 'not in', self.existing_quants.ids)]) + self.assertEqual(len(quant), 1) + # print quant.name, quant.product_id, quant.location_id + # TDE TODO: expand this test + + def test_basic_move(self): + # TDE NOTE: replaces test/move.yml present until saas-10, including onchanges + Move = self.env['stock.move'].sudo(self.user_stock_manager) + product = self.product_3.sudo(self.user_stock_manager) + + # simulate create + onchange + customer_move = self._create_move(product, self.warehouse_1.lot_stock_id, self.env.ref('stock.stock_location_customers'), product_uom_qty=5) + + # test move values + self.assertEqual(customer_move.product_uom, self.uom_kunit) + self.assertEqual(customer_move.location_id, self.warehouse_1.lot_stock_id) + self.assertEqual(customer_move.location_dest_id, self.env.ref('stock.stock_location_customers')) + + # confirm move, check quantity on hand and virtually available, without location context + customer_move.action_confirm() + self.assertEqual(product.qty_available, 0.0) + self.assertEqual(product.virtual_available, -5.0) + + customer_move.action_done() + self.assertEqual(product.qty_available, -5.0) + self.assertEqual(product.with_context(location=self.env.ref('stock.stock_location_customers').id).qty_available, 5.0) + + # compensate negative quants by receiving products from supplier + receive_move = self._create_move(product, self.env.ref('stock.stock_location_suppliers'), self.warehouse_1.lot_stock_id, product_uom_qty=15) + + receive_move.action_confirm() + receive_move.action_done() + + self.assertEqual(product.qty_available, 10.0) + self.assertEqual(product.virtual_available, 10.0) + + # new move towards customer + customer_move_2 = self._create_move(product, self.warehouse_1.lot_stock_id, self.env.ref('stock.stock_location_customers'), product_uom_qty=2) + + customer_move_2.action_confirm() + self.assertEqual(product.qty_available, 10.0) + self.assertEqual(product.virtual_available, 8.0) + + customer_move_2.action_done() + self.assertEqual(product.qty_available, 8.0) + self.assertEqual(product.with_context(location=self.env.ref('stock.stock_location_customers').id).qty_available, 7.0) + + +class TestResupply(TestStockCommon): + def setUp(self): + super(TestResupply, self).setUp() + + self.warehouse_2 = self.env['stock.warehouse'].create({ + 'name': 'Small Warehouse', + 'code': 'SWH', + 'default_resupply_wh_id': self.warehouse_1.id, + 'resupply_wh_ids': [(6, 0, [self.warehouse_1.id])] + }) + + # minimum stock rule for test product on this warehouse + self.env['stock.warehouse.orderpoint'].create({ + 'warehouse_id': self.warehouse_2.id, + 'location_id': self.warehouse_2.lot_stock_id.id, + 'product_id': self.product_1.id, + 'product_min_qty': 10, + 'product_max_qty': 100, + 'product_uom': self.uom_unit.id, + }) + + def test_resupply_from_wh(self): + # TDE NOTE: replaces tests/test_resupply.py, present until saas-10 + OrderScheduler = self.env['procurement.order'] + OrderScheduler.run_scheduler() + # we generated 2 procurements for product A: one on small wh and the other one on the transit location + procs = OrderScheduler.search([('product_id', '=', self.product_1.id)]) + self.assertEqual(len(procs), 2) + + proc1 = procs.filtered(lambda order: order.warehouse_id == self.warehouse_2) + self.assertEqual(proc1.state, 'running') + + proc2 = procs.filtered(lambda order: order.warehouse_id == self.warehouse_1) + self.assertEqual(proc2.location_id.usage, 'transit') + self.assertNotEqual(proc2.state, 'exception') + + proc2.run() + self.assertEqual(proc2.state, 'running') + self.assertTrue(proc2.rule_id)