# 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 decimal import Decimal from dateutil.relativedelta import relativedelta from trytond.modules.company.tests import ( CompanyTestMixin, create_company, set_company) from trytond.pool import Pool from trytond.tests.test_tryton import ModuleTestCase, with_transaction from trytond.transaction import Transaction, inactive_records class StockForecastTestCase(CompanyTestMixin, ModuleTestCase): 'Test StockForecast module' module = 'stock_forecast' @with_transaction() def test_forecast_rec_name(self): pool = Pool() Forecast = pool.get('stock.forecast') Location = pool.get('stock.location') customer, = Location.search([('code', '=', 'CUS')]) warehouse, = Location.search([('code', '=', 'WH')]) storage, = Location.search([('code', '=', 'STO')]) company = create_company() with set_company(company): forecast = Forecast( warehouse=warehouse, destination=customer, from_date=datetime.date(2023, 1, 1), to_date=datetime.date(2023, 3, 31), ) forecast.save() with inactive_records(): forecasts = Forecast.search([('rec_name', '=', "Warehouse")]) self.assertEqual( forecast.rec_name, "[WH] Warehouse → [CUS] Customer @ [01/01/2023 - 03/31/2023]") self.assertEqual(forecasts, [forecast]) @with_transaction() def test_distribute(self): 'Test distribute' pool = Pool() Line = pool.get('stock.forecast.line') line = Line() for values, result in ( ((1, 5), {0: 5}), ((4, 8), {0: 2, 1: 2, 2: 2, 3: 2}), ((2, 5), {0: 2, 1: 3}), ((10, 4), {0: 0, 1: 1, 2: 0, 3: 1, 4: 0, 5: 0, 6: 1, 7: 0, 8: 1, 9: 0}), ): self.assertEqual(line.distribute(*values), result) @with_transaction() def test_create_moves_before(self): "Test create moves before start date" pool = Pool() Uom = pool.get('product.uom') Template = pool.get('product.template') Product = pool.get('product.product') Location = pool.get('stock.location') Forecast = pool.get('stock.forecast') Move = pool.get('stock.move') unit, = Uom.search([('name', '=', 'Unit')]) template, = Template.create([{ 'name': 'Test create_moves', 'type': 'goods', 'default_uom': unit.id, }]) product, = Product.create([{ 'template': template.id, }]) customer, = Location.search([('code', '=', 'CUS')]) warehouse, = Location.search([('code', '=', 'WH')]) storage, = Location.search([('code', '=', 'STO')]) company = create_company() with set_company(company): today = datetime.date.today() forecast, = Forecast.create([{ 'warehouse': warehouse.id, 'destination': customer.id, 'from_date': today + relativedelta(months=1, day=1), 'to_date': today + relativedelta(months=1, day=20), 'company': company.id, 'lines': [ ('create', [{ 'product': product.id, 'quantity': 10, 'unit': unit.id, 'minimal_quantity': 2, }], ), ], }]) Forecast.confirm([forecast]) Forecast.create_moves([forecast]) line, = forecast.lines self.assertEqual(line.quantity_executed, 0) self.assertEqual(len(line.moves), 5) self.assertEqual(sum(move.quantity for move in line.moves), 10) self.assertGreaterEqual( min(m.planned_date for m in line.moves), forecast.from_date) Forecast.delete_moves([forecast]) line, = forecast.lines self.assertEqual(len(line.moves), 0) Move.create([{ 'from_location': storage.id, 'to_location': customer.id, 'product': product.id, 'unit': unit.id, 'quantity': 2, 'planned_date': today + relativedelta(months=1, day=5), 'company': company.id, 'currency': company.currency.id, 'unit_price': Decimal('1'), }]) line, = forecast.lines self.assertEqual(line.quantity_executed, 2) Forecast.create_moves([forecast]) line, = forecast.lines self.assertEqual(line.quantity_executed, 2) self.assertEqual(len(line.moves), 4) self.assertEqual(sum(move.quantity for move in line.moves), 8) self.assertGreaterEqual( min(m.planned_date for m in line.moves), forecast.from_date) @with_transaction() def test_create_moves_during(self): "Test create moves during the period" pool = Pool() Uom = pool.get('product.uom') Template = pool.get('product.template') Product = pool.get('product.product') Location = pool.get('stock.location') Forecast = pool.get('stock.forecast') Move = pool.get('stock.move') unit, = Uom.search([('name', '=', 'Unit')]) template, = Template.create([{ 'name': 'Test create_moves', 'type': 'goods', 'default_uom': unit.id, }]) product, = Product.create([{ 'template': template.id, }]) customer, = Location.search([('code', '=', 'CUS')]) warehouse, = Location.search([('code', '=', 'WH')]) storage, = Location.search([('code', '=', 'STO')]) company = create_company() with set_company(company): today = datetime.date.today() forecast, = Forecast.create([{ 'warehouse': warehouse.id, 'destination': customer.id, 'from_date': today - relativedelta(days=20), 'to_date': today + relativedelta(days=10), 'company': company.id, 'lines': [ ('create', [{ 'product': product.id, 'quantity': 20, 'unit': unit.id, 'minimal_quantity': 2, }], ), ], }]) Forecast.confirm([forecast]) Forecast.create_moves([forecast]) line, = forecast.lines self.assertEqual(line.quantity_executed, 0) self.assertEqual(len(line.moves), 10) self.assertEqual(sum(move.quantity for move in line.moves), 20) self.assertGreaterEqual( min(m.planned_date for m in line.moves), today) Forecast.delete_moves([forecast]) line, = forecast.lines self.assertEqual(len(line.moves), 0) Move.create([{ 'from_location': storage.id, 'to_location': customer.id, 'product': product.id, 'unit': unit.id, 'quantity': 10, 'planned_date': today - relativedelta(days=5), 'company': company.id, 'currency': company.currency.id, 'unit_price': Decimal('1'), }]) line, = forecast.lines self.assertEqual(line.quantity_executed, 10) Forecast.create_moves([forecast]) line, = forecast.lines self.assertEqual(line.quantity_executed, 10) self.assertEqual(len(line.moves), 5) self.assertEqual(sum(move.quantity for move in line.moves), 10) self.assertGreaterEqual( min(m.planned_date for m in line.moves), today) @with_transaction() def test_create_moves_after(self): "Test create not moves after end date" pool = Pool() Uom = pool.get('product.uom') Template = pool.get('product.template') Product = pool.get('product.product') Location = pool.get('stock.location') Forecast = pool.get('stock.forecast') unit, = Uom.search([('name', '=', 'Unit')]) template, = Template.create([{ 'name': 'Test create_moves', 'type': 'goods', 'default_uom': unit.id, }]) product, = Product.create([{ 'template': template.id, }]) customer, = Location.search([('code', '=', 'CUS')]) warehouse, = Location.search([('code', '=', 'WH')]) storage, = Location.search([('code', '=', 'STO')]) company = create_company() with set_company(company): today = datetime.date.today() forecast, = Forecast.create([{ 'warehouse': warehouse.id, 'destination': customer.id, 'from_date': today - relativedelta(days=20), 'to_date': today - relativedelta(days=10), 'company': company.id, 'lines': [ ('create', [{ 'product': product.id, 'quantity': 20, 'unit': unit.id, 'minimal_quantity': 2, }], ), ], }]) Forecast.confirm([forecast]) Forecast.create_moves([forecast]) line, = forecast.lines self.assertEqual(len(line.moves), 0) @with_transaction() def test_complete(self): 'Test complete' pool = Pool() Uom = pool.get('product.uom') Template = pool.get('product.template') Product = pool.get('product.product') Location = pool.get('stock.location') Forecast = pool.get('stock.forecast') Move = pool.get('stock.move') ForecastComplete = pool.get('stock.forecast.complete', type='wizard') unit, = Uom.search([('name', '=', 'Unit')]) template, = Template.create([{ 'name': 'Test complete', 'type': 'goods', 'default_uom': unit.id, }]) product, = Product.create([{ 'template': template.id, }]) customer, = Location.search([('code', '=', 'CUS')]) supplier, = Location.search([('code', '=', 'SUP')]) warehouse, = Location.search([('code', '=', 'WH')]) storage, = Location.search([('code', '=', 'STO')]) company = create_company() with set_company(company): today = datetime.date.today() moves = Move.create([{ 'from_location': supplier.id, 'to_location': storage.id, 'product': product.id, 'unit': unit.id, 'quantity': 10, 'effective_date': (today + relativedelta(months=-1, day=1)), 'company': company.id, 'currency': company.currency.id, 'unit_price': Decimal('1'), }, { 'from_location': storage.id, 'to_location': customer.id, 'product': product.id, 'unit': unit.id, 'quantity': 5, 'effective_date': (today + relativedelta(months=-1, day=15)), 'company': company.id, 'currency': company.currency.id, 'unit_price': Decimal('1'), }]) Move.do(moves) forecast, = Forecast.create([{ 'warehouse': warehouse.id, 'destination': customer.id, 'from_date': today + relativedelta(months=1, day=1), 'to_date': today + relativedelta(months=1, day=20), 'company': company.id, }]) with Transaction().set_context( active_model=Forecast.__name__, active_id=forecast.id): session_id, _, _ = ForecastComplete.create() forecast_complete = ForecastComplete(session_id) forecast_complete.ask.company = company forecast_complete.ask.warehouse = warehouse forecast_complete.ask.destination = customer forecast_complete.ask.from_date = ( today + relativedelta(months=-1, day=1)) forecast_complete.ask.to_date = ( today + relativedelta(months=-1, day=20)) forecast_complete.ask.products = [product] forecast_complete.transition_complete() self.assertEqual(len(forecast.lines), 1) forecast_line, = forecast.lines self.assertEqual(forecast_line.product, product) self.assertEqual(forecast_line.unit, unit) self.assertEqual(forecast_line.quantity, 5) self.assertEqual(forecast_line.minimal_quantity, 1) del ModuleTestCase