278 lines
13 KiB
Python
278 lines
13 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import fields
|
|
|
|
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
|
from odoo.addons.product.tests.test_product_attribute_value_config import TestProductAttributeValueCommon
|
|
from odoo.tests import tagged
|
|
|
|
|
|
@tagged("post_install", "-at_install")
|
|
class TestSaleProductAttributeValueCommon(AccountTestInvoicingCommon, TestProductAttributeValueCommon):
|
|
|
|
@classmethod
|
|
def setUpClass(cls, chart_template_ref=None):
|
|
super().setUpClass(chart_template_ref=chart_template_ref)
|
|
cls.computer.company_id = cls.env.company
|
|
cls.computer = cls.computer.with_env(cls.env)
|
|
cls.env['product.pricelist'].sudo().search([]).action_archive()
|
|
cls.env['product.pricelist'].create({'name': 'Base Pricelist'})
|
|
|
|
@classmethod
|
|
def _setup_currency(cls, currency_ratio=2):
|
|
"""Get or create a currency. This makes the test non-reliant on demo.
|
|
|
|
With an easy currency rate, for a simple 2 ratio in the following tests.
|
|
"""
|
|
from_currency = cls.computer.currency_id
|
|
cls._set_or_create_rate_today(from_currency, rate=1)
|
|
|
|
to_currency = cls._get_or_create_currency("my currency", "C")
|
|
cls._set_or_create_rate_today(to_currency, currency_ratio)
|
|
return to_currency
|
|
|
|
@classmethod
|
|
def _set_or_create_rate_today(cls, currency, rate):
|
|
"""Get or create a currency rate for today. This makes the test
|
|
non-reliant on demo data."""
|
|
name = fields.Date.today()
|
|
currency_id = currency.id
|
|
company_id = cls.env.company.id
|
|
|
|
CurrencyRate = cls.env['res.currency.rate']
|
|
|
|
currency_rate = CurrencyRate.search([
|
|
('company_id', '=', company_id),
|
|
('currency_id', '=', currency_id),
|
|
('name', '=', name),
|
|
])
|
|
|
|
if currency_rate:
|
|
currency_rate.rate = rate
|
|
else:
|
|
CurrencyRate.create({
|
|
'company_id': company_id,
|
|
'currency_id': currency_id,
|
|
'name': name,
|
|
'rate': rate,
|
|
})
|
|
|
|
@classmethod
|
|
def _get_or_create_currency(cls, name, symbol):
|
|
"""Get or create a currency based on name. This makes the test
|
|
non-reliant on demo data."""
|
|
currency = cls.env['res.currency'].search([('name', '=', name)])
|
|
return currency or currency.create({
|
|
'name': name,
|
|
'symbol': symbol,
|
|
})
|
|
|
|
|
|
@tagged('post_install', '-at_install')
|
|
class TestSaleProductAttributeValueConfig(TestSaleProductAttributeValueCommon):
|
|
def _setup_pricelist(self, currency_ratio=2):
|
|
to_currency = self._setup_currency(currency_ratio)
|
|
|
|
discount = 10
|
|
|
|
pricelist = self.env['product.pricelist'].create({
|
|
'name': 'test pl',
|
|
'currency_id': to_currency.id,
|
|
'company_id': self.computer.company_id.id,
|
|
})
|
|
|
|
pricelist_item = self.env['product.pricelist.item'].create({
|
|
'min_quantity': 2,
|
|
'compute_price': 'percentage',
|
|
'percent_price': discount,
|
|
'pricelist_id': pricelist.id,
|
|
})
|
|
|
|
return (pricelist, pricelist_item, currency_ratio, 1 - discount / 100)
|
|
|
|
def test_01_is_combination_possible_archived(self):
|
|
"""The goal is to test the possibility of archived combinations.
|
|
|
|
This test could not be put into product module because there was no
|
|
model which had product_id as required and without cascade on delete.
|
|
Here we have the sales order line in this situation.
|
|
|
|
This is a necessary condition for `_create_variant_ids` to archive
|
|
instead of delete the variants.
|
|
"""
|
|
def do_test(self):
|
|
computer_ssd_256 = self._get_product_template_attribute_value(self.ssd_256)
|
|
computer_ram_8 = self._get_product_template_attribute_value(self.ram_8)
|
|
computer_hdd_1 = self._get_product_template_attribute_value(self.hdd_1)
|
|
computer_hdd_2 = self._get_product_template_attribute_value(self.hdd_2)
|
|
|
|
variant = self.computer._get_variant_for_combination(computer_ssd_256 + computer_ram_8 + computer_hdd_1)
|
|
variant2 = self.computer._get_variant_for_combination(computer_ssd_256 + computer_ram_8 + computer_hdd_2)
|
|
|
|
self.assertTrue(variant)
|
|
self.assertTrue(variant2)
|
|
|
|
# Create a dummy SO to prevent the variant from being deleted by
|
|
# _create_variant_ids() because the variant is a related field that
|
|
# is required on the SO line
|
|
so = self.env['sale.order'].create({'partner_id': 1})
|
|
self.env['sale.order.line'].create({
|
|
'order_id': so.id,
|
|
'name': "test",
|
|
'product_id': variant.id
|
|
})
|
|
# additional variant to test correct ignoring when mismatch values
|
|
self.env['sale.order.line'].create({
|
|
'order_id': so.id,
|
|
'name': "test",
|
|
'product_id': variant2.id
|
|
})
|
|
|
|
variant2.active = False
|
|
# CASE: 1 not archived, 2 archived
|
|
self.assertTrue(self.computer._is_combination_possible(computer_ssd_256 + computer_ram_8 + computer_hdd_1))
|
|
self.assertFalse(self.computer._is_combination_possible(computer_ssd_256 + computer_ram_8 + computer_hdd_2))
|
|
# CASE: both archived combination (without no_variant)
|
|
variant.active = False
|
|
self.assertFalse(self.computer._is_combination_possible(computer_ssd_256 + computer_ram_8 + computer_hdd_2))
|
|
self.assertFalse(self.computer._is_combination_possible(computer_ssd_256 + computer_ram_8 + computer_hdd_1))
|
|
|
|
# CASE: OK after attribute line removed
|
|
self.computer_hdd_attribute_lines.write({'active': False})
|
|
self.assertTrue(self.computer._is_combination_possible(computer_ssd_256 + computer_ram_8))
|
|
|
|
# CASE: not archived (with no_variant)
|
|
self.hdd_attribute.create_variant = 'no_variant'
|
|
self._add_hdd_attribute_line()
|
|
computer_hdd_1 = self._get_product_template_attribute_value(self.hdd_1)
|
|
computer_hdd_2 = self._get_product_template_attribute_value(self.hdd_2)
|
|
|
|
self.assertTrue(self.computer._is_combination_possible(computer_ssd_256 + computer_ram_8 + computer_hdd_1))
|
|
|
|
# CASE: archived combination found (with no_variant)
|
|
variant = self.computer._get_variant_for_combination(computer_ssd_256 + computer_ram_8 + computer_hdd_1)
|
|
variant.active = False
|
|
self.assertFalse(self.computer._is_combination_possible(computer_ssd_256 + computer_ram_8 + computer_hdd_1))
|
|
|
|
# CASE: archived combination has different attributes (including no_variant)
|
|
self.computer_ssd_attribute_lines.write({'active': False})
|
|
|
|
variant4 = self.computer._get_variant_for_combination(computer_ram_8 + computer_hdd_1)
|
|
self.env['sale.order.line'].create({
|
|
'order_id': so.id,
|
|
'name': "test",
|
|
'product_id': variant4.id
|
|
})
|
|
self.assertTrue(self.computer._is_combination_possible(computer_ram_8 + computer_hdd_1))
|
|
|
|
# CASE: archived combination has different attributes (without no_variant)
|
|
self.computer_hdd_attribute_lines.write({'active': False})
|
|
self.hdd_attribute.create_variant = 'always'
|
|
self._add_hdd_attribute_line()
|
|
computer_ssd_256 = self._get_product_template_attribute_value(self.ssd_256)
|
|
computer_ram_8 = self._get_product_template_attribute_value(self.ram_8)
|
|
computer_hdd_1 = self._get_product_template_attribute_value(self.hdd_1)
|
|
computer_hdd_2 = self._get_product_template_attribute_value(self.hdd_2)
|
|
|
|
variant5 = self.computer._get_variant_for_combination(computer_ram_8 + computer_hdd_1)
|
|
self.env['sale.order.line'].create({
|
|
'order_id': so.id,
|
|
'name': "test",
|
|
'product_id': variant5.id
|
|
})
|
|
|
|
self.assertTrue(variant4 != variant5)
|
|
|
|
self.assertTrue(self.computer._is_combination_possible(computer_ram_8 + computer_hdd_1))
|
|
|
|
computer_ssd_256_before = self._get_product_template_attribute_value(self.ssd_256)
|
|
|
|
do_test(self)
|
|
|
|
# CASE: add back the removed attribute and try everything again
|
|
self.computer_ssd_attribute_lines = self.env['product.template.attribute.line'].create({
|
|
'product_tmpl_id': self.computer.id,
|
|
'attribute_id': self.ssd_attribute.id,
|
|
'value_ids': [(6, 0, [self.ssd_256.id, self.ssd_512.id])],
|
|
})
|
|
|
|
computer_ssd_256_after = self._get_product_template_attribute_value(self.ssd_256)
|
|
self.assertEqual(computer_ssd_256_after, computer_ssd_256_before)
|
|
self.assertEqual(computer_ssd_256_after.attribute_line_id, computer_ssd_256_before.attribute_line_id)
|
|
do_test(self)
|
|
|
|
def test_04_create_product_variant_non_dynamic(self):
|
|
"""The goal of this test is to make sure the _create_product_variant does
|
|
not create variant if the type is not dynamic. It can however return a
|
|
variant if it already exists."""
|
|
computer_ssd_256 = self._get_product_template_attribute_value(self.ssd_256)
|
|
computer_ram_8 = self._get_product_template_attribute_value(self.ram_8)
|
|
computer_ram_16 = self._get_product_template_attribute_value(self.ram_16)
|
|
computer_hdd_1 = self._get_product_template_attribute_value(self.hdd_1)
|
|
self._add_exclude(computer_ram_16, computer_hdd_1)
|
|
|
|
# CASE: variant is already created, it should return it
|
|
combination = computer_ssd_256 + computer_ram_8 + computer_hdd_1
|
|
variant1 = self.computer._get_variant_for_combination(combination)
|
|
self.assertEqual(self.computer._create_product_variant(combination), variant1)
|
|
|
|
# CASE: variant does not exist, but template is non-dynamic, so it
|
|
# should not create it
|
|
Product = self.env['product.product']
|
|
variant1.unlink()
|
|
self.assertEqual(self.computer._create_product_variant(combination), Product)
|
|
|
|
def test_05_create_product_variant_dynamic(self):
|
|
"""The goal of this test is to make sure the _create_product_variant does
|
|
work with dynamic. If the combination is possible, it should create it.
|
|
If it's not possible, it should not create it."""
|
|
self.computer_hdd_attribute_lines.write({'active': False})
|
|
self.hdd_attribute.create_variant = 'dynamic'
|
|
self._add_hdd_attribute_line()
|
|
|
|
computer_ssd_256 = self._get_product_template_attribute_value(self.ssd_256)
|
|
computer_ram_8 = self._get_product_template_attribute_value(self.ram_8)
|
|
computer_ram_16 = self._get_product_template_attribute_value(self.ram_16)
|
|
computer_hdd_1 = self._get_product_template_attribute_value(self.hdd_1)
|
|
self._add_exclude(computer_ram_16, computer_hdd_1)
|
|
|
|
# CASE: variant does not exist, but combination is not possible
|
|
# so it should not create it
|
|
impossible_combination = computer_ssd_256 + computer_ram_16 + computer_hdd_1
|
|
Product = self.env['product.product']
|
|
self.assertEqual(self.computer._create_product_variant(impossible_combination), Product)
|
|
|
|
# CASE: the variant does not exist, and the combination is possible, so
|
|
# it should create it
|
|
combination = computer_ssd_256 + computer_ram_8 + computer_hdd_1
|
|
variant = self.computer._create_product_variant(combination)
|
|
self.assertTrue(variant)
|
|
|
|
# CASE: the variant already exists, so it should return it
|
|
self.assertEqual(variant, self.computer._create_product_variant(combination))
|
|
|
|
def _add_keyboard_attribute(self):
|
|
self.keyboard_attribute = self.env['product.attribute'].create({
|
|
'name': 'Keyboard',
|
|
'sequence': 6,
|
|
'create_variant': 'dynamic',
|
|
})
|
|
self.keyboard_included = self.env['product.attribute.value'].create({
|
|
'name': 'Included',
|
|
'attribute_id': self.keyboard_attribute.id,
|
|
'sequence': 1,
|
|
})
|
|
self.keyboard_excluded = self.env['product.attribute.value'].create({
|
|
'name': 'Excluded',
|
|
'attribute_id': self.keyboard_attribute.id,
|
|
'sequence': 2,
|
|
})
|
|
self.computer_keyboard_attribute_lines = self.env['product.template.attribute.line'].create({
|
|
'product_tmpl_id': self.computer.id,
|
|
'attribute_id': self.keyboard_attribute.id,
|
|
'value_ids': [(6, 0, [self.keyboard_included.id, self.keyboard_excluded.id])],
|
|
})
|
|
self.computer_keyboard_attribute_lines.product_template_value_ids[0].price_extra = 5
|
|
self.computer_keyboard_attribute_lines.product_template_value_ids[1].price_extra = -5
|