first commit
This commit is contained in:
2
modules/stock/tests/__init__.py
Normal file
2
modules/stock/tests/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
BIN
modules/stock/tests/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
modules/stock/tests/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
modules/stock/tests/__pycache__/test_module.cpython-311.pyc
Normal file
BIN
modules/stock/tests/__pycache__/test_module.cpython-311.pyc
Normal file
Binary file not shown.
BIN
modules/stock/tests/__pycache__/test_scenario.cpython-311.pyc
Normal file
BIN
modules/stock/tests/__pycache__/test_scenario.cpython-311.pyc
Normal file
Binary file not shown.
246
modules/stock/tests/scenario_stock_average_cost_price.rst
Normal file
246
modules/stock/tests/scenario_stock_average_cost_price.rst
Normal file
@@ -0,0 +1,246 @@
|
||||
========================
|
||||
Stock Average Cost Price
|
||||
========================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime as dt
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model, Wizard
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.modules.currency.tests.tools import get_currency
|
||||
>>> from trytond.tests.tools import activate_modules
|
||||
|
||||
>>> today = dt.date.today()
|
||||
>>> next_day = today + dt.timedelta(days=1)
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
Get currency::
|
||||
|
||||
>>> currency = get_currency()
|
||||
|
||||
Create product::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> Product = Model.get('product.product')
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('300')
|
||||
>>> template.cost_price_method = 'average'
|
||||
>>> product, = template.products
|
||||
>>> product.cost_price = Decimal('80')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Negative Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('28')
|
||||
>>> template.cost_price_method = 'average'
|
||||
>>> negative_product, = template.products
|
||||
>>> negative_product.cost_price = Decimal('5.0000')
|
||||
>>> template.save()
|
||||
>>> negative_product, = template.products
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
>>> storage_sub_loc = Location(
|
||||
... name="Storage Sub", type='storage', parent=storage_loc)
|
||||
>>> storage_sub_loc.save()
|
||||
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
|
||||
|
||||
Make 1 unit of the product available @ 100 ::
|
||||
|
||||
>>> StockMove = Model.get('stock.move')
|
||||
>>> incoming_move = StockMove()
|
||||
>>> incoming_move.product = product
|
||||
>>> incoming_move.unit = unit
|
||||
>>> incoming_move.quantity = 1
|
||||
>>> incoming_move.from_location = supplier_loc
|
||||
>>> incoming_move.to_location = storage_sub_loc
|
||||
>>> incoming_move.planned_date = today
|
||||
>>> incoming_move.effective_date = today
|
||||
>>> incoming_move.unit_price = Decimal('100')
|
||||
>>> incoming_move.currency = currency
|
||||
>>> incoming_move.click('do')
|
||||
|
||||
Check Cost Price is 100::
|
||||
|
||||
>>> product.reload()
|
||||
>>> product.cost_price
|
||||
Decimal('100.0000')
|
||||
|
||||
Add 1 more unit @ 200::
|
||||
|
||||
>>> incoming_move = StockMove()
|
||||
>>> incoming_move.product = product
|
||||
>>> incoming_move.unit = unit
|
||||
>>> incoming_move.quantity = 1
|
||||
>>> incoming_move.from_location = supplier_loc
|
||||
>>> incoming_move.to_location = storage_loc
|
||||
>>> incoming_move.planned_date = today
|
||||
>>> incoming_move.effective_date = today
|
||||
>>> incoming_move.unit_price = Decimal('200')
|
||||
>>> incoming_move.currency = currency
|
||||
>>> incoming_move.click('do')
|
||||
|
||||
Check Cost Price Average is 150::
|
||||
|
||||
>>> product.reload()
|
||||
>>> product.cost_price
|
||||
Decimal('150.0000')
|
||||
|
||||
Add twice 1 more unit @ 200::
|
||||
|
||||
>>> incoming_moves = []
|
||||
>>> incoming_move = StockMove()
|
||||
>>> incoming_move.product = product
|
||||
>>> incoming_move.unit = unit
|
||||
>>> incoming_move.quantity = 1
|
||||
>>> incoming_move.from_location = supplier_loc
|
||||
>>> incoming_move.to_location = storage_loc
|
||||
>>> incoming_move.planned_date = today
|
||||
>>> incoming_move.effective_date = today
|
||||
>>> incoming_move.unit_price = Decimal('200')
|
||||
>>> incoming_move.currency = currency
|
||||
>>> incoming_move.save()
|
||||
>>> incoming_moves.append(incoming_move)
|
||||
|
||||
>>> incoming_move = StockMove()
|
||||
>>> incoming_move.product = product
|
||||
>>> incoming_move.unit = unit
|
||||
>>> incoming_move.quantity = 1
|
||||
>>> incoming_move.from_location = supplier_loc
|
||||
>>> incoming_move.to_location = storage_loc
|
||||
>>> incoming_move.planned_date = today
|
||||
>>> incoming_move.effective_date = today
|
||||
>>> incoming_move.unit_price = Decimal('200')
|
||||
>>> incoming_move.currency = currency
|
||||
>>> incoming_move.save()
|
||||
>>> incoming_moves.append(incoming_move)
|
||||
|
||||
>>> StockMove.click(incoming_moves, 'do')
|
||||
|
||||
Check Cost Price Average is 175::
|
||||
|
||||
>>> product.reload()
|
||||
>>> product.cost_price
|
||||
Decimal('175.0000')
|
||||
|
||||
Reduce Cost Price by 80%, to force to write recomputed price later::
|
||||
|
||||
>>> modify_cost_price = Wizard('product.modify_cost_price', [product])
|
||||
>>> modify_cost_price.form.cost_price = 'cost_price * 0.8'
|
||||
>>> modify_cost_price.form.date = next_day
|
||||
>>> modify_cost_price.execute('modify')
|
||||
>>> product.cost_price
|
||||
Decimal('140.0000')
|
||||
|
||||
Increase Cost Price by 10% using Template wizard::
|
||||
|
||||
>>> modify_cost_price = Wizard(
|
||||
... 'product.modify_cost_price', [product.template])
|
||||
>>> modify_cost_price.form.cost_price = 'cost_price * 1.1'
|
||||
>>> modify_cost_price.form.date = next_day
|
||||
>>> modify_cost_price.execute('modify')
|
||||
>>> product.reload()
|
||||
>>> product.cost_price
|
||||
Decimal('154.0000')
|
||||
|
||||
Send one product we don't have in stock::
|
||||
|
||||
>>> outgoing_move = StockMove()
|
||||
>>> outgoing_move.product = negative_product
|
||||
>>> outgoing_move.unit = unit
|
||||
>>> outgoing_move.quantity = 1
|
||||
>>> outgoing_move.unit_price = Decimal('28')
|
||||
>>> outgoing_move.from_location = storage_loc
|
||||
>>> outgoing_move.to_location = customer_loc
|
||||
>>> outgoing_move.planned_date = today
|
||||
>>> outgoing_move.effective_date = today
|
||||
>>> outgoing_move.currency = currency
|
||||
>>> outgoing_move.click('do')
|
||||
|
||||
Cost price should stay 5::
|
||||
|
||||
>>> negative_product.cost_price
|
||||
Decimal('5.0000')
|
||||
|
||||
Return one product to the supplier::
|
||||
|
||||
>>> outgoing_move = StockMove()
|
||||
>>> outgoing_move.product = negative_product
|
||||
>>> outgoing_move.unit = unit
|
||||
>>> outgoing_move.quantity = 1
|
||||
>>> outgoing_move.unit_price = Decimal('28')
|
||||
>>> outgoing_move.currency = currency
|
||||
>>> outgoing_move.from_location = storage_loc
|
||||
>>> outgoing_move.to_location = supplier_loc
|
||||
>>> outgoing_move.planned_date = today
|
||||
>>> outgoing_move.effective_date = today
|
||||
>>> outgoing_move.click('do')
|
||||
|
||||
Cost price should stay 5::
|
||||
|
||||
>>> negative_product.cost_price
|
||||
Decimal('5.0000')
|
||||
|
||||
Receive one unit of the product with negative stock so the stock stays negative::
|
||||
|
||||
>>> incoming_move = StockMove()
|
||||
>>> incoming_move.product = negative_product
|
||||
>>> incoming_move.unit = unit
|
||||
>>> incoming_move.quantity = 1
|
||||
>>> incoming_move.from_location = supplier_loc
|
||||
>>> incoming_move.to_location = storage_loc
|
||||
>>> incoming_move.planned_date = today
|
||||
>>> incoming_move.effective_date = today
|
||||
>>> incoming_move.unit_price = Decimal('3')
|
||||
>>> incoming_move.currency = currency
|
||||
>>> incoming_move.click('do')
|
||||
|
||||
Cost price should be set to last unit price::
|
||||
|
||||
>>> negative_product.reload()
|
||||
>>> negative_product.cost_price
|
||||
Decimal('3.0000')
|
||||
|
||||
Receive two units of the product so the stock becomes positive::
|
||||
|
||||
>>> incoming_move = StockMove()
|
||||
>>> incoming_move.product = negative_product
|
||||
>>> incoming_move.unit = unit
|
||||
>>> incoming_move.quantity = 2
|
||||
>>> incoming_move.from_location = supplier_loc
|
||||
>>> incoming_move.to_location = storage_loc
|
||||
>>> incoming_move.planned_date = today
|
||||
>>> incoming_move.effective_date = today
|
||||
>>> incoming_move.unit_price = Decimal('2')
|
||||
>>> incoming_move.currency = currency
|
||||
>>> incoming_move.click('do')
|
||||
|
||||
Cost price should be set to last unit price::
|
||||
|
||||
>>> negative_product.reload()
|
||||
>>> negative_product.cost_price
|
||||
Decimal('2.0000')
|
||||
|
||||
Recompute Cost Price::
|
||||
|
||||
>>> recompute = Wizard('product.recompute_cost_price', [negative_product])
|
||||
>>> recompute.execute('recompute')
|
||||
>>> negative_product.cost_price
|
||||
Decimal('2.0000')
|
||||
250
modules/stock/tests/scenario_stock_inventory.rst
Normal file
250
modules/stock/tests/scenario_stock_inventory.rst
Normal file
@@ -0,0 +1,250 @@
|
||||
========================
|
||||
Stock Inventory Scenario
|
||||
========================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime as dt
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.modules.currency.tests.tools import get_currency
|
||||
>>> from trytond.tests.tools import activate_modules, assertEqual
|
||||
|
||||
>>> today = dt.date.today()
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
Get currency::
|
||||
|
||||
>>> currency = get_currency()
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
|
||||
>>> lost_found_loc, = Location.find([('type', '=', 'lost_found')])
|
||||
|
||||
Create products::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('300')
|
||||
>>> template.cost_price_method = 'average'
|
||||
>>> product, = template.products
|
||||
>>> product.cost_price = Decimal('80')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
>>> kg, = ProductUom.find([('name', '=', 'Kilogram')])
|
||||
>>> template2 = ProductTemplate()
|
||||
>>> template2.name = 'Product'
|
||||
>>> template2.default_uom = kg
|
||||
>>> template2.type = 'goods'
|
||||
>>> template2.list_price = Decimal('140')
|
||||
>>> template2.cost_price_method = 'average'
|
||||
>>> product2, = template2.products
|
||||
>>> product2.cost_price = Decimal('60')
|
||||
>>> template2.save()
|
||||
>>> product2, = template2.products
|
||||
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.consumable = True
|
||||
>>> template.list_price = Decimal('300')
|
||||
>>> template.cost_price_method = 'average'
|
||||
>>> consumable, = template.products
|
||||
>>> consumable.cost_price = Decimal('80')
|
||||
>>> template.save()
|
||||
>>> consumable, = template.products
|
||||
|
||||
Fill storage::
|
||||
|
||||
>>> StockMove = Model.get('stock.move')
|
||||
>>> incoming_move = StockMove()
|
||||
>>> incoming_move.product = product
|
||||
>>> incoming_move.unit = unit
|
||||
>>> incoming_move.quantity = 1
|
||||
>>> incoming_move.from_location = supplier_loc
|
||||
>>> incoming_move.to_location = storage_loc
|
||||
>>> incoming_move.planned_date = today
|
||||
>>> incoming_move.effective_date = today
|
||||
>>> incoming_move.unit_price = Decimal('100')
|
||||
>>> incoming_move.currency = currency
|
||||
>>> incoming_moves = [incoming_move]
|
||||
|
||||
>>> incoming_move = StockMove()
|
||||
>>> incoming_move.product = product2
|
||||
>>> incoming_move.unit = kg
|
||||
>>> incoming_move.quantity = 2.5
|
||||
>>> incoming_move.from_location = supplier_loc
|
||||
>>> incoming_move.to_location = storage_loc
|
||||
>>> incoming_move.planned_date = today
|
||||
>>> incoming_move.effective_date = today
|
||||
>>> incoming_move.unit_price = Decimal('70')
|
||||
>>> incoming_move.currency = currency
|
||||
>>> incoming_moves.append(incoming_move)
|
||||
>>> StockMove.click(incoming_moves, 'do')
|
||||
|
||||
Create an inventory::
|
||||
|
||||
>>> Inventory = Model.get('stock.inventory')
|
||||
>>> inventory = Inventory()
|
||||
>>> inventory.location = storage_loc
|
||||
>>> inventory.empty_quantity = 'keep'
|
||||
>>> inventory.save()
|
||||
>>> inventory.click('complete_lines')
|
||||
>>> line_by_product = {l.product.id: l for l in inventory.lines}
|
||||
>>> line_p1 = line_by_product[product.id]
|
||||
>>> line_p1.expected_quantity
|
||||
1.0
|
||||
>>> line_p1.quantity = 3
|
||||
>>> line_p2 = line_by_product[product2.id]
|
||||
>>> line_p2.expected_quantity
|
||||
2.5
|
||||
>>> inventory.save()
|
||||
|
||||
Fill storage with more quantities::
|
||||
|
||||
>>> incoming_move = StockMove()
|
||||
>>> incoming_move.product = product
|
||||
>>> incoming_move.unit = unit
|
||||
>>> incoming_move.quantity = 1
|
||||
>>> incoming_move.from_location = supplier_loc
|
||||
>>> incoming_move.to_location = storage_loc
|
||||
>>> incoming_move.planned_date = today
|
||||
>>> incoming_move.effective_date = today
|
||||
>>> incoming_move.unit_price = Decimal('100')
|
||||
>>> incoming_move.currency = currency
|
||||
>>> incoming_moves = [incoming_move]
|
||||
|
||||
>>> incoming_move = StockMove()
|
||||
>>> incoming_move.product = product2
|
||||
>>> incoming_move.unit = kg
|
||||
>>> incoming_move.quantity = 1.3
|
||||
>>> incoming_move.from_location = supplier_loc
|
||||
>>> incoming_move.to_location = storage_loc
|
||||
>>> incoming_move.planned_date = today
|
||||
>>> incoming_move.effective_date = today
|
||||
>>> incoming_move.unit_price = Decimal('70')
|
||||
>>> incoming_move.currency = currency
|
||||
>>> incoming_moves.append(incoming_move)
|
||||
>>> StockMove.click(incoming_moves, 'do')
|
||||
|
||||
Update the inventory::
|
||||
|
||||
>>> inventory.click('complete_lines')
|
||||
>>> line_p1.reload()
|
||||
>>> line_p1.expected_quantity
|
||||
2.0
|
||||
>>> line_p1.quantity
|
||||
3.0
|
||||
>>> line_p2.reload()
|
||||
>>> line_p2.expected_quantity
|
||||
3.8
|
||||
>>> line_p2.quantity = 3.8
|
||||
>>> line_p2.save()
|
||||
|
||||
Confirm the inventory::
|
||||
|
||||
>>> inventory.click('confirm')
|
||||
>>> line_p1.reload()
|
||||
>>> line_p1.expected_quantity
|
||||
2.0
|
||||
>>> move, = line_p1.moves
|
||||
>>> move.quantity
|
||||
1.0
|
||||
>>> assertEqual(move.from_location, lost_found_loc)
|
||||
>>> assertEqual(move.to_location, inventory.location)
|
||||
>>> line_p2.reload()
|
||||
>>> len(line_p2.moves)
|
||||
0
|
||||
|
||||
Creating an inventory with empty quantities::
|
||||
|
||||
>>> inventory = Inventory()
|
||||
>>> inventory.location = storage_loc
|
||||
>>> inventory.empty_quantity = 'keep'
|
||||
>>> line = inventory.lines.new()
|
||||
>>> line.product = product
|
||||
>>> inventory.click('confirm')
|
||||
>>> line, = inventory.lines
|
||||
>>> len(line.moves)
|
||||
0
|
||||
|
||||
Empty storage::
|
||||
|
||||
>>> Inventory = Model.get('stock.inventory')
|
||||
>>> inventory = Inventory()
|
||||
>>> inventory.location = storage_loc
|
||||
>>> inventory.empty_quantity = 'keep'
|
||||
>>> line = inventory.lines.new()
|
||||
>>> line.product = product
|
||||
>>> line.quantity = 0
|
||||
>>> line = inventory.lines.new()
|
||||
>>> line.product = product2
|
||||
>>> line.quantity = 0
|
||||
>>> inventory.save()
|
||||
>>> line_p1, line_p2 = inventory.lines
|
||||
>>> line_p1.quantity
|
||||
0.0
|
||||
>>> line_p1.expected_quantity
|
||||
3.0
|
||||
>>> line_p2.quantity
|
||||
0.0
|
||||
>>> line_p2.expected_quantity
|
||||
3.8
|
||||
>>> inventory.click('confirm')
|
||||
|
||||
Add quantity of consumable product::
|
||||
|
||||
>>> inventory = Inventory()
|
||||
>>> inventory.location = storage_loc
|
||||
>>> inventory.empty_quantity = 'keep'
|
||||
>>> line = inventory.lines.new()
|
||||
>>> line.product = consumable
|
||||
>>> line.quantity = 5.0
|
||||
>>> inventory.click('complete_lines')
|
||||
>>> len(inventory.lines)
|
||||
1
|
||||
>>> inventory.click('confirm')
|
||||
>>> line, = inventory.lines
|
||||
>>> move, = line.moves
|
||||
>>> move.quantity
|
||||
5.0
|
||||
>>> assertEqual(move.from_location, lost_found_loc)
|
||||
>>> assertEqual(move.to_location, inventory.location)
|
||||
|
||||
Create an inventory that should be empty after completion::
|
||||
|
||||
>>> Inventory = Model.get('stock.inventory')
|
||||
>>> inventory = Inventory()
|
||||
>>> inventory.location = storage_loc
|
||||
>>> inventory.empty_quantity = 'keep'
|
||||
>>> inventory.click('complete_lines')
|
||||
>>> len(inventory.lines)
|
||||
0
|
||||
|
||||
Create an inventory and check rec_name::
|
||||
|
||||
>>> Inventory = Model.get('stock.inventory')
|
||||
>>> inventory = Inventory()
|
||||
>>> inventory.date = dt.date(2023, 1, 31)
|
||||
>>> inventory.location = storage_loc
|
||||
>>> inventory.empty_quantity = 'keep'
|
||||
>>> inventory.save()
|
||||
>>> inventory.rec_name
|
||||
'[6] [STO] Storage Zone @ 01/31/2023'
|
||||
111
modules/stock/tests/scenario_stock_inventory_count.rst
Normal file
111
modules/stock/tests/scenario_stock_inventory_count.rst
Normal file
@@ -0,0 +1,111 @@
|
||||
==============================
|
||||
Stock Inventory Count Scenario
|
||||
==============================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.tests.tools import activate_modules
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
|
||||
|
||||
Create products::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('300')
|
||||
>>> template.cost_price_method = 'average'
|
||||
>>> product, = template.products
|
||||
>>> product.cost_price = Decimal('80')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
>>> kg, = ProductUom.find([('name', '=', 'Kilogram')])
|
||||
>>> template2 = ProductTemplate()
|
||||
>>> template2.name = 'Product'
|
||||
>>> template2.default_uom = kg
|
||||
>>> template2.type = 'goods'
|
||||
>>> template2.list_price = Decimal('140')
|
||||
>>> template2.cost_price_method = 'average'
|
||||
>>> product2, = template2.products
|
||||
>>> product2.cost_price = Decimal('60')
|
||||
>>> template2.save()
|
||||
>>> product2, = template2.products
|
||||
|
||||
Create an inventory::
|
||||
|
||||
>>> Inventory = Model.get('stock.inventory')
|
||||
>>> inventory = Inventory()
|
||||
>>> inventory.location = storage_loc
|
||||
>>> inventory.empty_quantity = 'keep'
|
||||
>>> inventory.save()
|
||||
|
||||
Count inventory::
|
||||
|
||||
>>> count = inventory.click('do_count')
|
||||
|
||||
>>> count.form.search = product
|
||||
|
||||
>>> count.execute('quantity')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
InventoryCountWarning: ...
|
||||
|
||||
>>> Model.get('res.user.warning')(user=config.user,
|
||||
... name='stock.inventory,%s.product.product,%s.count_create' % (
|
||||
... inventory.id, product.id)).save()
|
||||
>>> count.execute('quantity')
|
||||
>>> count.form.quantity
|
||||
1.0
|
||||
>>> count.form.total_quantity
|
||||
1.0
|
||||
>>> count.execute('add')
|
||||
|
||||
>>> count.form.search = product
|
||||
>>> count.execute('quantity')
|
||||
>>> count.form.total_quantity
|
||||
2.0
|
||||
>>> count.execute('add')
|
||||
|
||||
>>> count.form.search = product2
|
||||
>>> Model.get('res.user.warning')(user=config.user,
|
||||
... name='stock.inventory,%s.product.product,%s.count_create' % (
|
||||
... inventory.id, product2.id)).save()
|
||||
>>> count.execute('quantity')
|
||||
>>> count.form.quantity
|
||||
>>> count.form.total_quantity
|
||||
>>> count.form.quantity = 10
|
||||
>>> count.form.total_quantity
|
||||
10.0
|
||||
>>> count.execute('add')
|
||||
|
||||
>>> count.execute('end')
|
||||
|
||||
Check inventory::
|
||||
|
||||
>>> len(inventory.lines)
|
||||
2
|
||||
>>> line1, = [l for l in inventory.lines if l.product == product]
|
||||
>>> line1.quantity
|
||||
2.0
|
||||
>>> line2, = [l for l in inventory.lines if l.product == product2]
|
||||
>>> line2.quantity
|
||||
10.0
|
||||
@@ -0,0 +1,81 @@
|
||||
=======================================
|
||||
Stock Inventory Scenario Empty Quantity
|
||||
=======================================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime as dt
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.modules.currency.tests.tools import get_currency
|
||||
>>> from trytond.tests.tools import activate_modules, assertEqual
|
||||
|
||||
>>> today = dt.date.today()
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
|
||||
>>> lost_found_loc, = Location.find([('type', '=', 'lost_found')])
|
||||
|
||||
Create product::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('300')
|
||||
>>> template.cost_price_method = 'average'
|
||||
>>> product, = template.products
|
||||
>>> product.cost_price = Decimal('80')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Fill storage::
|
||||
|
||||
>>> StockMove = Model.get('stock.move')
|
||||
>>> incoming_move = StockMove()
|
||||
>>> incoming_move.product = product
|
||||
>>> incoming_move.unit = unit
|
||||
>>> incoming_move.quantity = 1
|
||||
>>> incoming_move.from_location = supplier_loc
|
||||
>>> incoming_move.to_location = storage_loc
|
||||
>>> incoming_move.planned_date = today
|
||||
>>> incoming_move.effective_date = today
|
||||
>>> incoming_move.unit_price = Decimal('100')
|
||||
>>> incoming_move.currency = get_currency()
|
||||
>>> incoming_move.click('do')
|
||||
|
||||
Creating an inventory with empty quantities creates and empty move::
|
||||
|
||||
>>> Inventory = Model.get('stock.inventory')
|
||||
>>> inventory = Inventory()
|
||||
>>> inventory.location = storage_loc
|
||||
>>> inventory.empty_quantity = 'empty'
|
||||
>>> inventory.save()
|
||||
>>> inventory.click('complete_lines')
|
||||
>>> line, = inventory.lines
|
||||
>>> line.expected_quantity
|
||||
1.0
|
||||
>>> line.quantity
|
||||
>>> inventory.click('confirm')
|
||||
>>> line.reload()
|
||||
>>> line.expected_quantity
|
||||
1.0
|
||||
>>> move, = line.moves
|
||||
>>> move.quantity
|
||||
1.0
|
||||
>>> assertEqual(move.from_location, inventory.location)
|
||||
>>> assertEqual(move.to_location, lost_found_loc)
|
||||
67
modules/stock/tests/scenario_stock_move_in_future.rst
Normal file
67
modules/stock/tests/scenario_stock_move_in_future.rst
Normal file
@@ -0,0 +1,67 @@
|
||||
=============================
|
||||
Stock Move In Future Scenario
|
||||
=============================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime as dt
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.modules.currency.tests.tools import get_currency
|
||||
>>> from trytond.tests.tools import activate_modules
|
||||
|
||||
>>> today = dt.date.today()
|
||||
>>> tomorrow = today + dt.timedelta(days=1)
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
Create product::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> Product = Model.get('product.product')
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('20')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
>>> product.cost_price = Decimal('1')
|
||||
>>> product.save()
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
|
||||
A warning is raised when doing a move in the future::
|
||||
|
||||
>>> Move = Model.get('stock.move')
|
||||
>>> move = Move()
|
||||
>>> move.product = product
|
||||
>>> move.quantity = 1
|
||||
>>> move.from_location = supplier_loc
|
||||
>>> move.to_location = storage_loc
|
||||
>>> move.currency = get_currency()
|
||||
>>> move.effective_date = tomorrow
|
||||
>>> move.quantity = 2
|
||||
>>> move.unit_price = Decimal('1')
|
||||
>>> move.save()
|
||||
>>> move.click('do')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
MoveFutureWarning: ...
|
||||
|
||||
But it can be done for today::
|
||||
|
||||
>>> move.effective_date = today
|
||||
>>> move.click('do')
|
||||
>>> move.state
|
||||
'done'
|
||||
110
modules/stock/tests/scenario_stock_period.rst
Normal file
110
modules/stock/tests/scenario_stock_period.rst
Normal file
@@ -0,0 +1,110 @@
|
||||
=====================
|
||||
Stock Period Scenario
|
||||
=====================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime as dt
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.modules.currency.tests.tools import get_currency
|
||||
>>> from trytond.tests.tools import activate_modules
|
||||
|
||||
>>> today = dt.date.today()
|
||||
>>> yesterday = today - dt.timedelta(days=1)
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> Move = Model.get('stock.move')
|
||||
>>> Period = Model.get('stock.period')
|
||||
>>> Product = Model.get('product.product')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
|
||||
>>> currency = get_currency()
|
||||
|
||||
Create product::
|
||||
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
|
||||
|
||||
Create a period::
|
||||
|
||||
>>> period = Period(date=yesterday)
|
||||
>>> period.save()
|
||||
|
||||
Close the period::
|
||||
|
||||
>>> period.click('close')
|
||||
>>> period.state
|
||||
'closed'
|
||||
|
||||
Try to create a move::
|
||||
|
||||
>>> move = Move()
|
||||
>>> move.product = product
|
||||
>>> move.quantity = 1
|
||||
>>> move.from_location = storage_loc
|
||||
>>> move.to_location = customer_loc
|
||||
>>> move.planned_date = yesterday
|
||||
>>> move.unit_price = Decimal('42.0000')
|
||||
>>> move.currency = currency
|
||||
>>> move.save()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
AccessError: ...
|
||||
|
||||
Reopen the period::
|
||||
|
||||
>>> period.click('draft')
|
||||
>>> period.state
|
||||
'draft'
|
||||
|
||||
Close the period with draft move::
|
||||
|
||||
>>> move.save()
|
||||
>>> period.click('close')
|
||||
>>> period.state
|
||||
'closed'
|
||||
|
||||
Reopen the period::
|
||||
|
||||
>>> period.click('draft')
|
||||
>>> period.state
|
||||
'draft'
|
||||
|
||||
Create an assigned move::
|
||||
|
||||
>>> Move.write([move], {'state': 'assigned'}, config._context)
|
||||
>>> move.state
|
||||
'assigned'
|
||||
|
||||
Close the period with assigned move::
|
||||
|
||||
>>> period.click('close')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
PeriodCloseError: ...
|
||||
|
||||
Try to close a period on today::
|
||||
|
||||
>>> period = Period(date=today)
|
||||
>>> period.click('close')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
PeriodCloseError: ...
|
||||
@@ -0,0 +1,126 @@
|
||||
=====================================
|
||||
Stock Product Quantities by Warehouse
|
||||
=====================================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime as dt
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.modules.currency.tests.tools import get_currency
|
||||
>>> from trytond.tests.tools import activate_modules, assertEqual
|
||||
|
||||
>>> today = dt.date.today()
|
||||
>>> yesterday = today - dt.timedelta(days=1)
|
||||
>>> tomorrow = today + dt.timedelta(days=1)
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
Get currency::
|
||||
|
||||
>>> currency = get_currency()
|
||||
|
||||
Create product::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('20')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> warehouse_loc, = Location.find([('code', '=', 'WH')])
|
||||
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
|
||||
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
|
||||
Fill warehouse::
|
||||
|
||||
>>> Move = Model.get('stock.move')
|
||||
>>> move = Move()
|
||||
>>> move.product = product
|
||||
>>> move.from_location = supplier_loc
|
||||
>>> move.to_location = storage_loc
|
||||
>>> move.unit = unit
|
||||
>>> move.quantity = 10
|
||||
>>> move.effective_date = yesterday
|
||||
>>> move.unit_price = Decimal('10')
|
||||
>>> move.currency = currency
|
||||
>>> move.click('do')
|
||||
|
||||
Forecast some moves::
|
||||
|
||||
>>> move = Move()
|
||||
>>> move.product = product
|
||||
>>> move.from_location = storage_loc
|
||||
>>> move.to_location = customer_loc
|
||||
>>> move.unit = unit
|
||||
>>> move.quantity = 6
|
||||
>>> move.planned_date = tomorrow
|
||||
>>> move.unit_price = Decimal('20')
|
||||
>>> move.currency = currency
|
||||
>>> move.save()
|
||||
|
||||
>>> move = Move()
|
||||
>>> move.product = product
|
||||
>>> move.from_location = supplier_loc
|
||||
>>> move.to_location = storage_loc
|
||||
>>> move.unit = unit
|
||||
>>> move.quantity = 5
|
||||
>>> move.planned_date = tomorrow
|
||||
>>> move.unit_price = Decimal('10')
|
||||
>>> move.currency = currency
|
||||
>>> move.save()
|
||||
|
||||
>>> move = Move()
|
||||
>>> move.product = product
|
||||
>>> move.from_location = storage_loc
|
||||
>>> move.to_location = customer_loc
|
||||
>>> move.unit = unit
|
||||
>>> move.quantity = 3
|
||||
>>> move.planned_date = tomorrow
|
||||
>>> move.unit_price = Decimal('20')
|
||||
>>> move.currency = currency
|
||||
>>> move.save()
|
||||
|
||||
|
||||
Check Product Quantities by Warehouse::
|
||||
|
||||
>>> ProductQuantitiesByWarehouse = Model.get('stock.product_quantities_warehouse')
|
||||
>>> with config.set_context(
|
||||
... product_template=template.id, warehouse=warehouse_loc.id):
|
||||
... records = ProductQuantitiesByWarehouse.find([])
|
||||
>>> len(records)
|
||||
3
|
||||
>>> assertEqual([(r.date, r.quantity) for r in records],
|
||||
... [(yesterday, 10), (today, 10), (tomorrow, 6)])
|
||||
|
||||
Check Product Quantities by Warehouse Moves::
|
||||
|
||||
>>> ProductQuantitiesByWarehouseMove = Model.get(
|
||||
... 'stock.product_quantities_warehouse.move')
|
||||
>>> with config.set_context(
|
||||
... product_template=template.id, warehouse=warehouse_loc.id):
|
||||
... records = ProductQuantitiesByWarehouseMove.find([])
|
||||
>>> len(records)
|
||||
4
|
||||
>>> assertEqual([
|
||||
... (r.date, r.cumulative_quantity_start, r.quantity,
|
||||
... r.cumulative_quantity_end)
|
||||
... for r in records],
|
||||
... [
|
||||
... (yesterday, 0, 10, 10),
|
||||
... (tomorrow, 10, -6, 4),
|
||||
... (tomorrow, 4, 5, 9),
|
||||
... (tomorrow, 9, -3, 6)])
|
||||
115
modules/stock/tests/scenario_stock_product_replace.rst
Normal file
115
modules/stock/tests/scenario_stock_product_replace.rst
Normal file
@@ -0,0 +1,115 @@
|
||||
==============================
|
||||
Stock Product Replace Scenario
|
||||
==============================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model, Wizard
|
||||
>>> from trytond.modules.company.tests.tools import create_company, get_company
|
||||
>>> from trytond.tests.tools import (
|
||||
... activate_modules, assertEqual, assertFalse, assertTrue)
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock')
|
||||
|
||||
>>> Cron = Model.get('ir.cron')
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> Move = Model.get('stock.move')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> UoM = Model.get('product.uom')
|
||||
|
||||
Create company::
|
||||
|
||||
>>> _ = create_company()
|
||||
>>> company = get_company()
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> supplier_loc, = Location.find([('code', '=', "SUP")])
|
||||
>>> storage_loc, = Location.find([('code', '=', "STO")])
|
||||
>>> customer_loc, = Location.find([('code', '=', "CUS")])
|
||||
|
||||
Create a product::
|
||||
|
||||
>>> unit, = UoM.find([('name', '=', "Unit")])
|
||||
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = "Product"
|
||||
>>> template.type = 'goods'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.save()
|
||||
>>> product1, = template.products
|
||||
|
||||
Create a second product::
|
||||
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = "Product"
|
||||
>>> template.type = 'goods'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.save()
|
||||
>>> product2, = template.products
|
||||
|
||||
Fill storage location::
|
||||
|
||||
>>> move = Move(product=product1)
|
||||
>>> move.quantity = 1
|
||||
>>> move.from_location = supplier_loc
|
||||
>>> move.to_location = storage_loc
|
||||
>>> move.unit_price = Decimal('10.0000')
|
||||
>>> move.currency = company.currency
|
||||
>>> move.click('do')
|
||||
>>> move.state
|
||||
'done'
|
||||
|
||||
Replace the product::
|
||||
|
||||
>>> replace = Wizard('product.product.replace', models=[product1])
|
||||
>>> replace.form.destination = product2
|
||||
>>> replace.execute('replace')
|
||||
>>> assertEqual(product1.replaced_by, product2)
|
||||
>>> assertTrue(product1.active)
|
||||
|
||||
Create a draft move::
|
||||
|
||||
>>> move = Move(product=product1)
|
||||
>>> move.quantity = 1
|
||||
>>> move.from_location = storage_loc
|
||||
>>> move.to_location = customer_loc
|
||||
>>> move.unit_price = Decimal('20.0000')
|
||||
>>> move.currency = company.currency
|
||||
>>> move.save()
|
||||
>>> move.state
|
||||
'draft'
|
||||
|
||||
Empty storage location::
|
||||
|
||||
>>> move = Move(product=product1)
|
||||
>>> move.quantity = 1
|
||||
>>> move.from_location = storage_loc
|
||||
>>> move.to_location = customer_loc
|
||||
>>> move.unit_price = Decimal('20.0000')
|
||||
>>> move.currency = company.currency
|
||||
>>> move.click('do')
|
||||
>>> move.state
|
||||
'done'
|
||||
|
||||
Check replaced product is deactivated and draft move is deleted::
|
||||
|
||||
>>> product1.reload()
|
||||
>>> assertFalse(product1.active)
|
||||
>>> Move.find([('state', '=', 'draft')])
|
||||
[]
|
||||
|
||||
Create a move for replaced product change the product::
|
||||
|
||||
>>> move = Move(product=product1)
|
||||
>>> move.quantity = 1
|
||||
>>> move.from_location = storage_loc
|
||||
>>> move.to_location = customer_loc
|
||||
>>> move.unit_price = Decimal('20.0000')
|
||||
>>> move.currency = company.currency
|
||||
>>> move.save()
|
||||
>>> assertEqual(move.product, product2)
|
||||
@@ -0,0 +1,161 @@
|
||||
==================================
|
||||
Stock Recompute Average Cost Price
|
||||
==================================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime as dt
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model, Wizard
|
||||
>>> from trytond.modules.company.tests.tools import create_company, get_company
|
||||
>>> from trytond.tests.tools import activate_modules, assertEqual, assertFalse
|
||||
|
||||
>>> today = dt.date.today()
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
Get company::
|
||||
|
||||
>>> company = get_company()
|
||||
|
||||
Create product::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('300')
|
||||
>>> template.cost_price_method = 'average'
|
||||
>>> product, = template.products
|
||||
>>> product.cost_price = Decimal('80')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
|
||||
|
||||
Create some moves::
|
||||
|
||||
>>> StockMove = Model.get('stock.move')
|
||||
>>> StockMove(
|
||||
... product=product,
|
||||
... quantity=1,
|
||||
... from_location=supplier_loc,
|
||||
... to_location=storage_loc,
|
||||
... unit_price=Decimal('100'),
|
||||
... currency=company.currency,
|
||||
... effective_date=today - dt.timedelta(days=2)).click('do')
|
||||
>>> StockMove(
|
||||
... product=product,
|
||||
... quantity=2,
|
||||
... from_location=storage_loc,
|
||||
... to_location=customer_loc,
|
||||
... unit_price=Decimal('300'),
|
||||
... currency=company.currency,
|
||||
... effective_date=today - dt.timedelta(days=1)).click('do')
|
||||
>>> StockMove(
|
||||
... product=product,
|
||||
... quantity=2,
|
||||
... from_location=supplier_loc,
|
||||
... to_location=storage_loc,
|
||||
... unit_price=Decimal('120'),
|
||||
... currency=company.currency,
|
||||
... effective_date=today - dt.timedelta(days=1)).click('do')
|
||||
>>> StockMove(
|
||||
... product=product,
|
||||
... quantity=3,
|
||||
... from_location=supplier_loc,
|
||||
... to_location=storage_loc,
|
||||
... unit_price=Decimal('100'),
|
||||
... currency=company.currency,
|
||||
... effective_date=today).click('do')
|
||||
|
||||
>>> [m.cost_price for m in StockMove.find([])]
|
||||
[Decimal('105.0000'), Decimal('120.0000'), Decimal('100.0000'), Decimal('100.0000')]
|
||||
|
||||
>>> product.reload()
|
||||
>>> product.cost_price
|
||||
Decimal('105.0000')
|
||||
|
||||
Recompute cost price::
|
||||
|
||||
>>> recompute = Wizard('product.recompute_cost_price', [product])
|
||||
>>> recompute.execute('recompute')
|
||||
|
||||
>>> [m.cost_price for m in StockMove.find([])]
|
||||
[Decimal('105.0000'), Decimal('120.0000'), Decimal('120.0000'), Decimal('100.0000')]
|
||||
|
||||
>>> product.reload()
|
||||
>>> product.cost_price
|
||||
Decimal('105.0000')
|
||||
|
||||
Recompute cost price from a date::
|
||||
|
||||
>>> recompute = Wizard('product.recompute_cost_price', [product])
|
||||
>>> recompute.form.from_ = today - dt.timedelta(days=1)
|
||||
>>> recompute.execute('recompute')
|
||||
|
||||
>>> [m.cost_price for m in StockMove.find([])]
|
||||
[Decimal('105.0000'), Decimal('120.0000'), Decimal('120.0000'), Decimal('100.0000')]
|
||||
|
||||
>>> product.reload()
|
||||
>>> product.cost_price
|
||||
Decimal('105.0000')
|
||||
|
||||
Update unit price of a move::
|
||||
|
||||
>>> move, = StockMove.find([
|
||||
... ('from_location', '=', supplier_loc.id),
|
||||
... ('effective_date', '=', today - dt.timedelta(days=1)),
|
||||
... ])
|
||||
>>> bool(move.unit_price_updated)
|
||||
False
|
||||
>>> move.unit_price = Decimal('130')
|
||||
>>> move.save()
|
||||
>>> bool(move.unit_price_updated)
|
||||
True
|
||||
|
||||
>>> recompute = Wizard('product.recompute_cost_price', [product])
|
||||
>>> recompute.form.from_ = move.effective_date + dt.timedelta(days=1)
|
||||
>>> recompute.execute('recompute')
|
||||
>>> move.reload()
|
||||
>>> bool(move.unit_price_updated)
|
||||
True
|
||||
|
||||
>>> recompute = Wizard('product.recompute_cost_price', [product])
|
||||
>>> assertEqual(recompute.form.from_, move.effective_date)
|
||||
>>> recompute.execute('recompute')
|
||||
>>> move.reload()
|
||||
>>> assertFalse(move.unit_price_updated)
|
||||
>>> [m.cost_price for m in StockMove.find([])]
|
||||
[Decimal('107.5000'), Decimal('130.0000'), Decimal('130.0000'), Decimal('100.0000')]
|
||||
|
||||
Launch cron task::
|
||||
|
||||
>>> move.unit_price = Decimal('120')
|
||||
>>> move.save()
|
||||
|
||||
>>> Cron = Model.get('ir.cron')
|
||||
>>> Company = Model.get('company.company')
|
||||
>>> cron_recompute, = Cron.find([
|
||||
... ('method', '=', 'product.product|recompute_cost_price_from_moves'),
|
||||
... ])
|
||||
>>> cron_recompute.companies.append(Company(company.id))
|
||||
>>> cron_recompute.click('run_once')
|
||||
|
||||
>>> move.reload()
|
||||
>>> bool(move.unit_price_updated)
|
||||
False
|
||||
>>> [m.cost_price for m in StockMove.find([])]
|
||||
[Decimal('105.0000'), Decimal('120.0000'), Decimal('120.0000'), Decimal('100.0000')]
|
||||
@@ -0,0 +1,106 @@
|
||||
=============================================
|
||||
Stock Recompute Average Cost Price Production
|
||||
=============================================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime as dt
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model, Wizard
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.modules.currency.tests.tools import get_currency
|
||||
>>> from trytond.tests.tools import activate_modules
|
||||
|
||||
>>> today = dt.date.today()
|
||||
>>> yesterday = today - dt.timedelta(days=1)
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> StockMove = Model.get('stock.move')
|
||||
|
||||
Get currency::
|
||||
|
||||
>>> currency = get_currency()
|
||||
|
||||
Create product::
|
||||
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('50.0000')
|
||||
>>> template.cost_price_method = 'average'
|
||||
>>> product, = template.products
|
||||
>>> product.cost_price = Decimal('40.0000')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
>>> production_loc = Location(name="Production", type='production')
|
||||
>>> production_loc.save()
|
||||
|
||||
Consume product for production and reverse some::
|
||||
|
||||
>>> StockMove(
|
||||
... product=product,
|
||||
... quantity=10,
|
||||
... from_location=storage_loc,
|
||||
... to_location=production_loc,
|
||||
... effective_date=today).click('do')
|
||||
>>> StockMove(
|
||||
... product=product,
|
||||
... quantity=2,
|
||||
... from_location=production_loc,
|
||||
... to_location=storage_loc,
|
||||
... unit_price=Decimal('40.0000'),
|
||||
... currency=currency,
|
||||
... effective_date=today).click('do')
|
||||
|
||||
>>> [m.cost_price for m in StockMove.find([])]
|
||||
[Decimal('40.0000'), Decimal('40.0000')]
|
||||
|
||||
Recompute cost price::
|
||||
|
||||
>>> recompute = Wizard('product.recompute_cost_price', [product])
|
||||
>>> recompute.execute('recompute')
|
||||
|
||||
>>> [m.cost_price for m in StockMove.find([])]
|
||||
[Decimal('0.0000'), Decimal('0.0000')]
|
||||
|
||||
>>> product.reload()
|
||||
>>> product.cost_price
|
||||
Decimal('0.0000')
|
||||
|
||||
Receive product yesterday at new cost::
|
||||
|
||||
>>> StockMove(
|
||||
... product=product,
|
||||
... quantity=16,
|
||||
... from_location=supplier_loc,
|
||||
... to_location=storage_loc,
|
||||
... unit_price=Decimal('20.0000'),
|
||||
... currency=currency,
|
||||
... effective_date=yesterday).click('do')
|
||||
|
||||
Recompute cost price::
|
||||
|
||||
>>> recompute = Wizard('product.recompute_cost_price', [product])
|
||||
>>> recompute.execute('recompute')
|
||||
|
||||
>>> [m.cost_price for m in StockMove.find([])]
|
||||
[Decimal('20.0000'), Decimal('20.0000'), Decimal('20.0000')]
|
||||
|
||||
>>> product.reload()
|
||||
>>> product.cost_price
|
||||
Decimal('20.0000')
|
||||
157
modules/stock/tests/scenario_stock_reporting.rst
Normal file
157
modules/stock/tests/scenario_stock_reporting.rst
Normal file
@@ -0,0 +1,157 @@
|
||||
=================================
|
||||
Stock Shipment Reporting Scenario
|
||||
=================================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime as dt
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model, Report
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.modules.currency.tests.tools import get_currency
|
||||
>>> from trytond.tests.tools import activate_modules
|
||||
|
||||
>>> today = dt.date.today()
|
||||
>>> yesterday = today - dt.timedelta(days=1)
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
Get currency::
|
||||
|
||||
>>> currency = get_currency()
|
||||
|
||||
Create customer & supplier::
|
||||
|
||||
>>> Party = Model.get('party.party')
|
||||
>>> customer = Party(name='Customer')
|
||||
>>> customer.save()
|
||||
>>> supplier = Party(name='Supplier')
|
||||
>>> supplier.save()
|
||||
|
||||
Create product::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> Product = Model.get('product.product')
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('20')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> warehouse_loc, = Location.find([('code', '=', 'WH')])
|
||||
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
|
||||
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
|
||||
>>> input_loc, = Location.find([('code', '=', 'IN')])
|
||||
>>> output_loc, = Location.find([('code', '=', 'OUT')])
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
>>> lost_loc, = Location.find([('type', '=', 'lost_found')])
|
||||
|
||||
Create Shipment In::
|
||||
|
||||
>>> ShipmentIn = Model.get('stock.shipment.in')
|
||||
>>> shipment_in = ShipmentIn()
|
||||
>>> shipment_in.planned_date = today
|
||||
>>> shipment_in.supplier = supplier
|
||||
>>> shipment_in.warehouse = warehouse_loc
|
||||
|
||||
Receive a bunch of products::
|
||||
|
||||
>>> move = shipment_in.incoming_moves.new()
|
||||
>>> move.product = product
|
||||
>>> move.unit = unit
|
||||
>>> move.quantity = 100
|
||||
>>> move.from_location = supplier_loc
|
||||
>>> move.to_location = input_loc
|
||||
>>> move.unit_price = Decimal('1')
|
||||
>>> move.currency = currency
|
||||
>>> shipment_in.save()
|
||||
>>> shipment_in.click('receive')
|
||||
>>> shipment_in.click('do')
|
||||
|
||||
Testing the report::
|
||||
|
||||
>>> supplier_restocking_list = Report('stock.shipment.in.restocking_list')
|
||||
>>> ext, _, _, name = supplier_restocking_list.execute([shipment_in], {})
|
||||
>>> ext
|
||||
'odt'
|
||||
>>> name
|
||||
'Restocking List-1'
|
||||
|
||||
Create Shipment Out::
|
||||
|
||||
>>> ShipmentOut = Model.get('stock.shipment.out')
|
||||
>>> shipment_out = ShipmentOut()
|
||||
>>> shipment_out.planned_date = today
|
||||
>>> shipment_out.customer = customer
|
||||
>>> shipment_out.warehouse = warehouse_loc
|
||||
|
||||
Add two shipment lines of same product and go through the workflow::
|
||||
|
||||
>>> move = shipment_out.outgoing_moves.new()
|
||||
>>> move.product = product
|
||||
>>> move.unit = unit
|
||||
>>> move.quantity = 1
|
||||
>>> move.from_location = output_loc
|
||||
>>> move.to_location = customer_loc
|
||||
>>> move.unit_price = Decimal('1')
|
||||
>>> move.currency = currency
|
||||
>>> shipment_out.save()
|
||||
>>> shipment_out.click('wait')
|
||||
>>> shipment_out.click('assign_try')
|
||||
>>> shipment_out.click('pick')
|
||||
>>> shipment_out.click('pack')
|
||||
>>> shipment_out.click('do')
|
||||
|
||||
Testing the reports::
|
||||
|
||||
>>> delivery_note = Report('stock.shipment.out.delivery_note')
|
||||
>>> ext, _, _, name = delivery_note.execute([shipment_out], {})
|
||||
>>> ext
|
||||
'odt'
|
||||
>>> name
|
||||
'Delivery Note-1'
|
||||
|
||||
>>> picking_list = Report('stock.shipment.out.picking_list')
|
||||
>>> ext, _, _, name = picking_list.execute([shipment_out], {})
|
||||
>>> ext
|
||||
'odt'
|
||||
>>> name
|
||||
'Picking List-1'
|
||||
|
||||
Create an internal shipment::
|
||||
|
||||
>>> ShipmentInternal = Model.get('stock.shipment.internal')
|
||||
>>> shipment_internal = ShipmentInternal()
|
||||
>>> shipment_internal.planned_date = today
|
||||
>>> shipment_internal.from_location = storage_loc
|
||||
>>> shipment_internal.to_location = lost_loc
|
||||
>>> move = shipment_internal.moves.new()
|
||||
>>> move.product = product
|
||||
>>> move.unit = unit
|
||||
>>> move.quantity = 1
|
||||
>>> move.from_location = storage_loc
|
||||
>>> move.to_location = lost_loc
|
||||
>>> shipment_internal.save()
|
||||
>>> shipment_internal.click('wait')
|
||||
>>> shipment_internal.click('assign_try')
|
||||
>>> shipment_internal.click('do')
|
||||
|
||||
Testing the report::
|
||||
|
||||
>>> internal_report = Report('stock.shipment.internal.report')
|
||||
>>> ext, _, _, name = internal_report.execute([shipment_internal], {})
|
||||
>>> ext
|
||||
'odt'
|
||||
>>> name
|
||||
'Internal Shipment-1'
|
||||
|
||||
239
modules/stock/tests/scenario_stock_reporting_inventory.rst
Normal file
239
modules/stock/tests/scenario_stock_reporting_inventory.rst
Normal file
@@ -0,0 +1,239 @@
|
||||
==================================
|
||||
Stock Reporting Inventory Scenario
|
||||
==================================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime as dt
|
||||
>>> from decimal import Decimal
|
||||
>>> from unittest.mock import patch
|
||||
|
||||
>>> from proteus import Model
|
||||
>>> from trytond.ir.date import Date
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.modules.currency.tests.tools import get_currency
|
||||
>>> from trytond.tests.tools import activate_modules, assertEqual
|
||||
|
||||
>>> period_close = globals().get('period_close', False)
|
||||
>>> product_type = globals().get('product_type', 'product.template')
|
||||
|
||||
Patch today::
|
||||
|
||||
>>> mock = patch.object(Date, 'today', return_value=dt.date(2025, 1, 15))
|
||||
>>> _ = mock.start()
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
>>> Inventory = Model.get('stock.reporting.inventory')
|
||||
>>> InventoryMove = Model.get('stock.reporting.inventory.move')
|
||||
>>> InventoryDaily = Model.get('stock.reporting.inventory.daily')
|
||||
>>> InventoryTurnover = Model.get('stock.reporting.inventory.turnover')
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> Move = Model.get('stock.move')
|
||||
>>> Period = Model.get('stock.period')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
|
||||
Get currency::
|
||||
|
||||
>>> currency = get_currency()
|
||||
|
||||
Create product::
|
||||
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> warehouse_loc, = Location.find([('code', '=', 'WH')])
|
||||
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
|
||||
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
|
||||
Fill warehouse::
|
||||
|
||||
>>> move = Move()
|
||||
>>> move.product = product
|
||||
>>> move.from_location = supplier_loc
|
||||
>>> move.to_location = storage_loc
|
||||
>>> move.quantity = 10
|
||||
>>> move.effective_date = dt.date(2025, 1, 1)
|
||||
>>> move.unit_price = Decimal('10.0000')
|
||||
>>> move.currency = currency
|
||||
>>> move.click('do')
|
||||
>>> move.state
|
||||
'done'
|
||||
|
||||
>>> move = Move()
|
||||
>>> move.product = product
|
||||
>>> move.from_location = storage_loc
|
||||
>>> move.to_location = customer_loc
|
||||
>>> move.unit = unit
|
||||
>>> move.quantity = 1
|
||||
>>> move.effective_date = dt.date(2025, 1, 1)
|
||||
>>> move.unit_price = Decimal('20.0000')
|
||||
>>> move.currency = currency
|
||||
>>> move.click('do')
|
||||
>>> move.state
|
||||
'done'
|
||||
|
||||
>>> move = Move()
|
||||
>>> move.product = product
|
||||
>>> move.from_location = storage_loc
|
||||
>>> move.to_location = customer_loc
|
||||
>>> move.unit = unit
|
||||
>>> move.quantity = 2
|
||||
>>> move.effective_date = dt.date(2025, 1, 10)
|
||||
>>> move.unit_price = Decimal('20.0000')
|
||||
>>> move.currency = currency
|
||||
>>> move.click('do')
|
||||
>>> move.state
|
||||
'done'
|
||||
|
||||
Forecast some moves::
|
||||
|
||||
>>> move = Move()
|
||||
>>> move.product = product
|
||||
>>> move.from_location = supplier_loc
|
||||
>>> move.to_location = storage_loc
|
||||
>>> move.quantity = 10
|
||||
>>> move.effective_date = dt.date(2025, 1, 5)
|
||||
>>> move.unit_price = Decimal('10.0000')
|
||||
>>> move.currency = currency
|
||||
>>> move.save()
|
||||
>>> move.state
|
||||
'draft'
|
||||
|
||||
>>> move = Move()
|
||||
>>> move.product = product
|
||||
>>> move.from_location = storage_loc
|
||||
>>> move.to_location = customer_loc
|
||||
>>> move.unit = unit
|
||||
>>> move.quantity = 3
|
||||
>>> move.planned_date = dt.date(2025, 1, 20)
|
||||
>>> move.unit_price = Decimal('20.0000')
|
||||
>>> move.currency = currency
|
||||
>>> move.save()
|
||||
>>> move.state
|
||||
'draft'
|
||||
|
||||
Close period::
|
||||
|
||||
>>> period = Period(date=dt.date(2025, 1, 5))
|
||||
>>> if period_close:
|
||||
... period.click('close')
|
||||
|
||||
|
||||
Check inventory::
|
||||
|
||||
>>> with config.set_context(
|
||||
... location=warehouse_loc.id,
|
||||
... product_type=product_type,
|
||||
... date=dt.date(2024, 1, 1)):
|
||||
... Inventory.find([])
|
||||
[]
|
||||
|
||||
>>> with config.set_context(
|
||||
... location=warehouse_loc.id,
|
||||
... product_type=product_type,
|
||||
... date=dt.date(2025, 1, 1)):
|
||||
... inventory, = Inventory.find([])
|
||||
>>> inventory.quantity
|
||||
9.0
|
||||
>>> assertEqual(inventory.product.__class__.__name__, product_type)
|
||||
|
||||
>>> with config.set_context(
|
||||
... location=warehouse_loc.id,
|
||||
... product_type=product_type,
|
||||
... date=dt.date(2025, 1, 15)):
|
||||
... inventory, = Inventory.find([])
|
||||
>>> inventory.quantity
|
||||
7.0
|
||||
|
||||
>>> with config.set_context(
|
||||
... location=warehouse_loc.id,
|
||||
... product_type=product_type,
|
||||
... date=dt.date(2025, 1, 20)):
|
||||
... inventory, = Inventory.find([])
|
||||
>>> inventory.quantity
|
||||
4.0
|
||||
|
||||
>>> with config.set_context(
|
||||
... location=warehouse_loc.id,
|
||||
... product_type=product_type):
|
||||
... inventory_moves = InventoryMove.find([])
|
||||
... inventories_daily = InventoryDaily.find([])
|
||||
|
||||
>>> [i.quantity for i in inventory_moves]
|
||||
[4.0, 7.0, 9.0, 10.0]
|
||||
>>> [(i.input_quantity, i.output_quantity) for i in inventory_moves]
|
||||
[(None, 3.0), (None, 2.0), (None, 1.0), (10.0, None)]
|
||||
|
||||
>>> [i.quantity for i in inventories_daily]
|
||||
[4.0, 7.0, 9.0]
|
||||
>>> [(i.input_quantity, i.output_quantity) for i in inventories_daily]
|
||||
[(None, 3.0), (None, 2.0), (10.0, 1.0)]
|
||||
|
||||
>>> with config.set_context(
|
||||
... location=warehouse_loc.id,
|
||||
... from_date=dt.date(2025, 1, 15),
|
||||
... to_date=dt.date(2025, 1, 29),
|
||||
... product_type=product_type):
|
||||
... inventory_moves = InventoryMove.find([])
|
||||
... inventories_daily = InventoryDaily.find([])
|
||||
|
||||
>>> [i.quantity for i in inventory_moves]
|
||||
[4.0, 7.0]
|
||||
>>> [(i.input_quantity, i.output_quantity) for i in inventory_moves]
|
||||
[(None, 3.0), (None, None)]
|
||||
|
||||
>>> [i.quantity for i in inventories_daily]
|
||||
[4.0, 7.0]
|
||||
>>> [(i.input_quantity, i.output_quantity) for i in inventories_daily]
|
||||
[(None, 3.0), (None, None)]
|
||||
|
||||
>>> with config.set_context(
|
||||
... location=warehouse_loc.id,
|
||||
... from_date=dt.date(2025, 1, 10),
|
||||
... to_date=dt.date(2025, 1, 29),
|
||||
... product_type=product_type):
|
||||
... inventory_moves = InventoryMove.find([])
|
||||
... inventories_daily = InventoryDaily.find([])
|
||||
|
||||
>>> assertEqual(
|
||||
... [i.quantity for i in inventory_moves],
|
||||
... [4.0, 7.0] if period_close else [4.0, 7.0, 9.0])
|
||||
>>> assertEqual(
|
||||
... [(i.input_quantity, i.output_quantity) for i in inventory_moves],
|
||||
... [(None, 3.0), (None, 2.0)] if period_close
|
||||
... else [(None, 3.0), (None, 2.0), (None, None)])
|
||||
|
||||
>>> [i.quantity for i in inventories_daily]
|
||||
[4.0, 7.0]
|
||||
>>> [(i.input_quantity, i.output_quantity) for i in inventories_daily]
|
||||
[(None, 3.0), (None, 2.0)]
|
||||
|
||||
Check Inventory turnover::
|
||||
|
||||
>>> with config.set_context(
|
||||
... location=warehouse_loc.id,
|
||||
... from_date=dt.date(2025, 1, 10),
|
||||
... to_date=dt.date(2025, 1, 29),
|
||||
... product_type=product_type):
|
||||
... turnover, = InventoryTurnover.find([])
|
||||
|
||||
>>> turnover.output_quantity
|
||||
0.25
|
||||
>>> turnover.average_quantity
|
||||
5.5
|
||||
>>> turnover.turnover
|
||||
0.045
|
||||
>>> assertEqual(turnover.product.__class__.__name__, product_type)
|
||||
217
modules/stock/tests/scenario_stock_reporting_margin.rst
Normal file
217
modules/stock/tests/scenario_stock_reporting_margin.rst
Normal file
@@ -0,0 +1,217 @@
|
||||
===============================
|
||||
Stock Reporting Margin Scenario
|
||||
===============================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime as dt
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.modules.currency.tests.tools import get_currency
|
||||
>>> from trytond.tests.tools import activate_modules, assertEqual
|
||||
|
||||
>>> today = dt.date.today()
|
||||
>>> yesterday = today - dt.timedelta(days=1)
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
Get currency::
|
||||
|
||||
>>> currency = get_currency()
|
||||
|
||||
Create product::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('40')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
>>> product.cost_price = Decimal('20')
|
||||
>>> product.save()
|
||||
>>> template2, = template.duplicate()
|
||||
>>> product2, = template2.products
|
||||
|
||||
>>> Category = Model.get('product.category')
|
||||
>>> category_root = Category(name="Root")
|
||||
>>> category_root.save()
|
||||
>>> category1 = Category(name="Child1", parent=category_root)
|
||||
>>> category1.save()
|
||||
>>> category2 = Category(name="Child2", parent=category_root)
|
||||
>>> category2.save()
|
||||
|
||||
>>> template.categories.append(Category(category1.id))
|
||||
>>> template.save()
|
||||
>>> template2.categories.append(Category(category2.id))
|
||||
>>> template2.save()
|
||||
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
|
||||
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
>>> lost_loc, = Location.find([('type', '=', 'lost_found')])
|
||||
|
||||
Create some moves::
|
||||
|
||||
>>> Move = Model.get('stock.move')
|
||||
>>> move = Move()
|
||||
>>> move.product = product
|
||||
>>> move.from_location = supplier_loc
|
||||
>>> move.to_location = storage_loc
|
||||
>>> move.quantity = 8
|
||||
>>> move.unit_price = Decimal('20')
|
||||
>>> move.currency = currency
|
||||
>>> move.effective_date = yesterday
|
||||
>>> move.click('do')
|
||||
|
||||
>>> move = Move()
|
||||
>>> move.product = product
|
||||
>>> move.from_location = storage_loc
|
||||
>>> move.to_location = customer_loc
|
||||
>>> move.quantity = 2
|
||||
>>> move.unit_price = Decimal('40')
|
||||
>>> move.currency = currency
|
||||
>>> move.effective_date = yesterday
|
||||
>>> move.click('do')
|
||||
|
||||
>>> move = Move()
|
||||
>>> move.product = product
|
||||
>>> move.from_location = storage_loc
|
||||
>>> move.to_location = customer_loc
|
||||
>>> move.quantity = 4
|
||||
>>> move.unit_price = Decimal('30')
|
||||
>>> move.currency = currency
|
||||
>>> move.effective_date = today
|
||||
>>> move.click('do')
|
||||
|
||||
>>> move = Move()
|
||||
>>> move.product = product
|
||||
>>> move.from_location = customer_loc
|
||||
>>> move.to_location = storage_loc
|
||||
>>> move.quantity = 1
|
||||
>>> move.unit_price = Decimal('30')
|
||||
>>> move.currency = currency
|
||||
>>> move.effective_date = today
|
||||
>>> move.click('do')
|
||||
|
||||
>>> move = Move()
|
||||
>>> move.product = product2
|
||||
>>> move.from_location = storage_loc
|
||||
>>> move.to_location = customer_loc
|
||||
>>> move.quantity = 2
|
||||
>>> move.unit_price = Decimal('50')
|
||||
>>> move.currency = currency
|
||||
>>> move.effective_date = today
|
||||
>>> move.click('do')
|
||||
|
||||
>>> move = Move()
|
||||
>>> move.product = product
|
||||
>>> move.from_location = storage_loc
|
||||
>>> move.to_location = lost_loc
|
||||
>>> move.quantity = 1
|
||||
>>> move.effective_date = today
|
||||
>>> move.click('do')
|
||||
|
||||
Check reporting margin per product::
|
||||
|
||||
>>> MarginProduct = Model.get('stock.reporting.margin.product')
|
||||
>>> MarginProductTimeseries = Model.get(
|
||||
... 'stock.reporting.margin.product.time_series')
|
||||
>>> context = {
|
||||
... 'from_date': yesterday,
|
||||
... 'to_date': today,
|
||||
... 'period': 'day',
|
||||
... }
|
||||
>>> with config.set_context(context=context):
|
||||
... reports = MarginProduct.find([])
|
||||
... time_series = MarginProductTimeseries.find([])
|
||||
>>> len(reports)
|
||||
2
|
||||
>>> report, = [r for r in reports if r.product == product]
|
||||
>>> (report.quantity, report.cost, report.revenue, report.profit, report.margin)
|
||||
(5.0, Decimal('100.00'), Decimal('170.00'), Decimal('70.00'), Decimal('0.4118'))
|
||||
>>> len(time_series)
|
||||
3
|
||||
>>> with config.set_context(context=context):
|
||||
... assertEqual({(
|
||||
... r.product.id, str(r.date), r.quantity, r.cost, r.revenue,
|
||||
... r.profit, r.margin)
|
||||
... for r in time_series},
|
||||
... {
|
||||
... (product.id, str(yesterday), 2, Decimal('40.00'),
|
||||
... Decimal('80.00'), Decimal('40.00'), Decimal('0.5000')),
|
||||
... (product.id, str(today), 3, Decimal('60.00'),
|
||||
... Decimal('90.00'), Decimal('30.00'), Decimal('0.3333')),
|
||||
... (product2.id, str(today), 2, Decimal('40.00'),
|
||||
... Decimal('100.00'), Decimal('60.00'), Decimal('0.6000'))})
|
||||
|
||||
Check reporting margin per categories::
|
||||
|
||||
>>> MarginCategory = Model.get('stock.reporting.margin.category')
|
||||
>>> MarginCategoryTimeseries = Model.get(
|
||||
... 'stock.reporting.margin.category.time_series')
|
||||
>>> MarginCategoryTree = Model.get(
|
||||
... 'stock.reporting.margin.category.tree')
|
||||
>>> with config.set_context(context=context):
|
||||
... reports = MarginCategory.find([])
|
||||
... time_series = MarginCategoryTimeseries.find([])
|
||||
... tree = MarginCategoryTree.find([])
|
||||
>>> len(reports)
|
||||
2
|
||||
>>> with config.set_context(context=context):
|
||||
... assertEqual({(r.category.id, r.cost, r.revenue, r.profit, r.margin)
|
||||
... for r in reports},
|
||||
... {(category1.id, Decimal('100.00'), Decimal('170.00'),
|
||||
... Decimal('70.00'), Decimal('0.4118')),
|
||||
... (category2.id, Decimal('40.00'), Decimal('100.00'),
|
||||
... Decimal('60.00'), Decimal('0.6000'))})
|
||||
>>> len(time_series)
|
||||
3
|
||||
>>> with config.set_context(context=context):
|
||||
... assertEqual({
|
||||
... (r.category.id, str(r.date), r.cost, r.revenue, r.profit, r.margin)
|
||||
... for r in time_series},
|
||||
... {
|
||||
... (category1.id, str(yesterday), Decimal('40.00'), Decimal('80.00'),
|
||||
... Decimal('40.00'), Decimal('0.5000')),
|
||||
... (category1.id, str(today), Decimal('60.00'), Decimal('90.00'),
|
||||
... Decimal('30.00'), Decimal('0.3333')),
|
||||
... (category2.id, str(today), Decimal('40.00'), Decimal('100.00'),
|
||||
... Decimal('60.00'), Decimal('0.6000'))})
|
||||
>>> len(tree)
|
||||
3
|
||||
>>> with config.set_context(context=context):
|
||||
... assertEqual({(r.name, r.cost, r.revenue, r.profit, r.margin)
|
||||
... for r in tree},
|
||||
... {("Root", Decimal('140.00'), Decimal('270.00'),
|
||||
... Decimal('130.00'), Decimal('0.4815')),
|
||||
... ("Child1", Decimal('100.00'), Decimal('170.00'),
|
||||
... Decimal('70.00'), Decimal('0.4118')),
|
||||
... ('Child2', Decimal('40.00'), Decimal('100.00'),
|
||||
... Decimal('60.00'), Decimal('0.6000'))})
|
||||
>>> child1, = MarginCategoryTree.find([('rec_name', '=', 'Child1')])
|
||||
>>> child1.rec_name
|
||||
'Child1'
|
||||
|
||||
Check reporting margin including lost::
|
||||
|
||||
>>> context['include_lost'] = True
|
||||
|
||||
>>> with config.set_context(context=context):
|
||||
... reports = MarginProduct.find([])
|
||||
>>> len(reports)
|
||||
2
|
||||
>>> report, = [r for r in reports if r.product == product]
|
||||
>>> (report.quantity, report.cost, report.revenue, report.profit, report.margin)
|
||||
(6.0, Decimal('120.00'), Decimal('170.00'), Decimal('50.00'), Decimal('0.2941'))
|
||||
137
modules/stock/tests/scenario_stock_shipment_cron_assign.rst
Normal file
137
modules/stock/tests/scenario_stock_shipment_cron_assign.rst
Normal file
@@ -0,0 +1,137 @@
|
||||
==========================
|
||||
Stock Shipment Cron Assign
|
||||
==========================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime as dt
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.modules.currency.tests.tools import get_currency
|
||||
>>> from trytond.tests.tools import activate_modules
|
||||
|
||||
>>> today = dt.date.today()
|
||||
>>> yesterday = today - dt.timedelta(days=1)
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
>>> Cron = Model.get('ir.cron')
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> Move = Model.get('stock.move')
|
||||
>>> Party = Model.get('party.party')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> ShipmentInternal = Model.get('stock.shipment.internal')
|
||||
>>> ShipmentOut = Model.get('stock.shipment.out')
|
||||
>>> UoM = Model.get('product.uom')
|
||||
|
||||
Get currency::
|
||||
|
||||
>>> currency = get_currency()
|
||||
|
||||
Create a product::
|
||||
|
||||
>>> unit, = UoM.find([('name', '=', "Unit")])
|
||||
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = "Product"
|
||||
>>> template.type = 'goods'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Create customer::
|
||||
|
||||
>>> customer = Party(name="Customer")
|
||||
>>> customer.save()
|
||||
|
||||
Get locations::
|
||||
|
||||
>>> storage_loc, = Location.find([('code', '=', "STO")])
|
||||
>>> supplier_loc, = Location.find([('code', '=', "SUP")])
|
||||
>>> lost_loc, = Location.find([('type', '=', 'lost_found')], limit=1)
|
||||
|
||||
Fill storage::
|
||||
|
||||
>>> move = Move()
|
||||
>>> move.product = product
|
||||
>>> move.quantity = 5
|
||||
>>> move.from_location = supplier_loc
|
||||
>>> move.to_location = storage_loc
|
||||
>>> move.unit_price = Decimal('10.0000')
|
||||
>>> move.currency = currency
|
||||
>>> move.effective_date = yesterday
|
||||
>>> move.click('do')
|
||||
>>> move.state
|
||||
'done'
|
||||
|
||||
Create different shipments with different planned dates::
|
||||
|
||||
>>> shipment_int_1 = ShipmentInternal()
|
||||
>>> shipment_int_1.planned_date = today
|
||||
>>> shipment_int_1.from_location = storage_loc
|
||||
>>> shipment_int_1.to_location = lost_loc
|
||||
>>> move = shipment_int_1.moves.new()
|
||||
>>> move.from_location = shipment_int_1.from_location
|
||||
>>> move.to_location = shipment_int_1.to_location
|
||||
>>> move.product = product
|
||||
>>> move.quantity = 2
|
||||
>>> shipment_int_1.click('wait')
|
||||
>>> shipment_int_1.state
|
||||
'waiting'
|
||||
|
||||
>>> shipment_out_1 = ShipmentOut()
|
||||
>>> shipment_out_1.planned_date = today
|
||||
>>> shipment_out_1.customer = customer
|
||||
>>> move = shipment_out_1.outgoing_moves.new()
|
||||
>>> move.from_location = shipment_out_1.warehouse_output
|
||||
>>> move.to_location = shipment_out_1.customer_location
|
||||
>>> move.product = product
|
||||
>>> move.quantity = 2
|
||||
>>> move.unit_price = Decimal('10.0000')
|
||||
>>> move.currency = currency
|
||||
>>> shipment_out_1.click('wait')
|
||||
>>> shipment_out_1.state
|
||||
'waiting'
|
||||
|
||||
>>> shipment_int_2, = shipment_int_1.duplicate()
|
||||
>>> shipment_int_2.click('wait')
|
||||
>>> shipment_int_2.state
|
||||
'waiting'
|
||||
|
||||
>>> shipment_out_2, = shipment_out_1.duplicate()
|
||||
>>> shipment_out_2.click('wait')
|
||||
>>> shipment_out_2.state
|
||||
'waiting'
|
||||
|
||||
Run assignation cron::
|
||||
|
||||
>>> cron = Cron(method='ir.cron|stock_shipment_assign_try')
|
||||
>>> cron.interval_number = 1
|
||||
>>> cron.interval_type = 'days'
|
||||
>>> cron.click('run_once')
|
||||
|
||||
Check assignations::
|
||||
|
||||
>>> shipment_int_1.reload()
|
||||
>>> shipment_int_1.state
|
||||
'assigned'
|
||||
|
||||
>>> shipment_out_1.reload()
|
||||
>>> shipment_out_1.state
|
||||
'assigned'
|
||||
|
||||
>>> shipment_int_2.reload()
|
||||
>>> shipment_int_2.state
|
||||
'waiting'
|
||||
>>> shipment_int_2.partially_assigned
|
||||
True
|
||||
|
||||
>>> shipment_out_2.reload()
|
||||
>>> shipment_out_2.state
|
||||
'waiting'
|
||||
>>> shipment_out_2.partially_assigned
|
||||
False
|
||||
115
modules/stock/tests/scenario_stock_shipment_in.rst
Normal file
115
modules/stock/tests/scenario_stock_shipment_in.rst
Normal file
@@ -0,0 +1,115 @@
|
||||
==========================
|
||||
Stock Shipment In Scenario
|
||||
==========================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model, Report
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.modules.currency.tests.tools import get_currency
|
||||
>>> from trytond.tests.tools import activate_modules, assertNotEqual
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> Party = Model.get('party.party')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> ShipmentIn = Model.get('stock.shipment.in')
|
||||
|
||||
Create supplier::
|
||||
|
||||
>>> supplier = Party(name='Supplier')
|
||||
>>> supplier.save()
|
||||
|
||||
Create product::
|
||||
|
||||
>>> unit, = ProductUom.find([('name', '=', "Unit")])
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = "Product"
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('20')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
|
||||
>>> input_loc, = Location.find([('code', '=', 'IN')])
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
|
||||
Create a shipment::
|
||||
|
||||
>>> shipment = ShipmentIn()
|
||||
>>> shipment.supplier = supplier
|
||||
>>> move = shipment.incoming_moves.new()
|
||||
>>> move.product = product
|
||||
>>> move.quantity = 10
|
||||
>>> move.from_location = supplier_loc
|
||||
>>> move.to_location = input_loc
|
||||
>>> move.unit_price = Decimal('5')
|
||||
>>> move.currency = get_currency()
|
||||
>>> shipment.save()
|
||||
>>> assertNotEqual(shipment.number, None)
|
||||
|
||||
>>> len(shipment.incoming_moves)
|
||||
1
|
||||
>>> len(shipment.inventory_moves)
|
||||
0
|
||||
|
||||
Receive the shipment::
|
||||
|
||||
>>> shipment.click('receive')
|
||||
>>> shipment.state
|
||||
'received'
|
||||
>>> [m.state for m in shipment.incoming_moves]
|
||||
['done']
|
||||
>>> [m.state for m in shipment.inventory_moves]
|
||||
['draft']
|
||||
|
||||
>>> restocking_list = Report('stock.shipment.in.restocking_list')
|
||||
>>> _ = restocking_list.execute([shipment])
|
||||
|
||||
Change inventory quantity and try to finish::
|
||||
|
||||
>>> inventory_move, = shipment.inventory_moves
|
||||
>>> inventory_move.quantity = 11
|
||||
>>> shipment.click('do')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ShipmentCheckQuantityWarning: ...
|
||||
>>> inventory_move.reload()
|
||||
>>> inventory_move.quantity = 10
|
||||
>>> inventory_move.save()
|
||||
|
||||
Add extra product to inventory and try to finish::
|
||||
|
||||
>>> product2, = product.duplicate()
|
||||
|
||||
>>> move = shipment.inventory_moves.new()
|
||||
>>> move.product = product2
|
||||
>>> move.quantity = 1
|
||||
>>> move.from_location = input_loc
|
||||
>>> move.to_location = storage_loc
|
||||
>>> shipment.click('do')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ShipmentCheckQuantityWarning: ...
|
||||
>>> move = shipment.inventory_moves[-1]
|
||||
>>> shipment.inventory_moves.remove(move)
|
||||
>>> shipment.save()
|
||||
|
||||
Finish the shipment::
|
||||
|
||||
>>> shipment.click('do')
|
||||
>>> shipment.state
|
||||
'done'
|
||||
>>> len(shipment.incoming_moves)
|
||||
1
|
||||
>>> [m.state for m in shipment.inventory_moves]
|
||||
['done']
|
||||
78
modules/stock/tests/scenario_stock_shipment_in_return.rst
Normal file
78
modules/stock/tests/scenario_stock_shipment_in_return.rst
Normal file
@@ -0,0 +1,78 @@
|
||||
=================================
|
||||
Stock Shipment In Return Scenario
|
||||
=================================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime as dt
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.modules.currency.tests.tools import get_currency
|
||||
>>> from trytond.tests.tools import activate_modules, assertEqual, assertNotEqual
|
||||
|
||||
>>> today = dt.date.today()
|
||||
>>> yesterday = today - dt.timedelta(days=1)
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
Create supplier::
|
||||
|
||||
>>> Party = Model.get('party.party')
|
||||
>>> supplier = Party(name='Supplier')
|
||||
>>> supplier.save()
|
||||
|
||||
Create product::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> Product = Model.get('product.product')
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('20')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
|
||||
|
||||
Create Shipment In::
|
||||
|
||||
>>> ShipmentInReturn = Model.get('stock.shipment.in.return')
|
||||
>>> shipment_return = ShipmentInReturn()
|
||||
>>> shipment_return.planned_date = yesterday
|
||||
>>> shipment_return.supplier = supplier
|
||||
>>> shipment_return.from_location = storage_loc
|
||||
>>> move = shipment_return.moves.new()
|
||||
>>> move.product = product
|
||||
>>> move.unit = unit
|
||||
>>> move.quantity = 1
|
||||
>>> move.from_location = storage_loc
|
||||
>>> move.to_location = supplier_loc
|
||||
>>> move.unit_price = Decimal('1')
|
||||
>>> move.currency = get_currency()
|
||||
>>> shipment_return.save()
|
||||
>>> shipment_return.number
|
||||
>>> shipment_return.click('wait')
|
||||
>>> shipment_return.state
|
||||
'waiting'
|
||||
>>> assertNotEqual(shipment_return.number, None)
|
||||
|
||||
Reschedule shipment::
|
||||
|
||||
>>> Cron = Model.get('ir.cron')
|
||||
>>> cron = Cron(method='stock.shipment.in.return|reschedule')
|
||||
>>> cron.interval_number = 1
|
||||
>>> cron.interval_type = 'months'
|
||||
>>> cron.click('run_once')
|
||||
>>> shipment_return.reload()
|
||||
>>> assertEqual(shipment_return.planned_date, today)
|
||||
@@ -0,0 +1,81 @@
|
||||
=================================================
|
||||
Stock Shipment In Same Storage and Input Scenario
|
||||
=================================================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.modules.currency.tests.tools import get_currency
|
||||
>>> from trytond.tests.tools import activate_modules
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
Create supplier::
|
||||
|
||||
>>> Party = Model.get('party.party')
|
||||
>>> supplier = Party(name='Supplier')
|
||||
>>> supplier.save()
|
||||
|
||||
Create product::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('20')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> warehouse_loc, = Location.find([('code', '=', 'WH')])
|
||||
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
>>> storage1 = Location(name="Storage 1", parent=storage_loc)
|
||||
>>> storage1.save()
|
||||
|
||||
Use storage location as input location::
|
||||
|
||||
>>> warehouse_loc.input_location = storage_loc
|
||||
>>> warehouse_loc.save()
|
||||
|
||||
Create Shipment In::
|
||||
|
||||
>>> ShipmentIn = Model.get('stock.shipment.in')
|
||||
>>> shipment_in = ShipmentIn()
|
||||
>>> shipment_in.supplier = supplier
|
||||
>>> shipment_in.warehouse = warehouse_loc
|
||||
>>> move = shipment_in.incoming_moves.new()
|
||||
>>> move.product = product
|
||||
>>> move.unit = unit
|
||||
>>> move.quantity = 1
|
||||
>>> move.unit_price = Decimal('5')
|
||||
>>> move.currency = get_currency()
|
||||
>>> move.from_location = supplier_loc
|
||||
>>> move.to_location = storage1
|
||||
>>> shipment_in.save()
|
||||
|
||||
>>> len(shipment_in.incoming_moves)
|
||||
1
|
||||
>>> len(shipment_in.inventory_moves)
|
||||
0
|
||||
|
||||
Incoming moves are done when receiving the shipment::
|
||||
|
||||
>>> shipment_in.click('receive')
|
||||
>>> shipment_in.state
|
||||
'done'
|
||||
>>> move, = shipment_in.incoming_moves
|
||||
>>> move.state
|
||||
'done'
|
||||
>>> len(shipment_in.inventory_moves)
|
||||
0
|
||||
141
modules/stock/tests/scenario_stock_shipment_internal.rst
Normal file
141
modules/stock/tests/scenario_stock_shipment_internal.rst
Normal file
@@ -0,0 +1,141 @@
|
||||
================================
|
||||
Stock Shipment Internal Scenario
|
||||
================================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime as dt
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model, Report
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.tests.tools import (
|
||||
... activate_modules, assertEqual, assertNotEqual, set_user)
|
||||
|
||||
>>> today = dt.date.today()
|
||||
>>> yesterday = today - dt.timedelta(days=1)
|
||||
>>> tomorrow = today + dt.timedelta(days=1)
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
>>> Employee = Model.get('company.employee')
|
||||
>>> Party = Model.get('party.party')
|
||||
>>> User = Model.get('res.user')
|
||||
|
||||
Set employee::
|
||||
|
||||
>>> employee_party = Party(name="Employee")
|
||||
>>> employee_party.save()
|
||||
>>> employee = Employee(party=employee_party)
|
||||
>>> employee.save()
|
||||
>>> user = User(config.user)
|
||||
>>> user.employees.append(employee)
|
||||
>>> user.employee = employee
|
||||
>>> user.save()
|
||||
>>> set_user(user.id)
|
||||
|
||||
Create product::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> Product = Model.get('product.product')
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('20')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> lost_found_loc, = Location.find([('type', '=', 'lost_found')])
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
>>> internal_loc = Location(
|
||||
... name="Internal", type='storage', parent=storage_loc.parent)
|
||||
>>> internal_loc.save()
|
||||
|
||||
Create Internal Shipment::
|
||||
|
||||
>>> Shipment = Model.get('stock.shipment.internal')
|
||||
>>> StockMove = Model.get('stock.move')
|
||||
>>> shipment = Shipment()
|
||||
>>> shipment.planned_date = today
|
||||
>>> shipment.from_location = internal_loc
|
||||
>>> shipment.to_location = storage_loc
|
||||
>>> move = shipment.moves.new()
|
||||
>>> move.product = product
|
||||
>>> move.quantity = 1
|
||||
>>> move.from_location = internal_loc
|
||||
>>> move.to_location = storage_loc
|
||||
>>> shipment.save()
|
||||
>>> shipment.number
|
||||
>>> shipment.assigned_by
|
||||
>>> shipment.done_by
|
||||
|
||||
>>> shipment.click('wait')
|
||||
>>> shipment.state
|
||||
'waiting'
|
||||
>>> assertNotEqual(shipment.number, None)
|
||||
>>> shipment.click('assign_try')
|
||||
>>> shipment.state
|
||||
'waiting'
|
||||
>>> shipment.assigned_by
|
||||
>>> shipment.done_by
|
||||
|
||||
>>> report = Report('stock.shipment.internal.report')
|
||||
>>> _ = report.execute([shipment])
|
||||
|
||||
Create Internal Shipment from lost_found location::
|
||||
|
||||
>>> lost_found_shipment = Shipment()
|
||||
>>> lost_found_shipment.planned_date = today
|
||||
>>> lost_found_shipment.from_location = lost_found_loc
|
||||
>>> lost_found_shipment.to_location = internal_loc
|
||||
>>> move = StockMove()
|
||||
>>> move = lost_found_shipment.moves.new()
|
||||
>>> move.product = product
|
||||
>>> move.unit = unit
|
||||
>>> move.quantity = 2
|
||||
>>> move.from_location = lost_found_loc
|
||||
>>> move.to_location = internal_loc
|
||||
>>> lost_found_shipment.click('wait')
|
||||
>>> lost_found_shipment.click('assign_try')
|
||||
>>> lost_found_shipment.state
|
||||
'assigned'
|
||||
>>> lost_found_shipment.click('do')
|
||||
>>> lost_found_shipment.state
|
||||
'done'
|
||||
|
||||
Check that now we can finish the older shipment::
|
||||
|
||||
>>> shipment.click('assign_try')
|
||||
>>> assertEqual(shipment.assigned_by, employee)
|
||||
>>> shipment.done_by
|
||||
|
||||
>>> shipment.click('do')
|
||||
>>> shipment.state
|
||||
'done'
|
||||
>>> assertEqual(shipment.done_by, employee)
|
||||
|
||||
Duplicate Internal Shipment::
|
||||
|
||||
>>> shipment_copy, = shipment.duplicate()
|
||||
>>> len(shipment_copy.moves)
|
||||
1
|
||||
|
||||
Reschedule shipment::
|
||||
|
||||
>>> shipment_copy.planned_date = yesterday
|
||||
>>> shipment_copy.click('wait')
|
||||
>>> Cron = Model.get('ir.cron')
|
||||
>>> cron = Cron(method='stock.shipment.internal|reschedule')
|
||||
>>> cron.interval_number = 1
|
||||
>>> cron.interval_type = 'months'
|
||||
>>> cron.click('run_once')
|
||||
>>> shipment_copy.reload()
|
||||
>>> assertEqual(shipment_copy.planned_date, today)
|
||||
@@ -0,0 +1,98 @@
|
||||
=============================================
|
||||
Stock Shipment Internal with Transit Scenario
|
||||
=============================================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime as dt
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.tests.tools import activate_modules, assertEqual
|
||||
|
||||
>>> today = dt.date.today()
|
||||
>>> yesterday = today - dt.timedelta(days=1)
|
||||
>>> tomorrow = today + dt.timedelta(days=1)
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> Shipment = Model.get('stock.shipment.internal')
|
||||
|
||||
Create product::
|
||||
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = "Product"
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('20')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> warehouse1, = Location.find([('type', '=', 'warehouse')])
|
||||
>>> warehouse2, = warehouse1.duplicate()
|
||||
|
||||
Add lead time between warehouses::
|
||||
|
||||
>>> LeadTime = Model.get('stock.location.lead_time')
|
||||
>>> lead_time = LeadTime()
|
||||
>>> lead_time.warehouse_from = warehouse1
|
||||
>>> lead_time.warehouse_to = warehouse2
|
||||
>>> lead_time.lead_time = dt.timedelta(1)
|
||||
>>> lead_time.save()
|
||||
|
||||
Create Internal Shipment with lead time::
|
||||
|
||||
>>> shipment = Shipment()
|
||||
>>> shipment.planned_date = tomorrow
|
||||
>>> shipment.from_location = warehouse1.storage_location
|
||||
>>> shipment.to_location = warehouse2.storage_location
|
||||
>>> bool(shipment.transit_location)
|
||||
True
|
||||
>>> assertEqual(shipment.planned_start_date, today)
|
||||
>>> move = shipment.moves.new()
|
||||
>>> move.product = product
|
||||
>>> move.quantity = 2
|
||||
>>> move.from_location = shipment.from_location
|
||||
>>> move.to_location = shipment.to_location
|
||||
>>> shipment.click('wait')
|
||||
>>> len(shipment.moves)
|
||||
2
|
||||
>>> outgoing_move, = shipment.outgoing_moves
|
||||
>>> outgoing_move.quantity
|
||||
2.0
|
||||
>>> assertEqual(outgoing_move.from_location, shipment.from_location)
|
||||
>>> assertEqual(outgoing_move.to_location, shipment.transit_location)
|
||||
>>> assertEqual(outgoing_move.planned_date, today)
|
||||
>>> incoming_move, = shipment.incoming_moves
|
||||
>>> incoming_move.quantity
|
||||
2.0
|
||||
>>> assertEqual(incoming_move.from_location, shipment.transit_location)
|
||||
>>> assertEqual(incoming_move.to_location, shipment.to_location)
|
||||
>>> assertEqual(incoming_move.planned_date, tomorrow)
|
||||
|
||||
>>> outgoing_move.quantity = 1
|
||||
>>> outgoing_move.save()
|
||||
|
||||
>>> shipment.click('assign_force')
|
||||
>>> shipment.effective_start_date = yesterday
|
||||
>>> shipment.click('pack')
|
||||
>>> shipment.click('ship')
|
||||
>>> incoming_move, = shipment.incoming_moves
|
||||
>>> incoming_move.quantity
|
||||
1.0
|
||||
>>> shipment.outgoing_moves[0].state
|
||||
'done'
|
||||
>>> assertEqual(shipment.outgoing_moves[0].effective_date, yesterday)
|
||||
>>> shipment.click('do')
|
||||
>>> shipment.incoming_moves[0].state
|
||||
'done'
|
||||
>>> assertEqual(shipment.incoming_moves[0].effective_date, today)
|
||||
284
modules/stock/tests/scenario_stock_shipment_out.rst
Normal file
284
modules/stock/tests/scenario_stock_shipment_out.rst
Normal file
@@ -0,0 +1,284 @@
|
||||
===========================
|
||||
Stock Shipment Out Scenario
|
||||
===========================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime as dt
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model, Report
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.modules.currency.tests.tools import get_currency
|
||||
>>> from trytond.tests.tools import (
|
||||
... activate_modules, assertEqual, assertNotEqual, set_user)
|
||||
|
||||
>>> today = dt.date.today()
|
||||
>>> yesterday = today - dt.timedelta(days=1)
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
>>> Employee = Model.get('company.employee')
|
||||
>>> Party = Model.get('party.party')
|
||||
>>> User = Model.get('res.user')
|
||||
|
||||
Set employee::
|
||||
|
||||
>>> employee_party = Party(name="Employee")
|
||||
>>> employee_party.save()
|
||||
>>> employee = Employee(party=employee_party)
|
||||
>>> employee.save()
|
||||
>>> user = User(config.user)
|
||||
>>> user.employees.append(employee)
|
||||
>>> user.employee = employee
|
||||
>>> user.save()
|
||||
>>> set_user(user.id)
|
||||
|
||||
Get currency::
|
||||
|
||||
>>> currency = get_currency()
|
||||
|
||||
Create customer::
|
||||
|
||||
>>> Party = Model.get('party.party')
|
||||
>>> customer = Party(name='Customer')
|
||||
>>> customer.save()
|
||||
|
||||
Create product::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> Product = Model.get('product.product')
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('20')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> warehouse_loc, = Location.find([('code', '=', 'WH')])
|
||||
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
|
||||
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
|
||||
>>> output_loc, = Location.find([('code', '=', 'OUT')])
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
|
||||
Create Shipment Out::
|
||||
|
||||
>>> ShipmentOut = Model.get('stock.shipment.out')
|
||||
>>> shipment_out = ShipmentOut()
|
||||
>>> shipment_out.planned_date = today
|
||||
>>> shipment_out.customer = customer
|
||||
>>> shipment_out.warehouse = warehouse_loc
|
||||
|
||||
Add two shipment lines of same product::
|
||||
|
||||
>>> StockMove = Model.get('stock.move')
|
||||
>>> shipment_out.outgoing_moves.extend([StockMove(), StockMove()])
|
||||
>>> for move in shipment_out.outgoing_moves:
|
||||
... move.product = product
|
||||
... move.unit = unit
|
||||
... move.quantity = 1
|
||||
... move.from_location = output_loc
|
||||
... move.to_location = customer_loc
|
||||
... move.unit_price = Decimal('1')
|
||||
... move.currency = currency
|
||||
>>> shipment_out.save()
|
||||
>>> shipment_out.number
|
||||
>>> shipment_out.picked_by
|
||||
>>> shipment_out.packed_by
|
||||
>>> shipment_out.shipped_by
|
||||
>>> shipment_out.done_by
|
||||
|
||||
Set the shipment state to waiting::
|
||||
|
||||
>>> shipment_out.click('wait')
|
||||
>>> shipment_out.state
|
||||
'waiting'
|
||||
>>> assertNotEqual(shipment_out.number, None)
|
||||
>>> len(shipment_out.outgoing_moves)
|
||||
2
|
||||
>>> len(shipment_out.inventory_moves)
|
||||
2
|
||||
>>> assertEqual(
|
||||
... {m.origin for m in shipment_out.inventory_moves},
|
||||
... {m for m in shipment_out.outgoing_moves})
|
||||
|
||||
Make 1 unit of the product available::
|
||||
|
||||
>>> incoming_move = StockMove()
|
||||
>>> incoming_move.product = product
|
||||
>>> incoming_move.unit = unit
|
||||
>>> incoming_move.quantity = 1
|
||||
>>> incoming_move.from_location = supplier_loc
|
||||
>>> incoming_move.to_location = storage_loc
|
||||
>>> incoming_move.planned_date = today
|
||||
>>> incoming_move.effective_date = today
|
||||
>>> incoming_move.unit_price = Decimal('1')
|
||||
>>> incoming_move.currency = currency
|
||||
>>> incoming_move.click('do')
|
||||
|
||||
Assign the shipment now::
|
||||
|
||||
>>> shipment_assign = shipment_out.click('assign_wizard')
|
||||
>>> len(shipment_assign.form.moves)
|
||||
1
|
||||
>>> shipment_assign.execute('end')
|
||||
>>> shipment_out.reload()
|
||||
>>> len(shipment_out.outgoing_moves)
|
||||
2
|
||||
>>> len(shipment_out.inventory_moves)
|
||||
2
|
||||
>>> states = [m.state for m in shipment_out.inventory_moves]
|
||||
>>> states.sort()
|
||||
>>> states
|
||||
['assigned', 'draft']
|
||||
>>> effective_dates = [m.effective_date for m in
|
||||
... shipment_out.inventory_moves]
|
||||
>>> len(set(effective_dates))
|
||||
1
|
||||
>>> planned_dates = [m.planned_date for m in
|
||||
... shipment_out.outgoing_moves]
|
||||
>>> len(set(planned_dates))
|
||||
1
|
||||
|
||||
Ignore non assigned moves and pack shipment::
|
||||
|
||||
>>> shipment_assign = shipment_out.click('assign_wizard')
|
||||
>>> shipment_assign.execute('ignore')
|
||||
>>> sorted([m.quantity for m in shipment_out.inventory_moves])
|
||||
[0.0, 1.0]
|
||||
>>> shipment_out.picked_by
|
||||
>>> shipment_out.packed_by
|
||||
>>> shipment_out.shipped_by
|
||||
>>> shipment_out.done_by
|
||||
|
||||
>>> picking_list = Report('stock.shipment.out.picking_list')
|
||||
>>> _ = picking_list.execute([shipment_out])
|
||||
|
||||
>>> shipment_out.click('pick')
|
||||
>>> assertEqual(shipment_out.picked_by, employee)
|
||||
>>> shipment_out.packed_by
|
||||
>>> shipment_out.shipped_by
|
||||
>>> shipment_out.done_by
|
||||
|
||||
>>> shipment_out.click('pack')
|
||||
>>> assertEqual(shipment_out.packed_by, employee)
|
||||
>>> shipment_out.shipped_by
|
||||
>>> shipment_out.done_by
|
||||
>>> [m.state for m in shipment_out.outgoing_moves]
|
||||
['assigned']
|
||||
>>> len(shipment_out.inventory_moves)
|
||||
1
|
||||
>>> shipment_out.inventory_moves[0].state
|
||||
'done'
|
||||
>>> assertEqual(sum([m.quantity for m in shipment_out.inventory_moves]),
|
||||
... sum([m.quantity for m in shipment_out.outgoing_moves]))
|
||||
|
||||
>>> delivery_note = Report('stock.shipment.out.delivery_note')
|
||||
>>> _ = delivery_note.execute([shipment_out])
|
||||
|
||||
Set the state as Shipped::
|
||||
|
||||
>>> shipment_out.click('ship')
|
||||
>>> assertEqual(shipment_out.shipped_by, employee)
|
||||
>>> shipment_out.done_by
|
||||
|
||||
Set the state as Done::
|
||||
|
||||
>>> shipment_out.click('do')
|
||||
>>> assertEqual(shipment_out.done_by, employee)
|
||||
>>> [m.state for m in shipment_out.outgoing_moves]
|
||||
['done']
|
||||
>>> planned_dates = [m.planned_date for m in
|
||||
... shipment_out.outgoing_moves]
|
||||
>>> assertEqual(planned_dates, [today])
|
||||
>>> effective_dates = [m.effective_date for m in
|
||||
... shipment_out.outgoing_moves]
|
||||
>>> len(set(effective_dates))
|
||||
1
|
||||
>>> len(shipment_out.outgoing_moves)
|
||||
1
|
||||
>>> len(shipment_out.inventory_moves)
|
||||
1
|
||||
>>> shipment_out.inventory_moves[0].state
|
||||
'done'
|
||||
>>> assertEqual(sum([m.quantity for m in shipment_out.inventory_moves]),
|
||||
... sum([m.quantity for m in shipment_out.outgoing_moves]))
|
||||
|
||||
Create Shipment Out with effective date::
|
||||
|
||||
>>> ShipmentOut = Model.get('stock.shipment.out')
|
||||
>>> shipment_out = ShipmentOut()
|
||||
>>> shipment_out.planned_date = yesterday
|
||||
>>> shipment_out.effective_date = yesterday
|
||||
>>> shipment_out.customer = customer
|
||||
>>> shipment_out.warehouse = warehouse_loc
|
||||
>>> move = shipment_out.outgoing_moves.new()
|
||||
>>> move.product = product
|
||||
>>> move.unit = unit
|
||||
>>> move.quantity = 1
|
||||
>>> move.from_location = output_loc
|
||||
>>> move.to_location = customer_loc
|
||||
>>> move.unit_price = Decimal('1')
|
||||
>>> move.currency = currency
|
||||
>>> shipment_out.click('wait')
|
||||
|
||||
Make 1 unit of the product available::
|
||||
|
||||
>>> incoming_move = StockMove()
|
||||
>>> incoming_move.product = product
|
||||
>>> incoming_move.unit = unit
|
||||
>>> incoming_move.quantity = 1
|
||||
>>> incoming_move.from_location = supplier_loc
|
||||
>>> incoming_move.to_location = storage_loc
|
||||
>>> incoming_move.planned_date = yesterday
|
||||
>>> incoming_move.effective_date = yesterday
|
||||
>>> incoming_move.unit_price = Decimal('1')
|
||||
>>> incoming_move.currency = currency
|
||||
>>> incoming_move.click('do')
|
||||
|
||||
Finish the shipment::
|
||||
|
||||
>>> shipment_out.click('assign_try')
|
||||
>>> shipment_out.click('pick')
|
||||
>>> len(shipment_out.inventory_moves)
|
||||
1
|
||||
>>> len(shipment_out.outgoing_moves)
|
||||
1
|
||||
>>> shipment_out.click('pack')
|
||||
>>> shipment_out.click('pick')
|
||||
>>> len(shipment_out.inventory_moves)
|
||||
1
|
||||
>>> len(shipment_out.outgoing_moves)
|
||||
1
|
||||
>>> shipment_out.click('pack')
|
||||
|
||||
Finish the shipment::
|
||||
|
||||
>>> shipment_out.click('do')
|
||||
>>> shipment_out.state
|
||||
'done'
|
||||
>>> outgoing_move, = shipment_out.outgoing_moves
|
||||
>>> assertEqual(outgoing_move.effective_date, yesterday)
|
||||
>>> inventory_move, = shipment_out.inventory_moves
|
||||
>>> assertEqual(inventory_move.effective_date, yesterday)
|
||||
|
||||
Reschedule shipment::
|
||||
|
||||
>>> shipment_copy, = shipment_out.duplicate()
|
||||
>>> shipment_copy.planned_date = yesterday
|
||||
>>> shipment_copy.click('wait')
|
||||
>>> Cron = Model.get('ir.cron')
|
||||
>>> cron = Cron(method='stock.shipment.out|reschedule')
|
||||
>>> cron.interval_number = 1
|
||||
>>> cron.interval_type = 'months'
|
||||
>>> cron.click('run_once')
|
||||
>>> shipment_copy.reload()
|
||||
>>> assertEqual(shipment_copy.planned_date, today)
|
||||
89
modules/stock/tests/scenario_stock_shipment_out_return.rst
Normal file
89
modules/stock/tests/scenario_stock_shipment_out_return.rst
Normal file
@@ -0,0 +1,89 @@
|
||||
==================================
|
||||
Stock Shipment Out Return Scenario
|
||||
==================================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model, Report
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.modules.currency.tests.tools import get_currency
|
||||
>>> from trytond.tests.tools import activate_modules, assertNotEqual
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
>>> Party = Model.get('party.party')
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
|
||||
Create customer::
|
||||
|
||||
>>> customer = Party(name='Customer')
|
||||
>>> customer.save()
|
||||
|
||||
Create product::
|
||||
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = "Product"
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('20')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> warehouse_loc, = Location.find([('code', '=', 'WH')])
|
||||
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
|
||||
Create Shipment Out Return::
|
||||
|
||||
>>> ShipmentOutReturn = Model.get('stock.shipment.out.return')
|
||||
>>> shipment = ShipmentOutReturn()
|
||||
>>> shipment.customer = customer
|
||||
>>> shipment.warehouse = warehouse_loc
|
||||
>>> move = shipment.incoming_moves.new()
|
||||
>>> move.product = product
|
||||
>>> move.unit = unit
|
||||
>>> move.quantity = 1
|
||||
>>> move.from_location = customer_loc
|
||||
>>> move.to_location = warehouse_loc.input_location
|
||||
>>> move.unit_price = Decimal('20')
|
||||
>>> move.currency = get_currency()
|
||||
>>> shipment.save()
|
||||
>>> assertNotEqual(shipment.number, None)
|
||||
|
||||
>>> len(shipment.incoming_moves)
|
||||
1
|
||||
>>> len(shipment.inventory_moves)
|
||||
0
|
||||
|
||||
Receive shipment::
|
||||
|
||||
>>> shipment.click('receive')
|
||||
>>> shipment.state
|
||||
'received'
|
||||
|
||||
>>> [m.state for m in shipment.incoming_moves]
|
||||
['done']
|
||||
>>> [m.state for m in shipment.inventory_moves]
|
||||
['draft']
|
||||
|
||||
>>> restocking_list = Report('stock.shipment.out.return.restocking_list')
|
||||
>>> _ = restocking_list.execute([shipment])
|
||||
|
||||
Finish the shipment::
|
||||
|
||||
>>> shipment.click('do')
|
||||
>>> shipment.state
|
||||
'done'
|
||||
>>> len(shipment.incoming_moves)
|
||||
1
|
||||
>>> [m.state for m in shipment.inventory_moves]
|
||||
['done']
|
||||
@@ -0,0 +1,82 @@
|
||||
=========================================================
|
||||
Stock Shipment Out Return Same Storage and Input Scenario
|
||||
=========================================================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.modules.currency.tests.tools import get_currency
|
||||
>>> from trytond.tests.tools import activate_modules
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
Create customer::
|
||||
|
||||
>>> Party = Model.get('party.party')
|
||||
>>> customer = Party(name='Customer')
|
||||
>>> customer.save()
|
||||
|
||||
Create product::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> Product = Model.get('product.product')
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('20')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> warehouse_loc, = Location.find([('code', '=', 'WH')])
|
||||
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
>>> storage1 = Location(name="Storage 1", parent=storage_loc)
|
||||
>>> storage1.save()
|
||||
|
||||
Use storage location as input location::
|
||||
|
||||
>>> warehouse_loc.input_location = storage_loc
|
||||
>>> warehouse_loc.save()
|
||||
|
||||
Create Shipment Out Return::
|
||||
|
||||
>>> ShipmentOutReturn = Model.get('stock.shipment.out.return')
|
||||
>>> shipment = ShipmentOutReturn()
|
||||
>>> shipment.customer = customer
|
||||
>>> shipment.warehouse = warehouse_loc
|
||||
>>> move = shipment.incoming_moves.new()
|
||||
>>> move.product = product
|
||||
>>> move.unit = unit
|
||||
>>> move.quantity = 1
|
||||
>>> move.from_location = customer_loc
|
||||
>>> move.to_location = storage1
|
||||
>>> move.unit_price = Decimal('20')
|
||||
>>> move.currency = get_currency()
|
||||
>>> shipment.save()
|
||||
|
||||
>>> len(shipment.incoming_moves)
|
||||
1
|
||||
>>> len(shipment.inventory_moves)
|
||||
0
|
||||
|
||||
Shipment is done when receiving::
|
||||
|
||||
>>> shipment.click('receive')
|
||||
>>> shipment.state
|
||||
'done'
|
||||
>>> move, = shipment.incoming_moves
|
||||
>>> move.state
|
||||
'done'
|
||||
>>> len(shipment.inventory_moves)
|
||||
0
|
||||
@@ -0,0 +1,117 @@
|
||||
===================================================
|
||||
Stock Shipment Out Same Storage and Output Scenario
|
||||
===================================================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model
|
||||
>>> from trytond.modules.company.tests.tools import create_company
|
||||
>>> from trytond.modules.currency.tests.tools import get_currency
|
||||
>>> from trytond.tests.tools import activate_modules
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('stock', create_company)
|
||||
|
||||
>>> Move = Model.get('stock.move')
|
||||
|
||||
Create customer::
|
||||
|
||||
>>> Party = Model.get('party.party')
|
||||
>>> customer = Party(name='Customer')
|
||||
>>> customer.save()
|
||||
|
||||
Create product::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> Product = Model.get('product.product')
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'Product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal('20')
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Get stock locations::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> warehouse_loc, = Location.find([('code', '=', 'WH')])
|
||||
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
|
||||
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||||
>>> warehouse_loc.output_location = storage_loc
|
||||
>>> warehouse_loc.save()
|
||||
|
||||
Create Shipment Out::
|
||||
|
||||
>>> ShipmentOut = Model.get('stock.shipment.out')
|
||||
>>> shipment_out = ShipmentOut()
|
||||
>>> shipment_out.customer = customer
|
||||
>>> shipment_out.warehouse = warehouse_loc
|
||||
>>> move = shipment_out.outgoing_moves.new()
|
||||
>>> move.product = product
|
||||
>>> move.unit = unit
|
||||
>>> move.quantity = 1
|
||||
>>> move.unit_price = Decimal('5')
|
||||
>>> move.currency = get_currency()
|
||||
>>> move.from_location = storage_loc
|
||||
>>> move.to_location = customer_loc
|
||||
>>> shipment_out.save()
|
||||
|
||||
>>> len(shipment_out.outgoing_moves)
|
||||
1
|
||||
>>> len(shipment_out.inventory_moves)
|
||||
0
|
||||
|
||||
Set the shipment state to waiting::
|
||||
|
||||
>>> shipment_out.click('wait')
|
||||
>>> shipment_out.state
|
||||
'waiting'
|
||||
>>> len(shipment_out.outgoing_moves)
|
||||
1
|
||||
>>> len(shipment_out.inventory_moves)
|
||||
0
|
||||
|
||||
Try to assign::
|
||||
|
||||
>>> shipment_out.click('assign_try')
|
||||
>>> shipment_out.state
|
||||
'waiting'
|
||||
>>> move, = shipment_out.outgoing_moves
|
||||
>>> move.state
|
||||
'draft'
|
||||
|
||||
Fill storage location::
|
||||
|
||||
>>> move = Move()
|
||||
>>> move.from_location = warehouse_loc.lost_found_location
|
||||
>>> move.to_location = storage_loc
|
||||
>>> move.product = product
|
||||
>>> move.quantity = 1
|
||||
>>> move.click('do')
|
||||
>>> move.state
|
||||
'done'
|
||||
|
||||
Try to assign again::
|
||||
|
||||
>>> shipment_out.click('assign_try')
|
||||
>>> shipment_out.state
|
||||
'assigned'
|
||||
>>> move, = shipment_out.outgoing_moves
|
||||
>>> move.state
|
||||
'assigned'
|
||||
|
||||
Pack the shipment::
|
||||
|
||||
>>> shipment_out.click('pack')
|
||||
>>> shipment_out.state
|
||||
'packed'
|
||||
>>> len(shipment_out.outgoing_moves)
|
||||
1
|
||||
>>> len(shipment_out.inventory_moves)
|
||||
0
|
||||
1740
modules/stock/tests/test_module.py
Normal file
1740
modules/stock/tests/test_module.py
Normal file
File diff suppressed because it is too large
Load Diff
8
modules/stock/tests/test_scenario.py
Normal file
8
modules/stock/tests/test_scenario.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.tests.test_tryton import load_doc_tests
|
||||
|
||||
|
||||
def load_tests(*args, **kwargs):
|
||||
return load_doc_tests(__name__, __file__, *args, **kwargs)
|
||||
Reference in New Issue
Block a user