changeset 2a924f6752c3 in modules/stock:default
details: https://hg.tryton.org/modules/stock?cmd=changeset&node=2a924f6752c3
description:
Replace test setuptools command by unittest discover
issue9215
review389851002
diffstat:
setup.py | 4 +-
tests/__init__.py | 7 -
tests/test_module.py | 1524 +++++++++++++++++++++++++++++++++++++++++++++
tests/test_scenario.py | 22 +
tests/test_stock.py | 1607 ------------------------------------------------
tox.ini | 3 +-
6 files changed, 1549 insertions(+), 1618 deletions(-)
diffs (3211 lines):
diff -r 80d6b2eb115e -r 2a924f6752c3 setup.py
--- a/setup.py Tue Apr 12 10:35:40 2022 +0200
+++ b/setup.py Sat Apr 16 18:30:19 2022 +0200
@@ -143,6 +143,7 @@
install_requires=requires,
extras_require={
'sparklines': ['pygal'],
+ 'test': tests_require,
},
dependency_links=dependency_links,
zip_safe=False,
@@ -150,7 +151,4 @@
[trytond.modules]
stock = trytond.modules.stock
""",
- test_suite='tests',
- test_loader='trytond.test_loader:Loader',
- tests_require=tests_require,
)
diff -r 80d6b2eb115e -r 2a924f6752c3 tests/__init__.py
--- a/tests/__init__.py Tue Apr 12 10:35:40 2022 +0200
+++ b/tests/__init__.py Sat Apr 16 18:30:19 2022 +0200
@@ -1,9 +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.
-
-try:
- from trytond.modules.stock.tests.test_stock import suite
-except ImportError:
- from .test_stock import suite
-
-__all__ = ['suite']
diff -r 80d6b2eb115e -r 2a924f6752c3 tests/test_module.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test_module.py Sat Apr 16 18:30:19 2022 +0200
@@ -0,0 +1,1524 @@
+# This file is part of Tryton. The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+
+import datetime
+from collections import defaultdict
+from decimal import Decimal
+from functools import partial
+
+from dateutil.relativedelta import relativedelta
+
+from trytond.exceptions import UserError, UserWarning
+from trytond.modules.company.tests import (
+ CompanyTestMixin, PartyCompanyCheckEraseMixin, create_company, set_company)
+from trytond.pool import Pool
+from trytond.tests.test_tryton import ModuleTestCase, with_transaction
+from trytond.transaction import Transaction
+
+
+class StockTestCase(
+ PartyCompanyCheckEraseMixin, CompanyTestMixin, ModuleTestCase):
+ 'Test Stock module'
+ module = 'stock'
+ longMessage = True
+
+ @with_transaction()
+ def test_move_internal_quantity(self):
+ 'Test Move.internal_quantity'
+ pool = Pool()
+ Uom = pool.get('product.uom')
+ Template = pool.get('product.template')
+ Product = pool.get('product.product')
+ Location = pool.get('stock.location')
+ Move = pool.get('stock.move')
+
+ kg, = Uom.search([('name', '=', 'Kilogram')])
+ g, = Uom.search([('name', '=', 'Gram')])
+ template, = Template.create([{
+ 'name': 'Test Move.internal_quantity',
+ 'type': 'goods',
+ 'default_uom': kg.id,
+ }])
+ product, = Product.create([{
+ 'template': template.id,
+ }])
+ supplier, = Location.search([('code', '=', 'SUP')])
+ storage, = Location.search([('code', '=', 'STO')])
+ company = create_company()
+ currency = company.currency
+ with set_company(company):
+ tests = [
+ (kg, 10, 10, 0),
+ (g, 100, 0.1, 1),
+ (g, 1, 0, 0), # rounded
+ (kg, 35.23, 35.23, 2), # check infinite loop
+ ]
+ for uom, quantity, internal_quantity, ndigits in tests:
+ move, = Move.create([{
+ 'product': product.id,
+ 'uom': uom.id,
+ 'quantity': quantity,
+ 'from_location': supplier.id,
+ 'to_location': storage.id,
+ 'company': company.id,
+ 'unit_price': Decimal('1'),
+ 'currency': currency.id,
+ }])
+ self.assertEqual(round(move.internal_quantity, ndigits),
+ internal_quantity)
+
+ for uom, quantity, internal_quantity, ndigits in tests:
+ Move.write([move], {
+ 'uom': uom.id,
+ 'quantity': quantity,
+ })
+ self.assertEqual(round(move.internal_quantity, ndigits),
+ internal_quantity)
+
+ @with_transaction()
+ def test_products_by_location(self):
+ 'Test products_by_location'
+ pool = Pool()
+ Uom = pool.get('product.uom')
+ Template = pool.get('product.template')
+ Product = pool.get('product.product')
+ Location = pool.get('stock.location')
+ Move = pool.get('stock.move')
+ Period = pool.get('stock.period')
+ transaction = Transaction()
+
+ kg, = Uom.search([('name', '=', 'Kilogram')])
+ g, = Uom.search([('name', '=', 'Gram')])
+ template, = Template.create([{
+ 'name': 'Test products_by_location',
+ 'type': 'goods',
+ 'default_uom': kg.id,
+ }])
+ product, = Product.create([{
+ 'template': template.id,
+ }])
+ supplier, = Location.search([('code', '=', 'SUP')])
+ customer, = Location.search([('code', '=', 'CUS')])
+ storage, = Location.search([('code', '=', 'STO')])
+ storage_empty, = Location.copy([storage])
+ company = create_company()
+ currency = company.currency
+ with set_company(company):
+ today = datetime.date.today()
+
+ moves = Move.create([{
+ 'product': product.id,
+ 'uom': kg.id,
+ 'quantity': 5,
+ 'from_location': supplier.id,
+ 'to_location': storage.id,
+ 'planned_date': today + relativedelta(days=-5),
+ 'effective_date': today + relativedelta(days=-5),
+ 'company': company.id,
+ 'unit_price': Decimal('1'),
+ 'currency': currency.id,
+ }, {
+ 'product': product.id,
+ 'uom': kg.id,
+ 'quantity': 1,
+ 'from_location': supplier.id,
+ 'to_location': storage.id,
+ 'planned_date': today + relativedelta(days=-4),
+ 'company': company.id,
+ 'unit_price': Decimal('1'),
+ 'currency': currency.id,
+ }, {
+ 'product': product.id,
+ 'uom': kg.id,
+ 'quantity': 1,
+ 'from_location': storage.id,
+ 'to_location': customer.id,
+ 'planned_date': today,
+ 'effective_date': today,
+ 'company': company.id,
+ 'unit_price': Decimal('1'),
+ 'currency': currency.id,
+ }, {
+ 'product': product.id,
+ 'uom': kg.id,
+ 'quantity': 1,
+ 'from_location': storage.id,
+ 'to_location': customer.id,
+ 'planned_date': today,
+ 'company': company.id,
+ 'unit_price': Decimal('1'),
+ 'currency': currency.id,
+ }, {
+ 'product': product.id,
+ 'uom': kg.id,
+ 'quantity': 2,
+ 'from_location': storage.id,
+ 'to_location': customer.id,
+ 'planned_date': today + relativedelta(days=5),
+ 'company': company.id,
+ 'unit_price': Decimal('1'),
+ 'currency': currency.id,
+ }, {
+ 'product': product.id,
+ 'uom': kg.id,
+ 'quantity': 5,
+ 'from_location': supplier.id,
+ 'to_location': storage.id,
+ 'planned_date': today + relativedelta(days=7),
+ 'company': company.id,
+ 'unit_price': Decimal('1'),
+ 'currency': currency.id,
+ }])
+ Move.do([moves[0], moves[2]])
+
+ products_by_location = partial(Product.products_by_location,
+ [storage.id], grouping_filter=([product.id],))
+
+ tests = [
+ ({'stock_date_end': today + relativedelta(days=-6),
+ }, 0),
+ ({'stock_date_end': today + relativedelta(days=-5),
+ }, 5),
+ ({'stock_date_end': today + relativedelta(days=-4),
+ }, 5),
+ ({'stock_date_end': today + relativedelta(days=-3),
+ }, 5),
+ ({'stock_date_end': today,
+ }, 4),
+ ({'stock_date_end': today + relativedelta(days=1),
+ }, 3),
+ ({'stock_date_end': today + relativedelta(days=5),
+ }, 1),
+ ({'stock_date_end': today + relativedelta(days=6),
+ }, 1),
+ ({'stock_date_end': today + relativedelta(days=7),
+ }, 6),
+ ({'stock_date_end': today + relativedelta(days=8),
+ }, 6),
+ ({'stock_date_end': False,
+ }, 6),
+ ({'stock_date_end': today + relativedelta(days=-6),
+ 'forecast': True,
+ }, 0),
+ ({'stock_date_end': today + relativedelta(days=-5),
+ 'forecast': True,
+ }, 5),
+ ({'stock_date_end': today + relativedelta(days=-4),
+ 'forecast': True,
+ }, 5),
+ ({'stock_date_end': today + relativedelta(days=-3),
+ 'forecast': True,
+ }, 5),
+ ({'stock_date_end': today,
+ 'forecast': True,
+ }, 3),
+ ({'stock_date_end': today + relativedelta(days=1),
+ 'forecast': True,
+ }, 3),
+ ({'stock_date_end': today + relativedelta(days=5),
+ 'forecast': True,
+ }, 1),
+ ({'stock_date_end': today + relativedelta(days=6),
+ 'forecast': True,
+ }, 1),
+ ({'stock_date_end': today + relativedelta(days=7),
+ 'forecast': True,
+ }, 6),
+ ({'stock_date_end': False,
+ 'forecast': True,
+ }, 6),
+ ]
+ today_quantity = 4
+
+ def tests_product_quantity(context, quantity):
+ product_reloaded = Product(product.id)
+ if (not context.get('stock_date_end')
+ or context['stock_date_end'] > today):
+ self.assertEqual(
+ product_reloaded.forecast_quantity, quantity,
+ msg='context %r' % context)
+ self.assertEqual(
+ product_reloaded.quantity, today_quantity,
+ msg='context %r' % context)
+ elif context.get('forecast'):
+ self.assertEqual(
+ product_reloaded.forecast_quantity, quantity,
+ msg='context %r' % context)
+ elif context.get('stock_date_end') == today:
+ self.assertEqual(product_reloaded.quantity, quantity,
+ msg='context %r' % context)
+ else:
+ self.assertEqual(
+ product_reloaded.forecast_quantity, quantity,
+ msg='context %r' % context)
+ self.assertEqual(product_reloaded.quantity, quantity,
+ msg='context %r' % context)
+
+ def tests_product_search_quantity(context, quantity):
+ if (not context.get('stock_date_end')
+ or context['stock_date_end'] > today
+ or context.get('forecast')):
+ fname = 'forecast_quantity'
+ else:
+ fname = 'quantity'
+ found_products = Product.search([
+ (fname, '=', quantity),
+ ])
+ self.assertIn(product, found_products)
+
+ found_products = Product.search([
+ (fname, '!=', quantity),
+ ])
+ self.assertNotIn(product, found_products)
+
+ found_products = Product.search([
+ (fname, 'in', (quantity, quantity + 1)),
+ ])
+ self.assertIn(product, found_products)
+
+ found_products = Product.search([
+ (fname, 'not in', (quantity, quantity + 1)),
+ ])
+ self.assertNotIn(product, found_products)
+
+ found_products = Product.search([
+ (fname, '<', quantity),
+ ])
+ self.assertNotIn(product, found_products)
+ found_products = Product.search([
+ (fname, '<', quantity + 1),
+ ])
+ self.assertIn(product, found_products)
+
+ found_products = Product.search([
+ (fname, '>', quantity),
+ ])
+ self.assertNotIn(product, found_products)
+ found_products = Product.search([
+ (fname, '>', quantity - 1),
+ ])
+ self.assertIn(product, found_products)
+
+ found_products = Product.search([
+ (fname, '>=', quantity),
+ ])
+ self.assertIn(product, found_products)
+
+ found_products = Product.search([
+ (fname, '<=', quantity),
+ ])
+ self.assertIn(product, found_products)
+
+ def test_products_by_location():
+ for context, quantity in tests:
+ with transaction.set_context(context):
+ if not quantity:
+ self.assertEqual(products_by_location(), {})
+ else:
+ self.assertEqual(products_by_location(),
+ {(storage.id, product.id): quantity})
+ with transaction.set_context(
+ locations=[storage.id]):
+ tests_product_quantity(context, quantity)
+ tests_product_search_quantity(
+ context, quantity)
+ with transaction.set_context(
+ locations=[storage.id, storage_empty.id]):
+ tests_product_quantity(context, quantity)
+ tests_product_search_quantity(
+ context, quantity)
+
+ test_products_by_location()
+
+ periods = [
+ today + relativedelta(days=-6),
+ today + relativedelta(days=-5),
+ today + relativedelta(days=-4),
+ today + relativedelta(days=-3),
+ today + relativedelta(days=-2),
+ ]
+
+ moves = Move.create([{
+ 'product': product.id,
+ 'uom': g.id,
+ 'quantity': 1,
+ 'from_location': supplier.id,
+ 'to_location': storage.id,
+ 'planned_date': today + relativedelta(days=-5),
+ 'effective_date': (today
+ + relativedelta(days=-5)),
+ 'company': company.id,
+ 'unit_price': Decimal('1'),
+ 'currency': currency.id,
+ }])
+ Move.do(moves)
+ # Nothing should change when adding a small quantity
+ test_products_by_location()
+
+ for period_date in periods:
+ period, = Period.create([{
+ 'date': period_date,
+ 'company': company.id,
+ }])
+ Period.close([period])
+ test_products_by_location()
+
+ @with_transaction()
+ def test_products_by_location_with_childs(self):
+ 'Test products_by_location with_childs and stock_skip_warehouse'
+ pool = Pool()
+ Uom = pool.get('product.uom')
+ Template = pool.get('product.template')
+ Product = pool.get('product.product')
+ Location = pool.get('stock.location')
+ Move = pool.get('stock.move')
+
+ unit, = Uom.search([('name', '=', 'Unit')])
+ template, = Template.create([{
+ 'name': 'Test products_by_location',
+ 'type': 'goods',
+ 'default_uom': unit.id,
+ }])
+ product, = Product.create([{
+ 'template': template.id,
+ }])
+
+ lost_found, = Location.search([('type', '=', 'lost_found')])
+ warehouse, = Location.search([('type', '=', 'warehouse')])
+ storage, = Location.search([('code', '=', 'STO')])
+ input_, = Location.search([('code', '=', 'IN')])
+ storage1, = Location.create([{
+ 'name': 'Storage 1',
+ 'type': 'view',
+ 'parent': storage.id,
+ }])
+ storage2, = Location.create([{
+ 'name': 'Storage 1.1',
+ 'type': 'view',
+ 'parent': storage1.id,
+ }])
+ storage3, = Location.create([{
+ 'name': 'Storage 2',
+ 'type': 'view',
+ 'parent': storage.id,
+ }])
+ company = create_company()
+ with set_company(company):
+ today = datetime.date.today()
+
+ moves = Move.create([{
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 1,
+ 'from_location': lost_found.id,
+ 'to_location': storage.id,
+ 'planned_date': today,
+ 'effective_date': today,
+ 'company': company.id,
+ }, {
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 1,
+ 'from_location': input_.id,
+ 'to_location': storage.id,
+ 'planned_date': today,
+ 'effective_date': today,
+ 'company': company.id,
+ }])
+ Move.do(moves)
+
+ products_by_location = Product.products_by_location(
+ [warehouse.id],
+ grouping_filter=([product.id],),
+ with_childs=True)
+ self.assertEqual(products_by_location[(warehouse.id, product.id)],
+ 1)
+ products_by_location = Product.products_by_location(
+ [warehouse.id, storage.id],
+ grouping_filter=([product.id],),
+ with_childs=True)
+ self.assertEqual(
+ products_by_location[(warehouse.id, product.id)], 1)
+ self.assertEqual(products_by_location[(storage.id, product.id)], 2)
+
+ with Transaction().set_context(locations=[warehouse.id]):
+ found_products = Product.search([
+ ('quantity', '=', 1),
+ ])
+ self.assertListEqual([product], found_products)
+
+ with Transaction().set_context(stock_skip_warehouse=True):
+ products_by_location = Product.products_by_location(
+ [warehouse.id],
+ grouping_filter=([product.id],),
+ with_childs=True)
+ products_by_location_all = Product.products_by_location(
+ [warehouse.id], with_childs=True)
+ self.assertEqual(
+ products_by_location[(warehouse.id, product.id)], 2)
+ self.assertEqual(
+ products_by_location_all[(warehouse.id, product.id)], 2)
+
+ with Transaction().set_context(locations=[warehouse.id]):
+ found_products = Product.search([
+ ('quantity', '=', 2),
+ ])
+ self.assertListEqual([product], found_products)
+
+ @with_transaction()
+ def test_products_by_location_flat_childs(self, period_closed=False):
+ "Test products_by_location on flat_childs"
+ pool = Pool()
+ Uom = pool.get('product.uom')
+ Template = pool.get('product.template')
+ Product = pool.get('product.product')
+ Location = pool.get('stock.location')
+ Move = pool.get('stock.move')
+ Date = pool.get('ir.date')
+ Period = pool.get('stock.period')
+
+ unit, = Uom.search([('name', '=', 'Unit')])
+ template, = Template.create([{
+ 'name': "Product",
+ 'type': 'goods',
+ 'default_uom': unit.id,
+ }])
+ product, = Product.create([{
+ 'template': template.id,
+ }])
+
+ lost_found, = Location.search([('type', '=', 'lost_found')])
+ storage, = Location.search([('code', '=', 'STO')])
+ storage.flat_childs = True
+ storage.save()
+ storage1, = Location.create([{
+ 'name': 'Storage 1',
+ 'type': 'storage',
+ 'parent': storage.id,
+ }])
+ storage2, = Location.create([{
+ 'name': 'Storage 2',
+ 'type': 'storage',
+ 'parent': storage.id,
+ }])
+
+ company = create_company()
+ with set_company(company):
+ date = Date.today() - relativedelta(days=1)
+
+ moves = Move.create([{
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 1,
+ 'from_location': lost_found.id,
+ 'to_location': storage.id,
+ 'planned_date': date,
+ 'effective_date': date,
+ 'company': company.id,
+ }, {
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 1,
+ 'from_location': lost_found.id,
+ 'to_location': storage1.id,
+ 'planned_date': date,
+ 'effective_date': date,
+ 'company': company.id,
+ }, {
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 1,
+ 'from_location': storage1.id,
+ 'to_location': storage2.id,
+ 'planned_date': date,
+ 'effective_date': date,
+ 'company': company.id,
+ }])
+ Move.do(moves)
+
+ if period_closed:
+ period, = Period.create([{
+ 'date': date,
+ 'company': company.id,
+ }])
+ Period.close([period])
+
+ # Test flat location
+ products_by_location = Product.products_by_location(
+ [storage.id],
+ grouping_filter=([product.id],),
+ with_childs=True)
+ self.assertEqual(
+ products_by_location[(storage.id, product.id)], 2)
+
+ # Test mixed flat and nested location
+ products_by_location = Product.products_by_location(
+ [storage.parent.id, storage.id, storage1.id, storage2.id],
+ grouping_filter=([product.id],),
+ with_childs=True)
+ self.assertEqual(
+ products_by_location[(storage.parent.id, product.id)], 2)
+ self.assertEqual(
+ products_by_location[(storage.id, product.id)], 2)
+ self.assertEqual(
+ products_by_location[(storage1.id, product.id)], 0)
+ self.assertEqual(
+ products_by_location[(storage2.id, product.id)], 1)
+
+ # Test non flat
+ products_by_location = Product.products_by_location(
+ [lost_found.id],
+ grouping_filter=([product.id],),
+ with_childs=True)
+ self.assertEqual(
+ products_by_location[(lost_found.id, product.id)], -2)
+
+ def test_products_by_location_flat_childs_period_closed(self):
+ "Test products_by_location on flat_childs with period closed"
+ self.test_products_by_location_flat_childs(period_closed=True)
+
+ @with_transaction()
+ def test_products_by_location_2nd_level_flat_childs(self):
+ "Test products_by_location on 2nd level flat_childs"
+ pool = Pool()
+ Uom = pool.get('product.uom')
+ Template = pool.get('product.template')
+ Product = pool.get('product.product')
+ Location = pool.get('stock.location')
+ Move = pool.get('stock.move')
+ Date = pool.get('ir.date')
+
+ unit, = Uom.search([('name', '=', 'Unit')])
+ template, = Template.create([{
+ 'name': "Product",
+ 'type': 'goods',
+ 'default_uom': unit.id,
+ }])
+ product, = Product.create([{
+ 'template': template.id,
+ }])
+
+ supplier, = Location.search([('code', '=', 'SUP')])
+ storage, = Location.search([('code', '=', 'STO')])
+ storage1, = Location.create([{
+ 'name': 'Storage 1',
+ 'type': 'storage',
+ 'flat_childs': True,
+ 'parent': storage.id,
+ }])
+ storage2, = Location.create([{
+ 'name': 'Storage 2',
+ 'type': 'storage',
+ 'parent': storage1.id,
+ }])
+
+ company = create_company()
+ with set_company(company):
+ date = Date.today() - relativedelta(days=1)
+
+ moves = Move.create([{
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 80,
+ 'from_location': supplier.id,
+ 'to_location': storage.id,
+ 'effective_date': date,
+ 'company': company.id,
+ 'unit_price': 10.0
+ }, {
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 60,
+ 'from_location': storage.id,
+ 'to_location': storage2.id,
+ 'effective_date': date,
+ 'company': company.id,
+ }])
+ Move.do(moves)
+
+ # Test 2nd level location
+ products_by_location = Product.products_by_location(
+ [storage.id],
+ grouping_filter=([product.id],),
+ with_childs=True)
+ self.assertEqual(
+ products_by_location[(storage.id, product.id)], 80)
+
+ # Test 1st level and 2nd level nested locations
+ products_by_location = Product.products_by_location(
+ [storage.id, storage1.id],
+ grouping_filter=([product.id],),
+ with_childs=True)
+ self.assertEqual(
+ products_by_location[(storage.id, product.id)], 80)
+ self.assertEqual(
+ products_by_location[(storage1.id, product.id)], 60)
+
+ # Test mixed flat and 2nd level nested locations
+ products_by_location = Product.products_by_location(
+ [storage.id, storage2.id],
+ grouping_filter=([product.id],),
+ with_childs=True)
+ self.assertEqual(
+ products_by_location[(storage.id, product.id)], 80)
+ self.assertEqual(
+ products_by_location[(storage2.id, product.id)], 60)
+
+ @with_transaction()
+ def test_templates_by_location(self, period_closed=False):
+ "Test products_by_location grouped by template"
+ pool = Pool()
+ Uom = pool.get('product.uom')
+ Template = pool.get('product.template')
+ Product = pool.get('product.product')
+ Location = pool.get('stock.location')
+ Move = pool.get('stock.move')
+ Period = pool.get('stock.period')
+ Date = pool.get('ir.date')
+
+ unit, = Uom.search([('name', '=', 'Unit')])
+ template, = Template.create([{
+ 'name': 'Template',
+ 'type': 'goods',
+ 'default_uom': unit.id,
+ }])
+ product1, product2 = Product.create([{
+ 'template': template.id,
+ }] * 2)
+
+ lost_found, = Location.search([('type', '=', 'lost_found')])
+ storage, = Location.search([('code', '=', 'STO')])
+ input_, = Location.search([('code', '=', 'IN')])
+ company = create_company()
+ with set_company(company):
+ date = Date.today() - relativedelta(days=1)
+
+ moves = Move.create([{
+ 'product': product1.id,
+ 'uom': unit.id,
+ 'quantity': 2,
+ 'from_location': lost_found.id,
+ 'to_location': storage.id,
+ 'planned_date': date,
+ 'effective_date': date,
+ 'company': company.id,
+ }, {
+ 'product': product2.id,
+ 'uom': unit.id,
+ 'quantity': 3,
+ 'from_location': input_.id,
+ 'to_location': storage.id,
+ 'planned_date': date,
+ 'effective_date': date,
+ 'company': company.id,
+ }])
+ Move.do(moves)
+
+ if period_closed:
+ period, = Period.create([{
+ 'date': date,
+ 'company': company.id,
+ }])
+ Period.close([period])
+
+ templates_by_location = Product.products_by_location(
+ [storage.id],
+ grouping=('product.template',),
+ grouping_filter=([template.id],))
+
+ self.assertDictEqual(templates_by_location, {
+ (storage.id, template.id): 5,
+ })
+
+ def test_templates_by_location_period_closed(self):
+ "Test products_by_location grouped by template with period closed"
+ self.test_templates_by_location(period_closed=True)
+
+ @with_transaction()
+ def test_period(self):
+ 'Test period'
+ pool = Pool()
+ Uom = pool.get('product.uom')
+ Template = pool.get('product.template')
+ Product = pool.get('product.product')
+ Location = pool.get('stock.location')
+ Move = pool.get('stock.move')
+ Period = pool.get('stock.period')
+ transaction = Transaction()
+
+ unit, = Uom.search([('name', '=', 'Unit')])
+ template, = Template.create([{
+ 'name': 'Test period',
+ 'type': 'goods',
+ 'default_uom': unit.id,
+ }])
+ product, = Product.create([{
+ 'template': template.id,
+ }])
+ supplier, = Location.search([('code', '=', 'SUP')])
+ customer, = Location.search([('code', '=', 'CUS')])
+ storage, = Location.search([('code', '=', 'STO')])
+ company = create_company()
+ currency = company.currency
+ with set_company(company):
+ today = datetime.date.today()
+
+ moves = Move.create([{
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 10,
+ 'from_location': supplier.id,
+ 'to_location': storage.id,
+ 'planned_date': today + relativedelta(days=-5),
+ 'effective_date': today + relativedelta(days=-5),
+ 'company': company.id,
+ 'unit_price': Decimal('1'),
+ 'currency': currency.id,
+ }, {
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 15,
+ 'from_location': supplier.id,
+ 'to_location': storage.id,
+ 'planned_date': today + relativedelta(days=-4),
+ 'effective_date': today + relativedelta(days=-4),
+ 'company': company.id,
+ 'unit_price': Decimal('1'),
+ 'currency': currency.id,
+ }, {
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 5,
+ 'from_location': storage.id,
+ 'to_location': customer.id,
+ 'planned_date': today + relativedelta(days=-3),
+ 'effective_date': today + relativedelta(days=-3),
+ 'company': company.id,
+ 'unit_price': Decimal('1'),
+ 'currency': currency.id,
+ }])
+ Move.do(moves)
+ Move.create([{
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 3,
+ 'from_location': supplier.id,
+ 'to_location': storage.id,
+ 'planned_date': None,
+ 'effective_date': None,
+ 'company': company.id,
+ 'unit_price': Decimal('1'),
+ 'currency': currency.id,
+ }])
+
+ tests = [
+ (-5, {
+ supplier.id: -10,
+ storage.id: 10,
+ }),
+ (-3, {
+ supplier.id: -25,
+ storage.id: 20,
+ customer.id: 5,
+ })
+ ]
+
+ products_by_location = partial(Product.products_by_location,
+ [storage.id], grouping_filter=([product.id],))
+
+ tests_pbl = [
+ ({'stock_date_end': today + relativedelta(days=-6)}, 0),
+ ({'stock_date_end': today + relativedelta(days=-5)}, 10),
+ ({'stock_date_end': today + relativedelta(days=-4)}, 25),
+ ({'stock_date_end': today + relativedelta(days=-3)}, 20),
+ ({'stock_date_end': today + relativedelta(days=-2)}, 20),
+ ({'stock_date_end': today + relativedelta(days=-1)}, 20),
+ ({'stock_date_end': today}, 20),
+ ({'stock_date_end': datetime.date.max}, 23),
+ ]
+
+ def test_products_by_location():
+ for context, quantity in tests_pbl:
+ with transaction.set_context(context):
+ if not quantity:
+ self.assertEqual(products_by_location(), {})
+ else:
+ self.assertEqual(products_by_location(),
+ {(storage.id, product.id): quantity})
+
+ test_products_by_location()
+ for days, quantities in tests:
+ period, = Period.create([{
+ 'date': today + relativedelta(days=days),
+ 'company': company.id,
+ }])
+ Period.close([period])
+
+ self.assertEqual(period.state, 'closed')
+
+ caches = period.caches
+ for cache in caches:
+ self.assertEqual(cache.product, product)
+ self.assertEqual(cache.internal_quantity,
+ quantities[cache.location.id])
+
+ test_products_by_location()
+
+ # Test check_period_closed
+ moves = Move.create([{
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 10,
+ 'from_location': supplier.id,
+ 'to_location': storage.id,
+ 'planned_date': today,
+ 'effective_date': today,
+ 'company': company.id,
+ 'unit_price': Decimal('1'),
+ 'currency': currency.id,
+ }])
+ Move.do(moves)
+
+ self.assertRaises(Exception, Move.create, [{
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 10,
+ 'from_location': supplier.id,
+ 'to_location': storage.id,
+ 'planned_date': today + relativedelta(days=-5),
+ 'effective_date': today + relativedelta(days=-5),
+ 'company': company.id,
+ 'unit_price': Decimal('1'),
+ 'currency': currency.id,
+ }])
+ self.assertRaises(Exception, Move.create, [{
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 10,
+ 'from_location': supplier.id,
+ 'to_location': storage.id,
+ 'planned_date': today + relativedelta(days=-3),
+ 'effective_date': today + relativedelta(days=-3),
+ 'company': company.id,
+ 'unit_price': Decimal('1'),
+ 'currency': currency.id,
+ }])
+
+ # Test close period check
+ period, = Period.create([{
+ 'date': today,
+ 'company': company.id,
+ }])
+ self.assertRaises(Exception, Period.close, [period])
+
+ period, = Period.create([{
+ 'date': today + relativedelta(days=1),
+ 'company': company.id,
+ }])
+ self.assertRaises(Exception, Period.close, [period])
+
+ @with_transaction()
+ def test_check_origin(self):
+ 'Test Move check_origin'
+ pool = Pool()
+ Uom = pool.get('product.uom')
+ Template = pool.get('product.template')
+ Product = pool.get('product.product')
+ Location = pool.get('stock.location')
+ Move = pool.get('stock.move')
+
+ uom, = Uom.search([('name', '=', 'Unit')])
+ template, = Template.create([{
+ 'name': 'Test Move.check_origin',
+ 'type': 'goods',
+ 'default_uom': uom.id,
+ }])
+ product, = Product.create([{
+ 'template': template.id,
+ }])
+ storage, = Location.search([('code', '=', 'STO')])
+ customer, = Location.search([('code', '=', 'CUS')])
+ company = create_company()
+ with set_company(company):
+ moves = Move.create([{
+ 'product': product.id,
+ 'uom': uom.id,
+ 'quantity': 1,
+ 'from_location': storage.id,
+ 'to_location': customer.id,
+ 'company': company.id,
+ 'unit_price': Decimal(1),
+ 'currency': company.currency.id,
+ }])
+
+ Move.check_origin(moves, set())
+ Move.check_origin(moves, {'supplier'})
+ self.assertRaises(UserWarning, Move.check_origin, moves,
+ {'customer'})
+
+ def test_assign_try(self):
+ 'Test Move assign_try'
+ for quantity, quantities, success, result in [
+ (10, [2], True, {'assigned': [2]}),
+ (5, [10], False, {'assigned': [5], 'draft': [5]}),
+ (0, [3], False, {'draft': [3]}),
+ (6.8, [2.1, 1.7, 1.2, 1.8], True,
+ {'assigned': sorted([2.1, 1.7, 1.2, 1.8])}),
+ ]:
+ self._test_assign_try(quantity, quantities, success, result)
+
+ @with_transaction()
+ def _test_assign_try(self, quantity, quantities, success, result):
+ pool = Pool()
+ Template = pool.get('product.template')
+ Product = pool.get('product.product')
+ Uom = pool.get('product.uom')
+ Location = pool.get('stock.location')
+ Move = pool.get('stock.move')
+
+ uom, = Uom.search([('name', '=', 'Meter')])
+ template = Template(
+ name='Test Move.assign_try',
+ type='goods',
+ default_uom=uom,
+ )
+ template.save()
+ product = Product(template=template.id)
+ product.save()
+
+ supplier, = Location.search([('code', '=', 'SUP')])
+ storage, = Location.search([('code', '=', 'STO')])
+ customer, = Location.search([('code', '=', 'CUS')])
+
+ company = create_company()
+ with set_company(company):
+ move, = Move.create([{
+ 'product': product.id,
+ 'uom': uom.id,
+ 'quantity': quantity,
+ 'from_location': supplier.id,
+ 'to_location': storage.id,
+ 'company': company.id,
+ 'unit_price': Decimal(1),
+ 'currency': company.currency.id,
+ }])
+ Move.do([move])
+
+ moves = Move.create([{
+ 'product': product.id,
+ 'uom': uom.id,
+ 'quantity': qty,
+ 'from_location': storage.id,
+ 'to_location': customer.id,
+ 'company': company.id,
+ 'unit_price': Decimal(1),
+ 'currency': company.currency.id,
+ } for qty in quantities])
+
+ msg = 'quantity: %s, quantities: %s' % (quantity, quantities)
+ self.assertEqual(Move.assign_try(moves), success, msg=msg)
+ moves = Move.search([
+ ('product', '=', product.id),
+ ('from_location', '=', storage.id),
+ ('to_location', '=', customer.id),
+ ('company', '=', company.id),
+ ])
+ states = defaultdict(list)
+ for move in moves:
+ states[move.state].append(move.quantity)
+ for state in states:
+ states[state].sort()
+ self.assertEqual(states, result, msg=msg)
+
+ @with_transaction()
+ def test_assign_try_chained(self):
+ "Test Move assign_try chained"
+ pool = Pool()
+ Template = pool.get('product.template')
+ Product = pool.get('product.product')
+ Uom = pool.get('product.uom')
+ Location = pool.get('stock.location')
+ Move = pool.get('stock.move')
+
+ uom, = Uom.search([('name', '=', 'Meter')])
+ template = Template(
+ name='Test Move.assign_try',
+ type='goods',
+ default_uom=uom,
+ )
+ template.save()
+ product = Product(template=template.id)
+ product.save()
+
+ supplier, = Location.search([('code', '=', 'SUP')])
+ storage, = Location.search([('code', '=', 'STO')])
+ storage2, = Location.copy([storage])
+ storage3, = Location.copy([storage])
+
+ company = create_company()
+ with set_company(company):
+ move, = Move.create([{
+ 'product': product.id,
+ 'uom': uom.id,
+ 'quantity': 1,
+ 'from_location': supplier.id,
+ 'to_location': storage.id,
+ 'company': company.id,
+ 'unit_price': Decimal(1),
+ 'currency': company.currency.id,
+ }])
+ Move.do([move])
+
+ moves = Move.create([{
+ 'product': product.id,
+ 'uom': uom.id,
+ 'quantity': 1,
+ 'from_location': from_.id,
+ 'to_location': to.id,
+ 'company': company.id,
+ 'unit_price': Decimal(1),
+ 'currency': company.currency.id,
+ } for from_, to in [
+ (storage, storage2),
+ (storage2, storage3)]])
+
+ self.assertFalse(Move.assign_try(moves))
+ self.assertEqual([m.state for m in moves], ['assigned', 'draft'])
+
+ @with_transaction()
+ def test_assign_try_skip_to_location(self):
+ "Test Move assign_try skip to_location"
+ pool = Pool()
+ Template = pool.get('product.template')
+ Product = pool.get('product.product')
+ Uom = pool.get('product.uom')
+ Location = pool.get('stock.location')
+ Move = pool.get('stock.move')
+
+ uom, = Uom.search([('name', '=', 'Meter')])
+ template = Template(
+ name='Test Move.assign_try',
+ type='goods',
+ default_uom=uom,
+ )
+ template.save()
+ product = Product(template=template.id)
+ product.save()
+
+ supplier, = Location.search([('code', '=', 'SUP')])
+ storage, = Location.search([('code', '=', 'STO')])
+ child, = Location.copy([storage], default={'parent': storage.id})
+
+ company = create_company()
+ with set_company(company):
+ move, = Move.create([{
+ 'product': product.id,
+ 'uom': uom.id,
+ 'quantity': 1,
+ 'from_location': supplier.id,
+ 'to_location': child.id,
+ 'company': company.id,
+ 'unit_price': Decimal(1),
+ 'currency': company.currency.id,
+ }])
+ Move.do([move])
+
+ move, = Move.create([{
+ 'product': product.id,
+ 'uom': uom.id,
+ 'quantity': 1,
+ 'from_location': storage.id,
+ 'to_location': child.id,
+ 'company': company.id,
+ 'unit_price': Decimal(1),
+ 'currency': company.currency.id,
+ }])
+
+ self.assertFalse(Move.assign_try([move]))
+ self.assertEqual(move.state, 'draft')
+
+ @with_transaction()
+ def test_assign_try_prefer_from_location(self):
+ "Test Move assign_try prefer from location"
+ pool = Pool()
+ Template = pool.get('product.template')
+ Product = pool.get('product.product')
+ Uom = pool.get('product.uom')
+ Location = pool.get('stock.location')
+ Move = pool.get('stock.move')
+
+ uom, = Uom.search([('name', '=', 'Meter')])
+ template = Template(
+ name='Test Move.assign_try',
+ type='goods',
+ default_uom=uom,
+ )
+ template.save()
+ product = Product(template=template.id)
+ product.save()
+
+ supplier, = Location.search([('code', '=', 'SUP')])
+ storage, = Location.search([('code', '=', 'STO')])
+ # Ensure storage2 comes first when ordering locations by name
+ storage2, = Location.copy(
+ [storage], default={'name': "AAA", 'parent': storage.id})
+ customer, = Location.search([('code', '=', 'CUS')])
+
+ company = create_company()
+ with set_company(company):
+ moves = Move.create([{
+ 'product': product.id,
+ 'uom': uom.id,
+ 'quantity': 1,
+ 'from_location': supplier.id,
+ 'to_location': storage.id,
+ 'company': company.id,
+ 'unit_price': Decimal(1),
+ 'currency': company.currency.id,
+ }, {
+ 'product': product.id,
+ 'uom': uom.id,
+ 'quantity': 1,
+ 'from_location': supplier.id,
+ 'to_location': storage2.id,
+ 'company': company.id,
+ 'unit_price': Decimal(1),
+ 'currency': company.currency.id,
+ }])
+ Move.do(moves)
+
+ move, = Move.create([{
+ 'product': product.id,
+ 'uom': uom.id,
+ 'quantity': 1,
+ 'from_location': storage.id,
+ 'to_location': customer.id,
+ 'company': company.id,
+ 'unit_price': Decimal(1),
+ 'currency': company.currency.id,
+ }])
+
+ Move.assign_try([move])
+
+ self.assertEqual(move.state, 'assigned')
+ self.assertEqual(move.from_location, storage)
+
+ @with_transaction()
+ def test_assign_without_moves(self):
+ "Test Move assign_try with empty moves"
+ pool = Pool()
+ Move = pool.get('stock.move')
+
+ self.assertTrue(Move.assign_try([]))
+
+ @with_transaction()
+ def test_assign_try_modified_move(self):
+ "Test Move assign_try with modified move"
+ pool = Pool()
+ Template = pool.get('product.template')
+ Product = pool.get('product.product')
+ Uom = pool.get('product.uom')
+ Location = pool.get('stock.location')
+ Move = pool.get('stock.move')
+
+ uom, = Uom.search([('name', '=', 'Meter')])
+ template = Template(
+ name='Test Move.assign_try',
+ type='goods',
+ default_uom=uom,
+ )
+ template.save()
+ product = Product(template=template.id)
+ product.save()
+
+ supplier, = Location.search([('code', '=', 'SUP')])
+ storage, = Location.search([('code', '=', 'STO')])
+ storage2, = Location.copy([storage])
+ customer, = Location.search([('code', '=', 'CUS')])
+
+ company = create_company()
+ with set_company(company):
+ move, = Move.create([{
+ 'product': product.id,
+ 'uom': uom.id,
+ 'quantity': 1,
+ 'from_location': supplier.id,
+ 'to_location': storage.id,
+ 'company': company.id,
+ 'unit_price': Decimal(1),
+ 'currency': company.currency.id,
+ }])
+ Move.do([move])
+
+ move, = Move.create([{
+ 'product': product.id,
+ 'uom': uom.id,
+ 'quantity': 2,
+ 'from_location': storage2.id,
+ 'to_location': customer.id,
+ 'company': company.id,
+ 'unit_price': Decimal(1),
+ 'currency': company.currency.id,
+ }])
+
+ # Assign from a different location
+ move.from_location = storage
+ self.assertFalse(Move.assign_try([move]))
+
+ move, = Move.search([
+ ('to_location', '=', customer.id),
+ ('state', '=', 'assigned'),
+ ])
+ self.assertEqual(move.from_location, storage)
+ self.assertEqual(move.quantity, 1)
+
+ move, = Move.search([
+ ('to_location', '=', customer.id),
+ ('state', '=', 'draft'),
+ ])
+ # Remaining move has the original location
+ self.assertEqual(move.from_location, storage2)
+ self.assertEqual(move.quantity, 1)
+
+ @with_transaction()
+ def test_products_by_location_assign(self):
+ "Test products by location for assignation"
+ pool = Pool()
+ Template = pool.get('product.template')
+ Product = pool.get('product.product')
+ Uom = pool.get('product.uom')
+ Location = pool.get('stock.location')
+ Move = pool.get('stock.move')
+ today = datetime.date.today()
+
+ unit, = Uom.search([('name', '=', 'Unit')])
+ template = Template(
+ name="Product",
+ type='goods',
+ default_uom=unit,
+ )
+ template.save()
+ product, = Product.create([{'template': template.id}])
+
+ supplier, = Location.search([('code', '=', 'SUP')])
+ storage, = Location.search([('code', '=', 'STO')])
+ customer, = Location.search([('code', '=', 'CUS')])
+
+ company = create_company()
+ with set_company(company):
+ move_supplier, = Move.create([{
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 10,
+ 'from_location': supplier.id,
+ 'to_location': storage.id,
+ 'planned_date': today,
+ 'company': company.id,
+ 'unit_price': Decimal('1'),
+ 'currency': company.currency.id,
+ }])
+ move_customer, = Move.create([{
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 5,
+ 'from_location': storage.id,
+ 'to_location': customer.id,
+ 'planned_date': today + relativedelta(days=1),
+ 'company': company.id,
+ 'unit_price': Decimal('1'),
+ 'currency': company.currency.id,
+ }])
+
+ Move.assign([move_supplier])
+ with Transaction().set_context(
+ stock_date_end=today,
+ stock_assign=True):
+ pbl = Product.products_by_location(
+ [storage.id], grouping_filter=([product.id],))
+ self.assertDictEqual(pbl, {})
+
+ Move.assign([move_customer])
+ with Transaction().set_context(
+ stock_date_end=today,
+ stock_assign=True):
+ pbl = Product.products_by_location(
+ [storage.id], grouping_filter=([product.id],))
+ self.assertDictEqual(pbl, {(storage.id, product.id): -5})
+
+ Move.do([move_supplier])
+ with Transaction().set_context(
+ stock_date_end=today,
+ stock_assign=True):
+ pbl = Product.products_by_location(
+ [storage.id], grouping_filter=([product.id],))
+ self.assertDictEqual(pbl, {(storage.id, product.id): 5})
+
+ with Transaction().set_context(
+ stock_date_end=today + relativedelta(days=1),
+ stock_assign=True):
+ pbl = Product.products_by_location(
+ [storage.id], grouping_filter=([product.id],))
+ self.assertDictEqual(pbl, {(storage.id, product.id): 5})
+
+ with Transaction().set_context(
+ stock_date_start=today,
+ stock_date_end=today,
+ stock_assign=True):
+ pbl = Product.products_by_location(
+ [storage.id], grouping_filter=([product.id],))
+ self.assertDictEqual(pbl, {(storage.id, product.id): 10})
+
+ with Transaction().set_context(
+ stock_date_start=today + relativedelta(days=1),
+ stock_date_end=today + relativedelta(days=1),
+ stock_assign=True):
+ pbl = Product.products_by_location(
+ [storage.id], grouping_filter=([product.id],))
+ self.assertDictEqual(pbl, {(storage.id, product.id): -5})
+
+ @with_transaction()
+ def test_location_inactive_without_move(self):
+ "Test inactivate location without move"
+ pool = Pool()
+ Location = pool.get('stock.location')
+ storage, = Location.search([('code', '=', 'STO')])
+ location, = Location.create([{
+ 'name': "Location",
+ 'parent': storage.id,
+ }])
+
+ location.active = False
+ location.save()
+
+ @with_transaction()
+ def test_location_inactive_with_quantity(self):
+ "Test inactivate location with quantity"
+ pool = Pool()
+ Location = pool.get('stock.location')
+ Move = pool.get('stock.move')
+ Template = pool.get('product.template')
+ Product = pool.get('product.product')
+ Uom = pool.get('product.uom')
+
+ storage, = Location.search([('code', '=', 'STO')])
+ location, = Location.create([{
+ 'name': "Location",
+ 'parent': storage.id,
+ }])
+ unit, = Uom.search([('name', '=', "Unit")])
+ template, = Template.create([{
+ 'name': "Product",
+ 'type': 'goods',
+ 'default_uom': unit.id,
+ }])
+ product, = Product.create([{'template': template.id}])
+
+ company = create_company()
+ with set_company(company):
+
+ moves = Move.create([{
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 1,
+ 'from_location': storage.id,
+ 'to_location': location.id,
+ 'company': company.id,
+ }])
+ Move.do(moves)
+ with self.assertRaises(UserError):
+ location.active = False
+ location.save()
+
+ @with_transaction()
+ def test_location_inactive_with_draft_moves(self):
+ "Test inactivate location with draft moves"
+ pool = Pool()
+ Location = pool.get('stock.location')
+ Move = pool.get('stock.move')
+ Template = pool.get('product.template')
+ Product = pool.get('product.product')
+ Uom = pool.get('product.uom')
+
+ storage, = Location.search([('code', '=', 'STO')])
+ location, = Location.create([{
+ 'name': "Location",
+ 'parent': storage.id,
+ }])
+ unit, = Uom.search([('name', '=', "Unit")])
+ template, = Template.create([{
+ 'name': "Product",
+ 'type': 'goods',
+ 'default_uom': unit.id,
+ }])
+ product, = Product.create([{'template': template.id}])
+
+ company = create_company()
+ with set_company(company):
+ Move.create([{
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 1,
+ 'from_location': storage.id,
+ 'to_location': location.id,
+ 'company': company.id,
+ }, {
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 1,
+ 'from_location': location.id,
+ 'to_location': storage.id,
+ 'company': company.id,
+ }])
+ with self.assertRaises(UserError):
+ location.active = False
+ location.save()
+
+ @with_transaction()
+ def test_inactive_product_with_stock(self):
+ "Test inactivate product with stock"
+ pool = Pool()
+ Location = pool.get('stock.location')
+ Move = pool.get('stock.move')
+ Template = pool.get('product.template')
+ Product = pool.get('product.product')
+ Uom = pool.get('product.uom')
+
+ storage, = Location.search([('code', '=', 'STO')])
+ supplier, = Location.search([('code', '=', 'SUP')])
+ unit, = Uom.search([('name', '=', "Unit")])
+ template, = Template.create([{
+ 'name': "Product",
+ 'type': 'goods',
+ 'default_uom': unit.id,
+ }])
+ product, = Product.create([{'template': template.id}])
+
+ company = create_company()
+ with set_company(company):
+ Move.create([{
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 1,
+ 'from_location': supplier.id,
+ 'to_location': storage.id,
+ 'unit_price': Decimal('5'),
+ 'company': company.id,
+ }])
+ with self.assertRaises(UserWarning):
+ product.active = False
+ product.save()
+
+ Move.create([{
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 1,
+ 'from_location': storage.id,
+ 'to_location': supplier.id,
+ 'unit_price': Decimal('5'),
+ 'company': company.id,
+ }])
+ product.active = False
+ product.save()
+
+
+del ModuleTestCase
diff -r 80d6b2eb115e -r 2a924f6752c3 tests/test_scenario.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test_scenario.py Sat Apr 16 18:30:19 2022 +0200
@@ -0,0 +1,22 @@
+# This file is part of Tryton. The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+
+import doctest
+import glob
+import os
+
+from trytond.tests.test_tryton import doctest_checker, doctest_teardown
+
+
+def load_tests(loader, tests, pattern):
+ cwd = os.getcwd()
+ try:
+ os.chdir(os.path.dirname(__file__))
+ for scenario in glob.glob('*.rst'):
+ tests.addTests(doctest.DocFileSuite(
+ scenario, tearDown=doctest_teardown, encoding='utf-8',
+ checker=doctest_checker,
+ optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
+ finally:
+ os.chdir(cwd)
+ return tests
diff -r 80d6b2eb115e -r 2a924f6752c3 tests/test_stock.py
--- a/tests/test_stock.py Tue Apr 12 10:35:40 2022 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1607 +0,0 @@
-# This file is part of Tryton. The COPYRIGHT file at the top level of
-# this repository contains the full copyright notices and license terms.
-import datetime
-import doctest
-import unittest
-from collections import defaultdict
-from decimal import Decimal
-from functools import partial
-
-from dateutil.relativedelta import relativedelta
-
-import trytond.tests.test_tryton
-from trytond.exceptions import UserError, UserWarning
-from trytond.modules.company.tests import (
- CompanyTestMixin, PartyCompanyCheckEraseMixin, create_company, set_company)
-from trytond.pool import Pool
-from trytond.tests.test_tryton import (
- ModuleTestCase, doctest_checker, doctest_teardown, with_transaction)
-from trytond.transaction import Transaction
-
-
-class StockTestCase(
- PartyCompanyCheckEraseMixin, CompanyTestMixin, ModuleTestCase):
- 'Test Stock module'
- module = 'stock'
- longMessage = True
-
- @with_transaction()
- def test_move_internal_quantity(self):
- 'Test Move.internal_quantity'
- pool = Pool()
- Uom = pool.get('product.uom')
- Template = pool.get('product.template')
- Product = pool.get('product.product')
- Location = pool.get('stock.location')
- Move = pool.get('stock.move')
-
- kg, = Uom.search([('name', '=', 'Kilogram')])
- g, = Uom.search([('name', '=', 'Gram')])
- template, = Template.create([{
- 'name': 'Test Move.internal_quantity',
- 'type': 'goods',
- 'default_uom': kg.id,
- }])
- product, = Product.create([{
- 'template': template.id,
- }])
- supplier, = Location.search([('code', '=', 'SUP')])
- storage, = Location.search([('code', '=', 'STO')])
- company = create_company()
- currency = company.currency
- with set_company(company):
- tests = [
- (kg, 10, 10, 0),
- (g, 100, 0.1, 1),
- (g, 1, 0, 0), # rounded
- (kg, 35.23, 35.23, 2), # check infinite loop
- ]
- for uom, quantity, internal_quantity, ndigits in tests:
- move, = Move.create([{
- 'product': product.id,
- 'uom': uom.id,
- 'quantity': quantity,
- 'from_location': supplier.id,
- 'to_location': storage.id,
- 'company': company.id,
- 'unit_price': Decimal('1'),
- 'currency': currency.id,
- }])
- self.assertEqual(round(move.internal_quantity, ndigits),
- internal_quantity)
-
- for uom, quantity, internal_quantity, ndigits in tests:
- Move.write([move], {
- 'uom': uom.id,
- 'quantity': quantity,
- })
- self.assertEqual(round(move.internal_quantity, ndigits),
- internal_quantity)
-
- @with_transaction()
- def test_products_by_location(self):
- 'Test products_by_location'
- pool = Pool()
- Uom = pool.get('product.uom')
- Template = pool.get('product.template')
- Product = pool.get('product.product')
- Location = pool.get('stock.location')
- Move = pool.get('stock.move')
- Period = pool.get('stock.period')
- transaction = Transaction()
-
- kg, = Uom.search([('name', '=', 'Kilogram')])
- g, = Uom.search([('name', '=', 'Gram')])
- template, = Template.create([{
- 'name': 'Test products_by_location',
- 'type': 'goods',
- 'default_uom': kg.id,
- }])
- product, = Product.create([{
- 'template': template.id,
- }])
- supplier, = Location.search([('code', '=', 'SUP')])
- customer, = Location.search([('code', '=', 'CUS')])
- storage, = Location.search([('code', '=', 'STO')])
- storage_empty, = Location.copy([storage])
- company = create_company()
- currency = company.currency
- with set_company(company):
- today = datetime.date.today()
-
- moves = Move.create([{
- 'product': product.id,
- 'uom': kg.id,
- 'quantity': 5,
- 'from_location': supplier.id,
- 'to_location': storage.id,
- 'planned_date': today + relativedelta(days=-5),
- 'effective_date': today + relativedelta(days=-5),
- 'company': company.id,
- 'unit_price': Decimal('1'),
- 'currency': currency.id,
- }, {
- 'product': product.id,
- 'uom': kg.id,
- 'quantity': 1,
- 'from_location': supplier.id,
- 'to_location': storage.id,
- 'planned_date': today + relativedelta(days=-4),
- 'company': company.id,
- 'unit_price': Decimal('1'),
- 'currency': currency.id,
- }, {
- 'product': product.id,
- 'uom': kg.id,
- 'quantity': 1,
- 'from_location': storage.id,
- 'to_location': customer.id,
- 'planned_date': today,
- 'effective_date': today,
- 'company': company.id,
- 'unit_price': Decimal('1'),
- 'currency': currency.id,
- }, {
- 'product': product.id,
- 'uom': kg.id,
- 'quantity': 1,
- 'from_location': storage.id,
- 'to_location': customer.id,
- 'planned_date': today,
- 'company': company.id,
- 'unit_price': Decimal('1'),
- 'currency': currency.id,
- }, {
- 'product': product.id,
- 'uom': kg.id,
- 'quantity': 2,
- 'from_location': storage.id,
- 'to_location': customer.id,
- 'planned_date': today + relativedelta(days=5),
- 'company': company.id,
- 'unit_price': Decimal('1'),
- 'currency': currency.id,
- }, {
- 'product': product.id,
- 'uom': kg.id,
- 'quantity': 5,
- 'from_location': supplier.id,
- 'to_location': storage.id,
- 'planned_date': today + relativedelta(days=7),
- 'company': company.id,
- 'unit_price': Decimal('1'),
- 'currency': currency.id,
- }])
- Move.do([moves[0], moves[2]])
-
- products_by_location = partial(Product.products_by_location,
- [storage.id], grouping_filter=([product.id],))
-
- tests = [
- ({'stock_date_end': today + relativedelta(days=-6),
- }, 0),
- ({'stock_date_end': today + relativedelta(days=-5),
- }, 5),
- ({'stock_date_end': today + relativedelta(days=-4),
- }, 5),
- ({'stock_date_end': today + relativedelta(days=-3),
- }, 5),
- ({'stock_date_end': today,
- }, 4),
- ({'stock_date_end': today + relativedelta(days=1),
- }, 3),
- ({'stock_date_end': today + relativedelta(days=5),
- }, 1),
- ({'stock_date_end': today + relativedelta(days=6),
- }, 1),
- ({'stock_date_end': today + relativedelta(days=7),
- }, 6),
- ({'stock_date_end': today + relativedelta(days=8),
- }, 6),
- ({'stock_date_end': False,
- }, 6),
- ({'stock_date_end': today + relativedelta(days=-6),
- 'forecast': True,
- }, 0),
- ({'stock_date_end': today + relativedelta(days=-5),
- 'forecast': True,
- }, 5),
- ({'stock_date_end': today + relativedelta(days=-4),
- 'forecast': True,
- }, 5),
- ({'stock_date_end': today + relativedelta(days=-3),
- 'forecast': True,
- }, 5),
- ({'stock_date_end': today,
- 'forecast': True,
- }, 3),
- ({'stock_date_end': today + relativedelta(days=1),
- 'forecast': True,
- }, 3),
- ({'stock_date_end': today + relativedelta(days=5),
- 'forecast': True,
- }, 1),
- ({'stock_date_end': today + relativedelta(days=6),
- 'forecast': True,
- }, 1),
- ({'stock_date_end': today + relativedelta(days=7),
- 'forecast': True,
- }, 6),
- ({'stock_date_end': False,
- 'forecast': True,
- }, 6),
- ]
- today_quantity = 4
-
- def tests_product_quantity(context, quantity):
- product_reloaded = Product(product.id)
- if (not context.get('stock_date_end')
- or context['stock_date_end'] > today):
- self.assertEqual(
- product_reloaded.forecast_quantity, quantity,
- msg='context %r' % context)
- self.assertEqual(
- product_reloaded.quantity, today_quantity,
- msg='context %r' % context)
- elif context.get('forecast'):
- self.assertEqual(
- product_reloaded.forecast_quantity, quantity,
- msg='context %r' % context)
- elif context.get('stock_date_end') == today:
- self.assertEqual(product_reloaded.quantity, quantity,
- msg='context %r' % context)
- else:
- self.assertEqual(
- product_reloaded.forecast_quantity, quantity,
- msg='context %r' % context)
- self.assertEqual(product_reloaded.quantity, quantity,
- msg='context %r' % context)
-
- def tests_product_search_quantity(context, quantity):
- if (not context.get('stock_date_end')
- or context['stock_date_end'] > today
- or context.get('forecast')):
- fname = 'forecast_quantity'
- else:
- fname = 'quantity'
- found_products = Product.search([
- (fname, '=', quantity),
- ])
- self.assertIn(product, found_products)
-
- found_products = Product.search([
- (fname, '!=', quantity),
- ])
- self.assertNotIn(product, found_products)
-
- found_products = Product.search([
- (fname, 'in', (quantity, quantity + 1)),
- ])
- self.assertIn(product, found_products)
-
- found_products = Product.search([
- (fname, 'not in', (quantity, quantity + 1)),
- ])
- self.assertNotIn(product, found_products)
-
- found_products = Product.search([
- (fname, '<', quantity),
- ])
- self.assertNotIn(product, found_products)
- found_products = Product.search([
- (fname, '<', quantity + 1),
- ])
- self.assertIn(product, found_products)
-
- found_products = Product.search([
- (fname, '>', quantity),
- ])
- self.assertNotIn(product, found_products)
- found_products = Product.search([
- (fname, '>', quantity - 1),
- ])
- self.assertIn(product, found_products)
-
- found_products = Product.search([
- (fname, '>=', quantity),
- ])
- self.assertIn(product, found_products)
-
- found_products = Product.search([
- (fname, '<=', quantity),
- ])
- self.assertIn(product, found_products)
-
- def test_products_by_location():
- for context, quantity in tests:
- with transaction.set_context(context):
- if not quantity:
- self.assertEqual(products_by_location(), {})
- else:
- self.assertEqual(products_by_location(),
- {(storage.id, product.id): quantity})
- with transaction.set_context(
- locations=[storage.id]):
- tests_product_quantity(context, quantity)
- tests_product_search_quantity(
- context, quantity)
- with transaction.set_context(
- locations=[storage.id, storage_empty.id]):
- tests_product_quantity(context, quantity)
- tests_product_search_quantity(
- context, quantity)
-
- test_products_by_location()
-
- periods = [
- today + relativedelta(days=-6),
- today + relativedelta(days=-5),
- today + relativedelta(days=-4),
- today + relativedelta(days=-3),
- today + relativedelta(days=-2),
- ]
-
- moves = Move.create([{
- 'product': product.id,
- 'uom': g.id,
- 'quantity': 1,
- 'from_location': supplier.id,
- 'to_location': storage.id,
- 'planned_date': today + relativedelta(days=-5),
- 'effective_date': (today
- + relativedelta(days=-5)),
- 'company': company.id,
- 'unit_price': Decimal('1'),
- 'currency': currency.id,
- }])
- Move.do(moves)
- # Nothing should change when adding a small quantity
- test_products_by_location()
-
- for period_date in periods:
- period, = Period.create([{
- 'date': period_date,
- 'company': company.id,
- }])
- Period.close([period])
- test_products_by_location()
-
- @with_transaction()
- def test_products_by_location_with_childs(self):
- 'Test products_by_location with_childs and stock_skip_warehouse'
- pool = Pool()
- Uom = pool.get('product.uom')
- Template = pool.get('product.template')
- Product = pool.get('product.product')
- Location = pool.get('stock.location')
- Move = pool.get('stock.move')
-
- unit, = Uom.search([('name', '=', 'Unit')])
- template, = Template.create([{
- 'name': 'Test products_by_location',
- 'type': 'goods',
- 'default_uom': unit.id,
- }])
- product, = Product.create([{
- 'template': template.id,
- }])
-
- lost_found, = Location.search([('type', '=', 'lost_found')])
- warehouse, = Location.search([('type', '=', 'warehouse')])
- storage, = Location.search([('code', '=', 'STO')])
- input_, = Location.search([('code', '=', 'IN')])
- storage1, = Location.create([{
- 'name': 'Storage 1',
- 'type': 'view',
- 'parent': storage.id,
- }])
- storage2, = Location.create([{
- 'name': 'Storage 1.1',
- 'type': 'view',
- 'parent': storage1.id,
- }])
- storage3, = Location.create([{
- 'name': 'Storage 2',
- 'type': 'view',
- 'parent': storage.id,
- }])
- company = create_company()
- with set_company(company):
- today = datetime.date.today()
-
- moves = Move.create([{
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 1,
- 'from_location': lost_found.id,
- 'to_location': storage.id,
- 'planned_date': today,
- 'effective_date': today,
- 'company': company.id,
- }, {
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 1,
- 'from_location': input_.id,
- 'to_location': storage.id,
- 'planned_date': today,
- 'effective_date': today,
- 'company': company.id,
- }])
- Move.do(moves)
-
- products_by_location = Product.products_by_location(
- [warehouse.id],
- grouping_filter=([product.id],),
- with_childs=True)
- self.assertEqual(products_by_location[(warehouse.id, product.id)],
- 1)
- products_by_location = Product.products_by_location(
- [warehouse.id, storage.id],
- grouping_filter=([product.id],),
- with_childs=True)
- self.assertEqual(
- products_by_location[(warehouse.id, product.id)], 1)
- self.assertEqual(products_by_location[(storage.id, product.id)], 2)
-
- with Transaction().set_context(locations=[warehouse.id]):
- found_products = Product.search([
- ('quantity', '=', 1),
- ])
- self.assertListEqual([product], found_products)
-
- with Transaction().set_context(stock_skip_warehouse=True):
- products_by_location = Product.products_by_location(
- [warehouse.id],
- grouping_filter=([product.id],),
- with_childs=True)
- products_by_location_all = Product.products_by_location(
- [warehouse.id], with_childs=True)
- self.assertEqual(
- products_by_location[(warehouse.id, product.id)], 2)
- self.assertEqual(
- products_by_location_all[(warehouse.id, product.id)], 2)
-
- with Transaction().set_context(locations=[warehouse.id]):
- found_products = Product.search([
- ('quantity', '=', 2),
- ])
- self.assertListEqual([product], found_products)
-
- @with_transaction()
- def test_products_by_location_flat_childs(self, period_closed=False):
- "Test products_by_location on flat_childs"
- pool = Pool()
- Uom = pool.get('product.uom')
- Template = pool.get('product.template')
- Product = pool.get('product.product')
- Location = pool.get('stock.location')
- Move = pool.get('stock.move')
- Date = pool.get('ir.date')
- Period = pool.get('stock.period')
-
- unit, = Uom.search([('name', '=', 'Unit')])
- template, = Template.create([{
- 'name': "Product",
- 'type': 'goods',
- 'default_uom': unit.id,
- }])
- product, = Product.create([{
- 'template': template.id,
- }])
-
- lost_found, = Location.search([('type', '=', 'lost_found')])
- storage, = Location.search([('code', '=', 'STO')])
- storage.flat_childs = True
- storage.save()
- storage1, = Location.create([{
- 'name': 'Storage 1',
- 'type': 'storage',
- 'parent': storage.id,
- }])
- storage2, = Location.create([{
- 'name': 'Storage 2',
- 'type': 'storage',
- 'parent': storage.id,
- }])
-
- company = create_company()
- with set_company(company):
- date = Date.today() - relativedelta(days=1)
-
- moves = Move.create([{
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 1,
- 'from_location': lost_found.id,
- 'to_location': storage.id,
- 'planned_date': date,
- 'effective_date': date,
- 'company': company.id,
- }, {
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 1,
- 'from_location': lost_found.id,
- 'to_location': storage1.id,
- 'planned_date': date,
- 'effective_date': date,
- 'company': company.id,
- }, {
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 1,
- 'from_location': storage1.id,
- 'to_location': storage2.id,
- 'planned_date': date,
- 'effective_date': date,
- 'company': company.id,
- }])
- Move.do(moves)
-
- if period_closed:
- period, = Period.create([{
- 'date': date,
- 'company': company.id,
- }])
- Period.close([period])
-
- # Test flat location
- products_by_location = Product.products_by_location(
- [storage.id],
- grouping_filter=([product.id],),
- with_childs=True)
- self.assertEqual(
- products_by_location[(storage.id, product.id)], 2)
-
- # Test mixed flat and nested location
- products_by_location = Product.products_by_location(
- [storage.parent.id, storage.id, storage1.id, storage2.id],
- grouping_filter=([product.id],),
- with_childs=True)
- self.assertEqual(
- products_by_location[(storage.parent.id, product.id)], 2)
- self.assertEqual(
- products_by_location[(storage.id, product.id)], 2)
- self.assertEqual(
- products_by_location[(storage1.id, product.id)], 0)
- self.assertEqual(
- products_by_location[(storage2.id, product.id)], 1)
-
- # Test non flat
- products_by_location = Product.products_by_location(
- [lost_found.id],
- grouping_filter=([product.id],),
- with_childs=True)
- self.assertEqual(
- products_by_location[(lost_found.id, product.id)], -2)
-
- def test_products_by_location_flat_childs_period_closed(self):
- "Test products_by_location on flat_childs with period closed"
- self.test_products_by_location_flat_childs(period_closed=True)
-
- @with_transaction()
- def test_products_by_location_2nd_level_flat_childs(self):
- "Test products_by_location on 2nd level flat_childs"
- pool = Pool()
- Uom = pool.get('product.uom')
- Template = pool.get('product.template')
- Product = pool.get('product.product')
- Location = pool.get('stock.location')
- Move = pool.get('stock.move')
- Date = pool.get('ir.date')
-
- unit, = Uom.search([('name', '=', 'Unit')])
- template, = Template.create([{
- 'name': "Product",
- 'type': 'goods',
- 'default_uom': unit.id,
- }])
- product, = Product.create([{
- 'template': template.id,
- }])
-
- supplier, = Location.search([('code', '=', 'SUP')])
- storage, = Location.search([('code', '=', 'STO')])
- storage1, = Location.create([{
- 'name': 'Storage 1',
- 'type': 'storage',
- 'flat_childs': True,
- 'parent': storage.id,
- }])
- storage2, = Location.create([{
- 'name': 'Storage 2',
- 'type': 'storage',
- 'parent': storage1.id,
- }])
-
- company = create_company()
- with set_company(company):
- date = Date.today() - relativedelta(days=1)
-
- moves = Move.create([{
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 80,
- 'from_location': supplier.id,
- 'to_location': storage.id,
- 'effective_date': date,
- 'company': company.id,
- 'unit_price': 10.0
- }, {
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 60,
- 'from_location': storage.id,
- 'to_location': storage2.id,
- 'effective_date': date,
- 'company': company.id,
- }])
- Move.do(moves)
-
- # Test 2nd level location
- products_by_location = Product.products_by_location(
- [storage.id],
- grouping_filter=([product.id],),
- with_childs=True)
- self.assertEqual(
- products_by_location[(storage.id, product.id)], 80)
-
- # Test 1st level and 2nd level nested locations
- products_by_location = Product.products_by_location(
- [storage.id, storage1.id],
- grouping_filter=([product.id],),
- with_childs=True)
- self.assertEqual(
- products_by_location[(storage.id, product.id)], 80)
- self.assertEqual(
- products_by_location[(storage1.id, product.id)], 60)
-
- # Test mixed flat and 2nd level nested locations
- products_by_location = Product.products_by_location(
- [storage.id, storage2.id],
- grouping_filter=([product.id],),
- with_childs=True)
- self.assertEqual(
- products_by_location[(storage.id, product.id)], 80)
- self.assertEqual(
- products_by_location[(storage2.id, product.id)], 60)
-
- @with_transaction()
- def test_templates_by_location(self, period_closed=False):
- "Test products_by_location grouped by template"
- pool = Pool()
- Uom = pool.get('product.uom')
- Template = pool.get('product.template')
- Product = pool.get('product.product')
- Location = pool.get('stock.location')
- Move = pool.get('stock.move')
- Period = pool.get('stock.period')
- Date = pool.get('ir.date')
-
- unit, = Uom.search([('name', '=', 'Unit')])
- template, = Template.create([{
- 'name': 'Template',
- 'type': 'goods',
- 'default_uom': unit.id,
- }])
- product1, product2 = Product.create([{
- 'template': template.id,
- }] * 2)
-
- lost_found, = Location.search([('type', '=', 'lost_found')])
- storage, = Location.search([('code', '=', 'STO')])
- input_, = Location.search([('code', '=', 'IN')])
- company = create_company()
- with set_company(company):
- date = Date.today() - relativedelta(days=1)
-
- moves = Move.create([{
- 'product': product1.id,
- 'uom': unit.id,
- 'quantity': 2,
- 'from_location': lost_found.id,
- 'to_location': storage.id,
- 'planned_date': date,
- 'effective_date': date,
- 'company': company.id,
- }, {
- 'product': product2.id,
- 'uom': unit.id,
- 'quantity': 3,
- 'from_location': input_.id,
- 'to_location': storage.id,
- 'planned_date': date,
- 'effective_date': date,
- 'company': company.id,
- }])
- Move.do(moves)
-
- if period_closed:
- period, = Period.create([{
- 'date': date,
- 'company': company.id,
- }])
- Period.close([period])
-
- templates_by_location = Product.products_by_location(
- [storage.id],
- grouping=('product.template',),
- grouping_filter=([template.id],))
-
- self.assertDictEqual(templates_by_location, {
- (storage.id, template.id): 5,
- })
-
- def test_templates_by_location_period_closed(self):
- "Test products_by_location grouped by template with period closed"
- self.test_templates_by_location(period_closed=True)
-
- @with_transaction()
- def test_period(self):
- 'Test period'
- pool = Pool()
- Uom = pool.get('product.uom')
- Template = pool.get('product.template')
- Product = pool.get('product.product')
- Location = pool.get('stock.location')
- Move = pool.get('stock.move')
- Period = pool.get('stock.period')
- transaction = Transaction()
-
- unit, = Uom.search([('name', '=', 'Unit')])
- template, = Template.create([{
- 'name': 'Test period',
- 'type': 'goods',
- 'default_uom': unit.id,
- }])
- product, = Product.create([{
- 'template': template.id,
- }])
- supplier, = Location.search([('code', '=', 'SUP')])
- customer, = Location.search([('code', '=', 'CUS')])
- storage, = Location.search([('code', '=', 'STO')])
- company = create_company()
- currency = company.currency
- with set_company(company):
- today = datetime.date.today()
-
- moves = Move.create([{
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 10,
- 'from_location': supplier.id,
- 'to_location': storage.id,
- 'planned_date': today + relativedelta(days=-5),
- 'effective_date': today + relativedelta(days=-5),
- 'company': company.id,
- 'unit_price': Decimal('1'),
- 'currency': currency.id,
- }, {
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 15,
- 'from_location': supplier.id,
- 'to_location': storage.id,
- 'planned_date': today + relativedelta(days=-4),
- 'effective_date': today + relativedelta(days=-4),
- 'company': company.id,
- 'unit_price': Decimal('1'),
- 'currency': currency.id,
- }, {
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 5,
- 'from_location': storage.id,
- 'to_location': customer.id,
- 'planned_date': today + relativedelta(days=-3),
- 'effective_date': today + relativedelta(days=-3),
- 'company': company.id,
- 'unit_price': Decimal('1'),
- 'currency': currency.id,
- }])
- Move.do(moves)
- Move.create([{
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 3,
- 'from_location': supplier.id,
- 'to_location': storage.id,
- 'planned_date': None,
- 'effective_date': None,
- 'company': company.id,
- 'unit_price': Decimal('1'),
- 'currency': currency.id,
- }])
-
- tests = [
- (-5, {
- supplier.id: -10,
- storage.id: 10,
- }),
- (-3, {
- supplier.id: -25,
- storage.id: 20,
- customer.id: 5,
- })
- ]
-
- products_by_location = partial(Product.products_by_location,
- [storage.id], grouping_filter=([product.id],))
-
- tests_pbl = [
- ({'stock_date_end': today + relativedelta(days=-6)}, 0),
- ({'stock_date_end': today + relativedelta(days=-5)}, 10),
- ({'stock_date_end': today + relativedelta(days=-4)}, 25),
- ({'stock_date_end': today + relativedelta(days=-3)}, 20),
- ({'stock_date_end': today + relativedelta(days=-2)}, 20),
- ({'stock_date_end': today + relativedelta(days=-1)}, 20),
- ({'stock_date_end': today}, 20),
- ({'stock_date_end': datetime.date.max}, 23),
- ]
-
- def test_products_by_location():
- for context, quantity in tests_pbl:
- with transaction.set_context(context):
- if not quantity:
- self.assertEqual(products_by_location(), {})
- else:
- self.assertEqual(products_by_location(),
- {(storage.id, product.id): quantity})
-
- test_products_by_location()
- for days, quantities in tests:
- period, = Period.create([{
- 'date': today + relativedelta(days=days),
- 'company': company.id,
- }])
- Period.close([period])
-
- self.assertEqual(period.state, 'closed')
-
- caches = period.caches
- for cache in caches:
- self.assertEqual(cache.product, product)
- self.assertEqual(cache.internal_quantity,
- quantities[cache.location.id])
-
- test_products_by_location()
-
- # Test check_period_closed
- moves = Move.create([{
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 10,
- 'from_location': supplier.id,
- 'to_location': storage.id,
- 'planned_date': today,
- 'effective_date': today,
- 'company': company.id,
- 'unit_price': Decimal('1'),
- 'currency': currency.id,
- }])
- Move.do(moves)
-
- self.assertRaises(Exception, Move.create, [{
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 10,
- 'from_location': supplier.id,
- 'to_location': storage.id,
- 'planned_date': today + relativedelta(days=-5),
- 'effective_date': today + relativedelta(days=-5),
- 'company': company.id,
- 'unit_price': Decimal('1'),
- 'currency': currency.id,
- }])
- self.assertRaises(Exception, Move.create, [{
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 10,
- 'from_location': supplier.id,
- 'to_location': storage.id,
- 'planned_date': today + relativedelta(days=-3),
- 'effective_date': today + relativedelta(days=-3),
- 'company': company.id,
- 'unit_price': Decimal('1'),
- 'currency': currency.id,
- }])
-
- # Test close period check
- period, = Period.create([{
- 'date': today,
- 'company': company.id,
- }])
- self.assertRaises(Exception, Period.close, [period])
-
- period, = Period.create([{
- 'date': today + relativedelta(days=1),
- 'company': company.id,
- }])
- self.assertRaises(Exception, Period.close, [period])
-
- @with_transaction()
- def test_check_origin(self):
- 'Test Move check_origin'
- pool = Pool()
- Uom = pool.get('product.uom')
- Template = pool.get('product.template')
- Product = pool.get('product.product')
- Location = pool.get('stock.location')
- Move = pool.get('stock.move')
-
- uom, = Uom.search([('name', '=', 'Unit')])
- template, = Template.create([{
- 'name': 'Test Move.check_origin',
- 'type': 'goods',
- 'default_uom': uom.id,
- }])
- product, = Product.create([{
- 'template': template.id,
- }])
- storage, = Location.search([('code', '=', 'STO')])
- customer, = Location.search([('code', '=', 'CUS')])
- company = create_company()
- with set_company(company):
- moves = Move.create([{
- 'product': product.id,
- 'uom': uom.id,
- 'quantity': 1,
- 'from_location': storage.id,
- 'to_location': customer.id,
- 'company': company.id,
- 'unit_price': Decimal(1),
- 'currency': company.currency.id,
- }])
-
- Move.check_origin(moves, set())
- Move.check_origin(moves, {'supplier'})
- self.assertRaises(UserWarning, Move.check_origin, moves,
- {'customer'})
-
- def test_assign_try(self):
- 'Test Move assign_try'
- for quantity, quantities, success, result in [
- (10, [2], True, {'assigned': [2]}),
- (5, [10], False, {'assigned': [5], 'draft': [5]}),
- (0, [3], False, {'draft': [3]}),
- (6.8, [2.1, 1.7, 1.2, 1.8], True,
- {'assigned': sorted([2.1, 1.7, 1.2, 1.8])}),
- ]:
- self._test_assign_try(quantity, quantities, success, result)
-
- @with_transaction()
- def _test_assign_try(self, quantity, quantities, success, result):
- pool = Pool()
- Template = pool.get('product.template')
- Product = pool.get('product.product')
- Uom = pool.get('product.uom')
- Location = pool.get('stock.location')
- Move = pool.get('stock.move')
-
- uom, = Uom.search([('name', '=', 'Meter')])
- template = Template(
- name='Test Move.assign_try',
- type='goods',
- default_uom=uom,
- )
- template.save()
- product = Product(template=template.id)
- product.save()
-
- supplier, = Location.search([('code', '=', 'SUP')])
- storage, = Location.search([('code', '=', 'STO')])
- customer, = Location.search([('code', '=', 'CUS')])
-
- company = create_company()
- with set_company(company):
- move, = Move.create([{
- 'product': product.id,
- 'uom': uom.id,
- 'quantity': quantity,
- 'from_location': supplier.id,
- 'to_location': storage.id,
- 'company': company.id,
- 'unit_price': Decimal(1),
- 'currency': company.currency.id,
- }])
- Move.do([move])
-
- moves = Move.create([{
- 'product': product.id,
- 'uom': uom.id,
- 'quantity': qty,
- 'from_location': storage.id,
- 'to_location': customer.id,
- 'company': company.id,
- 'unit_price': Decimal(1),
- 'currency': company.currency.id,
- } for qty in quantities])
-
- msg = 'quantity: %s, quantities: %s' % (quantity, quantities)
- self.assertEqual(Move.assign_try(moves), success, msg=msg)
- moves = Move.search([
- ('product', '=', product.id),
- ('from_location', '=', storage.id),
- ('to_location', '=', customer.id),
- ('company', '=', company.id),
- ])
- states = defaultdict(list)
- for move in moves:
- states[move.state].append(move.quantity)
- for state in states:
- states[state].sort()
- self.assertEqual(states, result, msg=msg)
-
- @with_transaction()
- def test_assign_try_chained(self):
- "Test Move assign_try chained"
- pool = Pool()
- Template = pool.get('product.template')
- Product = pool.get('product.product')
- Uom = pool.get('product.uom')
- Location = pool.get('stock.location')
- Move = pool.get('stock.move')
-
- uom, = Uom.search([('name', '=', 'Meter')])
- template = Template(
- name='Test Move.assign_try',
- type='goods',
- default_uom=uom,
- )
- template.save()
- product = Product(template=template.id)
- product.save()
-
- supplier, = Location.search([('code', '=', 'SUP')])
- storage, = Location.search([('code', '=', 'STO')])
- storage2, = Location.copy([storage])
- storage3, = Location.copy([storage])
-
- company = create_company()
- with set_company(company):
- move, = Move.create([{
- 'product': product.id,
- 'uom': uom.id,
- 'quantity': 1,
- 'from_location': supplier.id,
- 'to_location': storage.id,
- 'company': company.id,
- 'unit_price': Decimal(1),
- 'currency': company.currency.id,
- }])
- Move.do([move])
-
- moves = Move.create([{
- 'product': product.id,
- 'uom': uom.id,
- 'quantity': 1,
- 'from_location': from_.id,
- 'to_location': to.id,
- 'company': company.id,
- 'unit_price': Decimal(1),
- 'currency': company.currency.id,
- } for from_, to in [
- (storage, storage2),
- (storage2, storage3)]])
-
- self.assertFalse(Move.assign_try(moves))
- self.assertEqual([m.state for m in moves], ['assigned', 'draft'])
-
- @with_transaction()
- def test_assign_try_skip_to_location(self):
- "Test Move assign_try skip to_location"
- pool = Pool()
- Template = pool.get('product.template')
- Product = pool.get('product.product')
- Uom = pool.get('product.uom')
- Location = pool.get('stock.location')
- Move = pool.get('stock.move')
-
- uom, = Uom.search([('name', '=', 'Meter')])
- template = Template(
- name='Test Move.assign_try',
- type='goods',
- default_uom=uom,
- )
- template.save()
- product = Product(template=template.id)
- product.save()
-
- supplier, = Location.search([('code', '=', 'SUP')])
- storage, = Location.search([('code', '=', 'STO')])
- child, = Location.copy([storage], default={'parent': storage.id})
-
- company = create_company()
- with set_company(company):
- move, = Move.create([{
- 'product': product.id,
- 'uom': uom.id,
- 'quantity': 1,
- 'from_location': supplier.id,
- 'to_location': child.id,
- 'company': company.id,
- 'unit_price': Decimal(1),
- 'currency': company.currency.id,
- }])
- Move.do([move])
-
- move, = Move.create([{
- 'product': product.id,
- 'uom': uom.id,
- 'quantity': 1,
- 'from_location': storage.id,
- 'to_location': child.id,
- 'company': company.id,
- 'unit_price': Decimal(1),
- 'currency': company.currency.id,
- }])
-
- self.assertFalse(Move.assign_try([move]))
- self.assertEqual(move.state, 'draft')
-
- @with_transaction()
- def test_assign_try_prefer_from_location(self):
- "Test Move assign_try prefer from location"
- pool = Pool()
- Template = pool.get('product.template')
- Product = pool.get('product.product')
- Uom = pool.get('product.uom')
- Location = pool.get('stock.location')
- Move = pool.get('stock.move')
-
- uom, = Uom.search([('name', '=', 'Meter')])
- template = Template(
- name='Test Move.assign_try',
- type='goods',
- default_uom=uom,
- )
- template.save()
- product = Product(template=template.id)
- product.save()
-
- supplier, = Location.search([('code', '=', 'SUP')])
- storage, = Location.search([('code', '=', 'STO')])
- # Ensure storage2 comes first when ordering locations by name
- storage2, = Location.copy(
- [storage], default={'name': "AAA", 'parent': storage.id})
- customer, = Location.search([('code', '=', 'CUS')])
-
- company = create_company()
- with set_company(company):
- moves = Move.create([{
- 'product': product.id,
- 'uom': uom.id,
- 'quantity': 1,
- 'from_location': supplier.id,
- 'to_location': storage.id,
- 'company': company.id,
- 'unit_price': Decimal(1),
- 'currency': company.currency.id,
- }, {
- 'product': product.id,
- 'uom': uom.id,
- 'quantity': 1,
- 'from_location': supplier.id,
- 'to_location': storage2.id,
- 'company': company.id,
- 'unit_price': Decimal(1),
- 'currency': company.currency.id,
- }])
- Move.do(moves)
-
- move, = Move.create([{
- 'product': product.id,
- 'uom': uom.id,
- 'quantity': 1,
- 'from_location': storage.id,
- 'to_location': customer.id,
- 'company': company.id,
- 'unit_price': Decimal(1),
- 'currency': company.currency.id,
- }])
-
- Move.assign_try([move])
-
- self.assertEqual(move.state, 'assigned')
- self.assertEqual(move.from_location, storage)
-
- @with_transaction()
- def test_assign_without_moves(self):
- "Test Move assign_try with empty moves"
- pool = Pool()
- Move = pool.get('stock.move')
-
- self.assertTrue(Move.assign_try([]))
-
- @with_transaction()
- def test_assign_try_modified_move(self):
- "Test Move assign_try with modified move"
- pool = Pool()
- Template = pool.get('product.template')
- Product = pool.get('product.product')
- Uom = pool.get('product.uom')
- Location = pool.get('stock.location')
- Move = pool.get('stock.move')
-
- uom, = Uom.search([('name', '=', 'Meter')])
- template = Template(
- name='Test Move.assign_try',
- type='goods',
- default_uom=uom,
- )
- template.save()
- product = Product(template=template.id)
- product.save()
-
- supplier, = Location.search([('code', '=', 'SUP')])
- storage, = Location.search([('code', '=', 'STO')])
- storage2, = Location.copy([storage])
- customer, = Location.search([('code', '=', 'CUS')])
-
- company = create_company()
- with set_company(company):
- move, = Move.create([{
- 'product': product.id,
- 'uom': uom.id,
- 'quantity': 1,
- 'from_location': supplier.id,
- 'to_location': storage.id,
- 'company': company.id,
- 'unit_price': Decimal(1),
- 'currency': company.currency.id,
- }])
- Move.do([move])
-
- move, = Move.create([{
- 'product': product.id,
- 'uom': uom.id,
- 'quantity': 2,
- 'from_location': storage2.id,
- 'to_location': customer.id,
- 'company': company.id,
- 'unit_price': Decimal(1),
- 'currency': company.currency.id,
- }])
-
- # Assign from a different location
- move.from_location = storage
- self.assertFalse(Move.assign_try([move]))
-
- move, = Move.search([
- ('to_location', '=', customer.id),
- ('state', '=', 'assigned'),
- ])
- self.assertEqual(move.from_location, storage)
- self.assertEqual(move.quantity, 1)
-
- move, = Move.search([
- ('to_location', '=', customer.id),
- ('state', '=', 'draft'),
- ])
- # Remaining move has the original location
- self.assertEqual(move.from_location, storage2)
- self.assertEqual(move.quantity, 1)
-
- @with_transaction()
- def test_products_by_location_assign(self):
- "Test products by location for assignation"
- pool = Pool()
- Template = pool.get('product.template')
- Product = pool.get('product.product')
- Uom = pool.get('product.uom')
- Location = pool.get('stock.location')
- Move = pool.get('stock.move')
- today = datetime.date.today()
-
- unit, = Uom.search([('name', '=', 'Unit')])
- template = Template(
- name="Product",
- type='goods',
- default_uom=unit,
- )
- template.save()
- product, = Product.create([{'template': template.id}])
-
- supplier, = Location.search([('code', '=', 'SUP')])
- storage, = Location.search([('code', '=', 'STO')])
- customer, = Location.search([('code', '=', 'CUS')])
-
- company = create_company()
- with set_company(company):
- move_supplier, = Move.create([{
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 10,
- 'from_location': supplier.id,
- 'to_location': storage.id,
- 'planned_date': today,
- 'company': company.id,
- 'unit_price': Decimal('1'),
- 'currency': company.currency.id,
- }])
- move_customer, = Move.create([{
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 5,
- 'from_location': storage.id,
- 'to_location': customer.id,
- 'planned_date': today + relativedelta(days=1),
- 'company': company.id,
- 'unit_price': Decimal('1'),
- 'currency': company.currency.id,
- }])
-
- Move.assign([move_supplier])
- with Transaction().set_context(
- stock_date_end=today,
- stock_assign=True):
- pbl = Product.products_by_location(
- [storage.id], grouping_filter=([product.id],))
- self.assertDictEqual(pbl, {})
-
- Move.assign([move_customer])
- with Transaction().set_context(
- stock_date_end=today,
- stock_assign=True):
- pbl = Product.products_by_location(
- [storage.id], grouping_filter=([product.id],))
- self.assertDictEqual(pbl, {(storage.id, product.id): -5})
-
- Move.do([move_supplier])
- with Transaction().set_context(
- stock_date_end=today,
- stock_assign=True):
- pbl = Product.products_by_location(
- [storage.id], grouping_filter=([product.id],))
- self.assertDictEqual(pbl, {(storage.id, product.id): 5})
-
- with Transaction().set_context(
- stock_date_end=today + relativedelta(days=1),
- stock_assign=True):
- pbl = Product.products_by_location(
- [storage.id], grouping_filter=([product.id],))
- self.assertDictEqual(pbl, {(storage.id, product.id): 5})
-
- with Transaction().set_context(
- stock_date_start=today,
- stock_date_end=today,
- stock_assign=True):
- pbl = Product.products_by_location(
- [storage.id], grouping_filter=([product.id],))
- self.assertDictEqual(pbl, {(storage.id, product.id): 10})
-
- with Transaction().set_context(
- stock_date_start=today + relativedelta(days=1),
- stock_date_end=today + relativedelta(days=1),
- stock_assign=True):
- pbl = Product.products_by_location(
- [storage.id], grouping_filter=([product.id],))
- self.assertDictEqual(pbl, {(storage.id, product.id): -5})
-
- @with_transaction()
- def test_location_inactive_without_move(self):
- "Test inactivate location without move"
- pool = Pool()
- Location = pool.get('stock.location')
- storage, = Location.search([('code', '=', 'STO')])
- location, = Location.create([{
- 'name': "Location",
- 'parent': storage.id,
- }])
-
- location.active = False
- location.save()
-
- @with_transaction()
- def test_location_inactive_with_quantity(self):
- "Test inactivate location with quantity"
- pool = Pool()
- Location = pool.get('stock.location')
- Move = pool.get('stock.move')
- Template = pool.get('product.template')
- Product = pool.get('product.product')
- Uom = pool.get('product.uom')
-
- storage, = Location.search([('code', '=', 'STO')])
- location, = Location.create([{
- 'name': "Location",
- 'parent': storage.id,
- }])
- unit, = Uom.search([('name', '=', "Unit")])
- template, = Template.create([{
- 'name': "Product",
- 'type': 'goods',
- 'default_uom': unit.id,
- }])
- product, = Product.create([{'template': template.id}])
-
- company = create_company()
- with set_company(company):
-
- moves = Move.create([{
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 1,
- 'from_location': storage.id,
- 'to_location': location.id,
- 'company': company.id,
- }])
- Move.do(moves)
- with self.assertRaises(UserError):
- location.active = False
- location.save()
-
- @with_transaction()
- def test_location_inactive_with_draft_moves(self):
- "Test inactivate location with draft moves"
- pool = Pool()
- Location = pool.get('stock.location')
- Move = pool.get('stock.move')
- Template = pool.get('product.template')
- Product = pool.get('product.product')
- Uom = pool.get('product.uom')
-
- storage, = Location.search([('code', '=', 'STO')])
- location, = Location.create([{
- 'name': "Location",
- 'parent': storage.id,
- }])
- unit, = Uom.search([('name', '=', "Unit")])
- template, = Template.create([{
- 'name': "Product",
- 'type': 'goods',
- 'default_uom': unit.id,
- }])
- product, = Product.create([{'template': template.id}])
-
- company = create_company()
- with set_company(company):
- Move.create([{
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 1,
- 'from_location': storage.id,
- 'to_location': location.id,
- 'company': company.id,
- }, {
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 1,
- 'from_location': location.id,
- 'to_location': storage.id,
- 'company': company.id,
- }])
- with self.assertRaises(UserError):
- location.active = False
- location.save()
-
- @with_transaction()
- def test_inactive_product_with_stock(self):
- "Test inactivate product with stock"
- pool = Pool()
- Location = pool.get('stock.location')
- Move = pool.get('stock.move')
- Template = pool.get('product.template')
- Product = pool.get('product.product')
- Uom = pool.get('product.uom')
-
- storage, = Location.search([('code', '=', 'STO')])
- supplier, = Location.search([('code', '=', 'SUP')])
- unit, = Uom.search([('name', '=', "Unit")])
- template, = Template.create([{
- 'name': "Product",
- 'type': 'goods',
- 'default_uom': unit.id,
- }])
- product, = Product.create([{'template': template.id}])
-
- company = create_company()
- with set_company(company):
- Move.create([{
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 1,
- 'from_location': supplier.id,
- 'to_location': storage.id,
- 'unit_price': Decimal('5'),
- 'company': company.id,
- }])
- with self.assertRaises(UserWarning):
- product.active = False
- product.save()
-
- Move.create([{
- 'product': product.id,
- 'uom': unit.id,
- 'quantity': 1,
- 'from_location': storage.id,
- 'to_location': supplier.id,
- 'unit_price': Decimal('5'),
- 'company': company.id,
- }])
- product.active = False
- product.save()
-
-
-def suite():
- suite = trytond.tests.test_tryton.suite()
- suite.addTests(unittest.TestLoader().loadTestsFromTestCase(StockTestCase))
- suite.addTests(doctest.DocFileSuite(
- 'scenario_stock_product_quantities_by_warehouse.rst',
- tearDown=doctest_teardown, encoding='utf-8',
- checker=doctest_checker,
- optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
- suite.addTests(doctest.DocFileSuite('scenario_stock_shipment_out.rst',
- tearDown=doctest_teardown, encoding='utf-8',
- checker=doctest_checker,
- optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
- suite.addTests(doctest.DocFileSuite(
- 'scenario_stock_shipment_out_same_storage_output.rst',
- tearDown=doctest_teardown, encoding='utf-8',
- checker=doctest_checker,
- optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
- suite.addTests(doctest.DocFileSuite(
- 'scenario_stock_average_cost_price.rst',
- tearDown=doctest_teardown, encoding='utf-8',
- checker=doctest_checker,
- optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
- suite.addTests(doctest.DocFileSuite(
- 'scenario_stock_recompute_average_cost_price.rst',
- tearDown=doctest_teardown, encoding='utf-8',
- checker=doctest_checker,
- optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
- suite.addTests(doctest.DocFileSuite(
- 'scenario_stock_recompute_average_cost_price_production.rst',
- tearDown=doctest_teardown, encoding='utf-8',
- checker=doctest_checker,
- optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
- suite.addTests(doctest.DocFileSuite(
- 'scenario_stock_inventory.rst',
- tearDown=doctest_teardown, encoding='utf-8',
- checker=doctest_checker,
- optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
- suite.addTests(doctest.DocFileSuite(
- 'scenario_stock_inventory_empty_quantity.rst',
- tearDown=doctest_teardown, encoding='utf-8',
- checker=doctest_checker,
- optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
- suite.addTests(doctest.DocFileSuite(
- 'scenario_stock_inventory_count.rst',
- tearDown=doctest_teardown, encoding='utf-8',
- checker=doctest_checker,
- optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
- suite.addTests(doctest.DocFileSuite('scenario_stock_shipment_internal.rst',
- tearDown=doctest_teardown, encoding='utf-8',
- checker=doctest_checker,
- optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
- suite.addTests(doctest.DocFileSuite('scenario_stock_reporting.rst',
- tearDown=doctest_teardown, encoding='utf-8',
- checker=doctest_checker,
- optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
- suite.addTests(doctest.DocFileSuite(
- 'scenario_stock_shipment_in_same_storage_input.rst',
- tearDown=doctest_teardown, encoding='utf-8',
- checker=doctest_checker,
- optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
- suite.addTests(doctest.DocFileSuite(
- 'scenario_stock_shipment_out_return_same_storage_input.rst',
- tearDown=doctest_teardown, encoding='utf-8',
- checker=doctest_checker,
- optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
- suite.addTests(doctest.DocFileSuite(
- 'scenario_stock_move_in_future.rst',
- tearDown=doctest_teardown, encoding='utf-8',
- checker=doctest_checker,
- optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
- suite.addTests(doctest.DocFileSuite(
- 'scenario_stock_shipment_in_return.rst',
- tearDown=doctest_teardown, encoding='utf-8',
- checker=doctest_checker,
- optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
- suite.addTests(doctest.DocFileSuite(
- 'scenario_stock_reporting_margin.rst',
- tearDown=doctest_teardown, encoding='utf-8',
- checker=doctest_checker,
- optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
- return suite
diff -r 80d6b2eb115e -r 2a924f6752c3 tox.ini
--- a/tox.ini Tue Apr 12 10:35:40 2022 +0200
+++ b/tox.ini Sat Apr 16 18:30:19 2022 +0200
@@ -2,8 +2,9 @@
envlist = {py37,py38,py39,py310}-{sqlite,postgresql}
[testenv]
+extras = test
commands =
- coverage run --include=.*/stock/* setup.py test
+ coverage run --include=.*/stock/* -m unittest discover -s tests
coverage report --include=.*/stock/* --omit=*/tests/*
deps =
coverage