# 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.model.exceptions import AccessError
from trytond.modules.company.tests import (
    CompanyTestMixin, PartyCompanyCheckEraseMixin, create_company, set_company)
from trytond.modules.party.tests import PartyCheckReplaceMixin
from trytond.modules.stock.exceptions import (
    LocationValidationError, MoveOriginWarning, PeriodCloseError,
    ProductStockWarning)
from trytond.pool import Pool
from trytond.tests.test_tryton import ModuleTestCase, with_transaction
from trytond.transaction import Transaction, check_access


class StockTestCase(
        PartyCompanyCheckEraseMixin, PartyCheckReplaceMixin, 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 unit, quantity, internal_quantity, ndigits in tests:
                move, = Move.create([{
                            'product': product.id,
                            'unit': unit.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 unit, quantity, internal_quantity, ndigits in tests:
                    Move.write([move], {
                        'unit': unit.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,
                        'unit': 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,
                        'unit': 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,
                        'unit': 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,
                        'unit': 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,
                        'unit': 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,
                        'unit': 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,
                        'unit': 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,
                        'unit': 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,
                        'unit': 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,
                        'unit': 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,
                        'unit': 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,
                        'unit': 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,
                        'unit': unit.id,
                        'quantity': 80,
                        'from_location': supplier.id,
                        'to_location': storage.id,
                        'effective_date': date,
                        'company': company.id,
                        'unit_price': 10.0,
                        'currency': company.currency.id,
                        }, {
                        'product': product.id,
                        'unit': 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_products_by_location_grouped_by_date(self):
        "Test products_by_location grouped by date"
        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': "Template",
                    'type': 'goods',
                    'default_uom': unit.id,
                    }])
        product, = Product.create([{
                    'template': template.id,
                    }])
        lost_found, = Location.search([('type', '=', 'lost_found')])
        storage, = Location.search([('code', '=', 'STO')])
        output, = Location.search([('code', '=', 'OUT')])
        company = create_company()
        with set_company(company):
            today = Date.today()

            moves = Move.create([{
                        'product': product.id,
                        'unit': unit.id,
                        'quantity': 10,
                        'from_location': lost_found.id,
                        'to_location': storage.id,
                        'effective_date': today,
                        'company': company.id,
                        }, {
                        'product': product.id,
                        'unit': unit.id,
                        'quantity': 2,
                        'from_location': storage.id,
                        'to_location': output.id,
                        'effective_date': today + relativedelta(days=1),
                        'company': company.id,
                        }, {
                        'product': product.id,
                        'unit': unit.id,
                        'quantity': 3,
                        'from_location': storage.id,
                        'to_location': output.id,
                        'effective_date': today + relativedelta(days=5),
                        'company': company.id,
                        }])
            with Transaction().set_context(_skip_warnings=True):
                Move.do(moves)

            with Transaction().set_context(stock_date_start=today):
                products_by_location = Product.products_by_location(
                    [storage.id],
                    grouping=('date', 'product'),
                    grouping_filter=(None, [product.id]))

            self.assertDictEqual(products_by_location, {
                    (storage.id,
                        today, product.id): 10,
                    (storage.id,
                        today + relativedelta(days=1), product.id): -2,
                    (storage.id,
                        today + relativedelta(days=5), product.id): -3,
                    })

    @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,
                        'unit': 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,
                        'unit': 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,
                        'unit': 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,
                        'unit': 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,
                        'unit': 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,
                        'unit': 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,
                        'unit': 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(AccessError, Move.create, [{
                        'product': product.id,
                        'unit': 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(AccessError, Move.create, [{
                        'product': product.id,
                        'unit': 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(PeriodCloseError, Period.close, [period])

            period, = Period.create([{
                        'date': today + relativedelta(days=1),
                        'company': company.id,
                        }])
            self.assertRaises(PeriodCloseError, 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')

        unit, = Uom.search([('name', '=', 'Unit')])
        template, = Template.create([{
                    'name': 'Test Move.check_origin',
                    'type': 'goods',
                    'default_uom': unit.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,
                        'unit': unit.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(MoveOriginWarning, 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')

        unit, = Uom.search([('name', '=', 'Meter')])
        template = Template(
            name='Test Move.assign_try',
            type='goods',
            default_uom=unit,
            )
        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,
                        'unit': unit.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,
                        'unit': unit.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')

        unit, = Uom.search([('name', '=', 'Meter')])
        template = Template(
            name='Test Move.assign_try',
            type='goods',
            default_uom=unit,
            )
        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,
                        'unit': unit.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,
                        'unit': unit.id,
                        'quantity': 1,
                        'from_location': from_.id,
                        'to_location': to.id,
                        'company': company.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')

        unit, = Uom.search([('name', '=', 'Meter')])
        template = Template(
            name='Test Move.assign_try',
            type='goods',
            default_uom=unit,
            )
        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,
                        'unit': unit.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,
                        'unit': unit.id,
                        'quantity': 1,
                        'from_location': storage.id,
                        'to_location': child.id,
                        'company': company.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')

        unit, = Uom.search([('name', '=', 'Meter')])
        template = Template(
            name='Test Move.assign_try',
            type='goods',
            default_uom=unit,
            )
        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,
                        'unit': unit.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,
                        'unit': unit.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,
                        'unit': unit.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')

        unit, = Uom.search([('name', '=', 'Meter')])
        template = Template(
            name='Test Move.assign_try',
            type='goods',
            default_uom=unit,
            )
        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,
                        'unit': unit.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,
                        'unit': unit.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,
                        'unit': 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,
                        'unit': 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 - 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, {})

            with Transaction().set_context(
                    stock_date_start=today - relativedelta(days=1),
                    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_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): 5})

            with Transaction().set_context(
                    stock_date_start=today,
                    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 + 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, {})

    @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,
                        'unit': unit.id,
                        'quantity': 1,
                        'from_location': storage.id,
                        'to_location': location.id,
                        'company': company.id,
                        }])
            Move.do(moves)
            with self.assertRaises(LocationValidationError):
                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,
                        'unit': unit.id,
                        'quantity': 1,
                        'from_location': storage.id,
                        'to_location': location.id,
                        'company': company.id,
                        }, {
                        'product': product.id,
                        'unit': unit.id,
                        'quantity': 1,
                        'from_location': location.id,
                        'to_location': storage.id,
                        'company': company.id,
                        }])
            with self.assertRaises(LocationValidationError):
                location.active = False
                location.save()

    @with_transaction()
    def test_inactive_products_with_stock(self):
        "Test inactivate products 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,
                    }])
        products = Product.create([{'template': template.id}] * 2)
        product, product2 = products

        company = create_company()
        with set_company(company):
            Move.create([{
                        'product': product.id,
                        'unit': unit.id,
                        'quantity': 1,
                        'from_location': supplier.id,
                        'to_location': storage.id,
                        'unit_price': Decimal('5'),
                        'currency': company.currency.id,
                        'company': company.id,
                        }, {
                        'product': product2.id,
                        'unit': unit.id,
                        'quantity': 1,
                        'from_location': supplier.id,
                        'to_location': storage.id,
                        'unit_price': Decimal('5'),
                        'currency': company.currency.id,
                        'company': company.id,
                        }])
            with check_access():
                with self.assertRaises(ProductStockWarning):
                    Product.write(products, {'active': False})

                with self.assertRaises(ProductStockWarning):
                    Template.write([template], {'active': False})

            Move.create([{
                        'product': product.id,
                        'unit': unit.id,
                        'quantity': 1,
                        'from_location': storage.id,
                        'to_location': supplier.id,
                        'unit_price': Decimal('5'),
                        'currency': company.currency.id,
                        'company': company.id,
                        }, {
                        'product': product2.id,
                        'unit': unit.id,
                        'quantity': 1,
                        'from_location': storage.id,
                        'to_location': supplier.id,
                        'unit_price': Decimal('5'),
                        'currency': company.currency.id,
                        'company': company.id,
                        }])
            with check_access():
                Template.write([template], {'active': False})
                Product.write(products, {'active': False})

    @with_transaction()
    def test_inactive_products_one_with_stock(self):
        "Test inactivate products one 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,
                    }])
        products = Product.create([{'template': template.id}] * 2)
        product, product2 = products

        company = create_company()
        with set_company(company):
            Move.create([{
                        'product': product.id,
                        'unit': unit.id,
                        'quantity': 1,
                        'from_location': supplier.id,
                        'to_location': storage.id,
                        'unit_price': Decimal('5'),
                        'currency': company.currency.id,
                        'company': company.id,
                        }])
            with check_access():
                with self.assertRaises(ProductStockWarning):
                    Product.write(products, {'active': False})

                with self.assertRaises(ProductStockWarning):
                    Template.write([template], {'active': False})

            Move.create([{
                        'product': product.id,
                        'unit': unit.id,
                        'quantity': 1,
                        'from_location': storage.id,
                        'to_location': supplier.id,
                        'unit_price': Decimal('5'),
                        'currency': company.currency.id,
                        'company': company.id,
                        }])
            with check_access():
                Template.write([template], {'active': False})
                Product.write(products, {'active': False})

    @with_transaction()
    def test_location_inactive_with_consumable_product(self):
        "Test inactive location with consumable products"
        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')

        warehouse, = Location.search([('type', '=', 'warehouse')])
        storage, = Location.search([('code', '=', 'STO')])
        lost_found, = Location.search([('type', '=', 'lost_found')])

        unit, = Uom.search([('name', '=', "Unit")])
        template, = Template.create([{
                    'name': "Product",
                    'type': 'goods',
                    'default_uom': unit.id,
                    'consumable': True,
                    }])
        product, = Product.create([{'template': template.id}])

        company = create_company()
        with set_company(company):
            today = datetime.date.today()

            moves = Move.create([{
                        'product': product.id,
                        'unit': unit.id,
                        'quantity': 1,
                        'from_location': lost_found.id,
                        'to_location': storage.id,
                        'planned_date': today,
                        'effective_date': today,
                        'company': company.id,
                        }])
            Move.do(moves)
            warehouse.active = False
            warehouse.save()


del ModuleTestCase
