diff --git a/addons/sale/tests/test_onchange.py b/addons/sale/tests/test_onchange.py index 198d4702420..25a0cd2f1e4 100644 --- a/addons/sale/tests/test_onchange.py +++ b/addons/sale/tests/test_onchange.py @@ -1,271 +1,10 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.tests import Form from odoo.tests.common import TransactionCase -class TestOnchangeProductId(TransactionCase): - """Test that when an included tax is mapped by a fiscal position, the included tax must be - subtracted to the price of the product. - """ - - def setUp(self): - super(TestOnchangeProductId, self).setUp() - self.fiscal_position_model = self.env['account.fiscal.position'] - self.fiscal_position_tax_model = self.env['account.fiscal.position.tax'] - self.tax_model = self.env['account.tax'] - self.so_model = self.env['sale.order'] - self.po_line_model = self.env['sale.order.line'] - self.res_partner_model = self.env['res.partner'] - self.product_tmpl_model = self.env['product.template'] - self.product_model = self.env['product.product'] - self.product_uom_model = self.env['uom.uom'] - self.pricelist_model = self.env['product.pricelist'] - - def test_onchange_product_id(self): - - uom_id = self.product_uom_model.search([('name', '=', 'Units')])[0] - pricelist = self.pricelist_model.search([('name', '=', 'Public Pricelist')])[0] - - partner_id = self.res_partner_model.create(dict(name="George")) - tax_include_id = self.tax_model.create(dict(name="Include tax", - amount='21.00', - price_include=True, - type_tax_use='sale')) - tax_exclude_id = self.tax_model.create(dict(name="Exclude tax", - amount='0.00', - type_tax_use='sale')) - - product_tmpl_id = self.product_tmpl_model.create(dict(name="Voiture", - list_price=121, - taxes_id=[(6, 0, [tax_include_id.id])])) - - product_id = product_tmpl_id.product_variant_id - - fp_id = self.fiscal_position_model.create(dict(name="fiscal position", sequence=1)) - - fp_tax_id = self.fiscal_position_tax_model.create(dict(position_id=fp_id.id, - tax_src_id=tax_include_id.id, - tax_dest_id=tax_exclude_id.id)) - - # Create the SO with one SO line and apply a pricelist and fiscal position on it - order_form = Form(self.env['sale.order'].with_context(tracking_disable=True)) - order_form.partner_id = partner_id - order_form.pricelist_id = pricelist - order_form.fiscal_position_id = fp_id - with order_form.order_line.new() as line: - line.name = product_id.name - line.product_id = product_id - line.product_uom_qty = 1.0 - line.product_uom = uom_id - sale_order = order_form.save() - - # Check the unit price of SO line - self.assertEqual(100, sale_order.order_line[0].price_unit, "The included tax must be subtracted to the price") - - def test_pricelist_application(self): - """ Test different prices are correctly applied based on dates """ - support_product = self.env['product.product'].create({ - 'name': 'Virtual Home Staging', - 'list_price': 100, - }) - partner = self.res_partner_model.create(dict(name="George")) - - christmas_pricelist = self.env['product.pricelist'].create({ - 'name': 'Christmas pricelist', - 'item_ids': [(0, 0, { - 'date_start': "2017-12-01", - 'date_end': "2017-12-24", - 'compute_price': 'percentage', - 'base': 'list_price', - 'percent_price': 20, - 'applied_on': '3_global', - 'name': 'Pre-Christmas discount' - }), (0, 0, { - 'date_start': "2017-12-25", - 'date_end': "2017-12-31", - 'compute_price': 'percentage', - 'base': 'list_price', - 'percent_price': 50, - 'applied_on': '3_global', - 'name': 'Post-Christmas super-discount' - })] - }) - - # Create the SO with pricelist based on date - order_form = Form(self.env['sale.order'].with_context(tracking_disable=True)) - order_form.partner_id = partner - order_form.date_order = '2017-12-20' - order_form.pricelist_id = christmas_pricelist - with order_form.order_line.new() as line: - line.product_id = support_product - so = order_form.save() - # Check the unit price and subtotal of SO line - self.assertEqual(so.order_line[0].price_unit, 80, "First date pricelist rule not applied") - self.assertEqual(so.order_line[0].price_subtotal, so.order_line[0].price_unit * so.order_line[0].product_uom_qty, 'Total of SO line should be a multiplication of unit price and ordered quantity') - - # Change order date of the SO and check the unit price and subtotal of SO line - with Form(so) as order: - order.date_order = '2017-12-30' - with order.order_line.edit(0) as line: - line.product_id = support_product - - self.assertEqual(so.order_line[0].price_unit, 50, "Second date pricelist rule not applied") - self.assertEqual(so.order_line[0].price_subtotal, so.order_line[0].price_unit * so.order_line[0].product_uom_qty, 'Total of SO line should be a multiplication of unit price and ordered quantity') - - def test_pricelist_uom_discount(self): - """ Test prices and discounts are correctly applied based on date and uom""" - computer_case = self.env['product.product'].create({ - 'name': 'Drawer Black', - 'list_price': 100, - }) - partner = self.res_partner_model.create(dict(name="George")) - categ_unit_id = self.ref('uom.product_uom_categ_unit') - goup_discount_id = self.ref('product.group_discount_per_so_line') - self.env.user.write({'groups_id': [(4, goup_discount_id, 0)]}) - new_uom = self.env['uom.uom'].create({ - 'name': '10 units', - 'factor_inv': 10, - 'uom_type': 'bigger', - 'rounding': 1.0, - 'category_id': categ_unit_id - }) - christmas_pricelist = self.env['product.pricelist'].create({ - 'name': 'Christmas pricelist', - 'discount_policy': 'without_discount', - 'item_ids': [(0, 0, { - 'date_start': "2017-12-01", - 'date_end': "2017-12-30", - 'compute_price': 'percentage', - 'base': 'list_price', - 'percent_price': 10, - 'applied_on': '3_global', - 'name': 'Christmas discount' - })] - }) - - so = self.env['sale.order'].create({ - 'partner_id': partner.id, - 'date_order': '2017-12-20', - 'pricelist_id': christmas_pricelist.id, - }) - - order_line = self.env['sale.order.line'].create({ - 'order_id': so.id, - 'product_id': computer_case.id, - }) - - self.assertEqual(order_line.price_subtotal, 90, "Christmas discount pricelist rule not applied") - self.assertEqual(order_line.discount, 10, "Christmas discount not equalt to 10%") - order_line.product_uom = new_uom - self.assertEqual(order_line.price_subtotal, 900, "Christmas discount pricelist rule not applied") - self.assertEqual(order_line.discount, 10, "Christmas discount not equalt to 10%") - - def test_pricelist_based_on_other(self): - """ Test price and discount are correctly applied with a pricelist based on an other one""" - computer_case = self.env['product.product'].create({ - 'name': 'Drawer Black', - 'list_price': 100, - }) - partner = self.res_partner_model.create(dict(name="George")) - goup_discount_id = self.ref('product.group_discount_per_so_line') - self.env.user.write({'groups_id': [(4, goup_discount_id, 0)]}) - - first_pricelist = self.env['product.pricelist'].create({ - 'name': 'First pricelist', - 'discount_policy': 'without_discount', - 'item_ids': [(0, 0, { - 'compute_price': 'percentage', - 'base': 'list_price', - 'percent_price': 10, - 'applied_on': '3_global', - 'name': 'First discount' - })] - }) - - second_pricelist = self.env['product.pricelist'].create({ - 'name': 'Second pricelist', - 'discount_policy': 'without_discount', - 'item_ids': [(0, 0, { - 'compute_price': 'formula', - 'base': 'pricelist', - 'base_pricelist_id': first_pricelist.id, - 'price_discount': 10, - 'applied_on': '3_global', - 'name': 'Second discount' - })] - }) - - so = self.env['sale.order'].create({ - 'partner_id': partner.id, - 'date_order': '2018-07-11', - 'pricelist_id': second_pricelist.id, - }) - - order_line = self.env['sale.order.line'].create({ - 'order_id': so.id, - 'product_id': computer_case.id, - }) - - self.assertEqual(order_line.price_subtotal, 81, "Second pricelist rule not applied") - self.assertEqual(order_line.discount, 19, "Second discount not applied") - - def test_pricelist_with_other_currency(self): - """ Test prices are correctly applied with a pricelist with an other currency""" - computer_case = self.env['product.product'].create({ - 'name': 'Drawer Black', - 'list_price': 100, - }) - computer_case.list_price = 100 - partner = self.res_partner_model.create(dict(name="George")) - categ_unit_id = self.ref('uom.product_uom_categ_unit') - other_currency = self.env['res.currency'].create({'name': 'other currency', - 'symbol': 'other'}) - self.env['res.currency.rate'].create({'name': '2018-07-11', - 'rate': 2.0, - 'currency_id': other_currency.id, - 'company_id': self.env.company.id}) - self.env['res.currency.rate'].search( - [('currency_id', '=', self.env.company.currency_id.id)] - ).unlink() - new_uom = self.env['uom.uom'].create({ - 'name': '10 units', - 'factor_inv': 10, - 'uom_type': 'bigger', - 'rounding': 1.0, - 'category_id': categ_unit_id - }) - - # This pricelist doesn't show the discount - first_pricelist = self.env['product.pricelist'].create({ - 'name': 'First pricelist', - 'currency_id': other_currency.id, - 'discount_policy': 'with_discount', - 'item_ids': [(0, 0, { - 'compute_price': 'percentage', - 'base': 'list_price', - 'percent_price': 10, - 'applied_on': '3_global', - 'name': 'First discount' - })] - }) - - so = self.env['sale.order'].create({ - 'partner_id': partner.id, - 'date_order': '2018-07-12', - 'pricelist_id': first_pricelist.id, - }) - - order_line = self.env['sale.order.line'].new({ - 'order_id': so.id, - 'product_id': computer_case.id, - }) - - # force compute uom and prices - self.assertEqual(order_line.price_unit, 180, "First pricelist rule not applied") - order_line.product_uom = new_uom - self.assertEqual(order_line.price_unit, 1800, "First pricelist rule not applied") +class TestSaleOnchanges(TransactionCase): def test_sale_warnings(self): """Test warnings & SO/SOL updates when partner/products with sale warnings are used.""" diff --git a/addons/sale/tests/test_sale_order.py b/addons/sale/tests/test_sale_order.py index feb3376e303..6e4a44cce5e 100644 --- a/addons/sale/tests/test_sale_order.py +++ b/addons/sale/tests/test_sale_order.py @@ -4,6 +4,7 @@ from datetime import timedelta from freezegun import freeze_time from odoo import fields +from odoo.fields import Command from odoo.exceptions import UserError, AccessError from odoo.tests import tagged, Form from odoo.tools import float_compare @@ -11,7 +12,7 @@ from odoo.tools import float_compare from .common import TestSaleCommon -@tagged('post_install', '-at_install', 'sale_order') +@tagged('post_install', '-at_install') class TestSaleOrder(TestSaleCommon): @classmethod @@ -723,3 +724,42 @@ class TestSaleOrder(TestSaleCommon): # (541,26 / 1,15) * ,98 * 38 = 17527,410782609 ~= 17527.41 self.assertEqual(line.price_subtotal, 17527.41) self.assertEqual(line.untaxed_amount_to_invoice, line.price_subtotal) + + def test_so_tax_mapping(self): + uom = self.env['uom.uom'].search([('name', '=', 'Units')], limit=1) + pricelist = self.env['product.pricelist'].search([('name', '=', 'Public Pricelist')], limit=1) + + partner = self.env['res.partner'].create(dict(name="George")) + tax_include = self.env['account.tax'].create(dict(name="Include tax", + amount='21.00', + price_include=True, + type_tax_use='sale')) + tax_exclude = self.env['account.tax'].create(dict(name="Exclude tax", + amount='0.00', + type_tax_use='sale')) + + product_tmpl = self.env['product.template'].create(dict(name="Voiture", + list_price=121, + taxes_id=[(6, 0, [tax_include.id])])) + + product = product_tmpl.product_variant_id + + fpos = self.env['account.fiscal.position'].create(dict(name="fiscal position", sequence=1)) + fp_tax_id = self.env['account.fiscal.position.tax'].create({ + 'position_id': fpos.id, + 'tax_src_id': tax_include.id, + 'tax_dest_id': tax_exclude.id, + }) + + sale_order = self.env['sale.order'].create({ + 'partner_id': partner.id, + 'pricelist_id': pricelist.id, + 'fiscal_position_id': fpos.id, + 'order_line': [Command.create({ + 'product_id': product.id, + 'product_uom': uom.id, + })] + }) + + # Check the unit price of SO line + self.assertEqual(100, sale_order.order_line[0].price_unit, "The included tax must be subtracted to the price") diff --git a/addons/sale/tests/test_sale_pricelist.py b/addons/sale/tests/test_sale_pricelist.py index a1db9f509ac..f4fd05947a8 100644 --- a/addons/sale/tests/test_sale_pricelist.py +++ b/addons/sale/tests/test_sale_pricelist.py @@ -2,10 +2,11 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from .common import TestSaleCommon +from odoo.fields import Command from odoo.tests import tagged -@tagged('post_install', '-at_install', 'sale_pricelist') +@tagged('post_install', '-at_install') class TestSaleOrder(TestSaleCommon): @classmethod @@ -158,3 +159,206 @@ class TestSaleOrder(TestSaleCommon): else: # no discount for the rest self.assertEqual(line.discount, 0.0, 'Pricelist of SO should not be applied on an order line') self.assertEqual(line.price_unit, line.product_id.list_price, 'Unit price of order line should be a sale price as the pricelist not applied on the other category\'s product') + + def test_pricelist_application(self): + """ Test different prices are correctly applied based on dates """ + support_product = self.env['product.product'].create({ + 'name': 'Virtual Home Staging', + 'list_price': 100, + }) + partner = self.env['res.partner'].create(dict(name="George")) + + christmas_pricelist = self.env['product.pricelist'].create({ + 'name': 'Christmas pricelist', + 'item_ids': [(0, 0, { + 'date_start': "2017-12-01", + 'date_end': "2017-12-24", + 'compute_price': 'percentage', + 'base': 'list_price', + 'percent_price': 20, + 'applied_on': '3_global', + 'name': 'Pre-Christmas discount' + }), (0, 0, { + 'date_start': "2017-12-25", + 'date_end': "2017-12-31", + 'compute_price': 'percentage', + 'base': 'list_price', + 'percent_price': 50, + 'applied_on': '3_global', + 'name': 'Post-Christmas super-discount' + })] + }) + + # Create the SO with pricelist based on date + so = self.env['sale.order'].create({ + 'partner_id': partner.id, + 'date_order': '2017-12-20', + 'pricelist_id': christmas_pricelist.id, + 'order_line': [Command.create({'product_id': support_product.id})] + }) + # Check the unit price and subtotal of SO line + self.assertEqual(so.order_line[0].price_unit, 80, "First date pricelist rule not applied") + self.assertEqual(so.order_line[0].price_subtotal, so.order_line[0].price_unit * so.order_line[0].product_uom_qty, 'Total of SO line should be a multiplication of unit price and ordered quantity') + + # Change order date of the SO and check the unit price and subtotal of SO line + so.date_order = '2017-12-30' + so.update_prices() + + self.assertEqual(so.order_line[0].price_unit, 50, "Second date pricelist rule not applied") + self.assertEqual(so.order_line[0].price_subtotal, so.order_line[0].price_unit * so.order_line[0].product_uom_qty, 'Total of SO line should be a multiplication of unit price and ordered quantity') + + def test_pricelist_uom_discount(self): + """ Test prices and discounts are correctly applied based on date and uom""" + computer_case = self.env['product.product'].create({ + 'name': 'Drawer Black', + 'list_price': 100, + }) + partner = self.env['res.partner'].create(dict(name="George")) + categ_unit_id = self.ref('uom.product_uom_categ_unit') + goup_discount_id = self.ref('product.group_discount_per_so_line') + self.env.user.write({'groups_id': [(4, goup_discount_id, 0)]}) + new_uom = self.env['uom.uom'].create({ + 'name': '10 units', + 'factor_inv': 10, + 'uom_type': 'bigger', + 'rounding': 1.0, + 'category_id': categ_unit_id + }) + christmas_pricelist = self.env['product.pricelist'].create({ + 'name': 'Christmas pricelist', + 'discount_policy': 'without_discount', + 'item_ids': [(0, 0, { + 'date_start': "2017-12-01", + 'date_end': "2017-12-30", + 'compute_price': 'percentage', + 'base': 'list_price', + 'percent_price': 10, + 'applied_on': '3_global', + 'name': 'Christmas discount' + })] + }) + + so = self.env['sale.order'].create({ + 'partner_id': partner.id, + 'date_order': '2017-12-20', + 'pricelist_id': christmas_pricelist.id, + }) + + order_line = self.env['sale.order.line'].create({ + 'order_id': so.id, + 'product_id': computer_case.id, + }) + + self.assertEqual(order_line.price_subtotal, 90, "Christmas discount pricelist rule not applied") + self.assertEqual(order_line.discount, 10, "Christmas discount not equalt to 10%") + order_line.product_uom = new_uom + self.assertEqual(order_line.price_subtotal, 900, "Christmas discount pricelist rule not applied") + self.assertEqual(order_line.discount, 10, "Christmas discount not equalt to 10%") + + def test_pricelist_based_on_other(self): + """ Test price and discount are correctly applied with a pricelist based on an other one""" + computer_case = self.env['product.product'].create({ + 'name': 'Drawer Black', + 'list_price': 100, + }) + partner = self.env['res.partner'].create(dict(name="George")) + goup_discount_id = self.ref('product.group_discount_per_so_line') + self.env.user.write({'groups_id': [(4, goup_discount_id, 0)]}) + + first_pricelist = self.env['product.pricelist'].create({ + 'name': 'First pricelist', + 'discount_policy': 'without_discount', + 'item_ids': [(0, 0, { + 'compute_price': 'percentage', + 'base': 'list_price', + 'percent_price': 10, + 'applied_on': '3_global', + 'name': 'First discount' + })] + }) + + second_pricelist = self.env['product.pricelist'].create({ + 'name': 'Second pricelist', + 'discount_policy': 'without_discount', + 'item_ids': [(0, 0, { + 'compute_price': 'formula', + 'base': 'pricelist', + 'base_pricelist_id': first_pricelist.id, + 'price_discount': 10, + 'applied_on': '3_global', + 'name': 'Second discount' + })] + }) + + so = self.env['sale.order'].create({ + 'partner_id': partner.id, + 'date_order': '2018-07-11', + 'pricelist_id': second_pricelist.id, + }) + + order_line = self.env['sale.order.line'].create({ + 'order_id': so.id, + 'product_id': computer_case.id, + }) + + self.assertEqual(order_line.price_subtotal, 81, "Second pricelist rule not applied") + self.assertEqual(order_line.discount, 19, "Second discount not applied") + + def test_pricelist_with_other_currency(self): + """ Test prices are correctly applied with a pricelist with an other currency""" + computer_case = self.env['product.product'].create({ + 'name': 'Drawer Black', + 'list_price': 100, + }) + # computer_case.list_price = 100 + partner = self.env['res.partner'].create(dict(name="George")) + categ_unit_id = self.ref('uom.product_uom_categ_unit') + other_currency = self.env['res.currency'].create({ + 'name': 'other currency', + 'symbol': 'other' + }) + self.env['res.currency.rate'].create({'name': '2018-07-11', + 'rate': 2.0, + 'currency_id': other_currency.id, + 'company_id': self.env.company.id + }) + self.env['res.currency.rate'].search( + [('currency_id', '=', self.env.company.currency_id.id)] + ).unlink() + new_uom = self.env['uom.uom'].create({ + 'name': '10 units', + 'factor_inv': 10, + 'uom_type': 'bigger', + 'rounding': 1.0, + 'category_id': categ_unit_id + }) + + # This pricelist doesn't show the discount + first_pricelist = self.env['product.pricelist'].create({ + 'name': 'First pricelist', + 'currency_id': other_currency.id, + 'discount_policy': 'with_discount', + 'item_ids': [(0, 0, { + 'compute_price': 'percentage', + 'base': 'list_price', + 'percent_price': 10, + 'applied_on': '3_global', + 'name': 'First discount' + })] + }) + + so = self.env['sale.order'].create({ + 'partner_id': partner.id, + 'date_order': '2018-07-12', + 'pricelist_id': first_pricelist.id, + }) + + order_line = self.env['sale.order.line'].new({ + 'order_id': so.id, + 'product_id': computer_case.id, + }) + + # force compute uom and prices + self.assertEqual(order_line.price_unit, 180, "First pricelist rule not applied") + order_line.product_uom = new_uom + self.assertEqual(order_line.price_unit, 1800, "First pricelist rule not applied")