diff --git a/addons/account/controllers/portal.py b/addons/account/controllers/portal.py index b72d3415bcf..005f1997af4 100644 --- a/addons/account/controllers/portal.py +++ b/addons/account/controllers/portal.py @@ -11,7 +11,8 @@ class PortalAccount(CustomerPortal): def _prepare_portal_layout_values(self): values = super(PortalAccount, self)._prepare_portal_layout_values() - invoice_count = request.env['account.move'].search_count([ + # An internal user could not have access to the account.move model + invoice_count = request.env['account.move'].sudo().search_count([ ('type', 'in', ('out_invoice', 'in_invoice', 'out_refund', 'in_refund', 'out_receipt', 'in_receipt')), ]) values['invoice_count'] = invoice_count diff --git a/addons/account/models/account.py b/addons/account/models/account.py index b4f5756fd2b..7dd4ef7d2ed 100644 --- a/addons/account/models/account.py +++ b/addons/account/models/account.py @@ -259,7 +259,6 @@ class AccountAccount(models.Model): """, tuple(self.ids)) ids = self._cr.fetchall() if ids: - # import pdb; pdb.set_trace() raise ValidationError(_('Some journal items already exist with this account but in other journals than the allowed ones.')) @api.depends('code') diff --git a/addons/account/test/account_minimal_test.xml b/addons/account/test/account_minimal_test.xml deleted file mode 100644 index 144f971cf90..00000000000 --- a/addons/account/test/account_minimal_test.xml +++ /dev/null @@ -1,301 +0,0 @@ - - - - - - - - X1100 - - - - - - - - - X1000 - Fixed Assets - (test) - - - - X1010 - Current Assets - (test) - - - - X1011 - Purchased Stocks - (test) - - - - - X1012 - Debtors - (test) - - - - - X1013 - VAT Paid- (test) - - - - X1014 - Bank Current Account - (test) - - - - X1015 - Cash - (test) - - - - X1016 - Opening Income - (test) - - - - X1017 - USD Bank Account - (test) - - - - - X1019 - Internal Transfert Account - (test) - - 1 - - - X1020 - Non-current Assets - (test) - - - - X1030 - Prepayments - (test) - - - - X1110 - Current Liabilities - (test) - - - - X1111 - Creditors - (test) - - - - - - X1112 - VAT Received - (test) - - - - - X1113 - Reserve and Profit/Loss - (test) - - - - - X1120 - Non-current Liabilities - (test) - - - - X1114 - Opening Expense - (test) - - - - - - - Foreign Exchange Gain - (test) - X2010 - - - - - X2020 - Product Sales - (test) - - - - - X2021 - Sale of Lands - (test) - - - - - X2022 - Bank Accounts Interests - (test) - - - - - X2030 - Cost of Goods Sold - (test) - - - - - Foreign Exchange Loss - (test) - X2110 - - - - - X2120 - Expenses - (test) - - - - - X2121 - Salary Expenses - (test) - - - - - X2122 - Purchase of Equipments - (test) - - - - - X2123 - Bank Fees - (test) - - - - - X3001 - Capital - - - - X3002 - Dividends - - - - - - property_account_receivable_id - - - - - - property_account_payable_id - - - - - - property_account_position_id - - - - - - - - - Customer Invoices - Test - TINV - sale - - - - - - - Vendor Bills - Test - TEXJ - purchase - - - - - - - 987654321 - Bank - - - - Bank - Test - TBNK - bank - - - - - Cash - Test - TCSH - cash - - - - - - - Miscellaneous - Test - TMIS - general - - - - Currency Difference - Test - CUR - general - - - - - - - 123456789 - Bank US - - - - USD Bank - Test - TUBK - bank - - - - - - - - - - - property_account_expense_categ_id - - - - - - property_account_income_categ_id - - - - - - diff --git a/addons/account/tests/__init__.py b/addons/account/tests/__init__.py index 004d914db65..7bf7eabf151 100644 --- a/addons/account/tests/__init__.py +++ b/addons/account/tests/__init__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from . import account_minimal_test from . import test_account_move_out_invoice from . import test_account_move_out_refund from . import test_account_move_in_invoice diff --git a/addons/account/tests/account_minimal_test.py b/addons/account/tests/account_minimal_test.py new file mode 100644 index 00000000000..daaaaa35652 --- /dev/null +++ b/addons/account/tests/account_minimal_test.py @@ -0,0 +1,294 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.tests.common import SavepointCase + + +class AccountMinimalTest(SavepointCase): + """ This should be loaded for non python tests in other modules that require + accounting test data but that don't depend on any localization""" + + @classmethod + def setUpClass(cls): + super(AccountMinimalTest, cls).setUpClass() + cls.create_accounting_minimal_data() + + @classmethod + def create_accounting_minimal_data(cls): + cls.company = cls.env.company + cls.company.bank_account_code_prefix = 'X1100' + + # Chart of Accounts + + # Account Tags + cls.demo_capital_account = cls.env['account.account.tag'].create({'name': 'Demo Capital Account'}) + cls.demo_stock_account = cls.env['account.account.tag'].create({'name': 'Demo Stock Account'}) + cls.demo_sale_of_land_account = cls.env['account.account.tag'].create({'name': 'Demo Sale of Land Account'}) + cls.demo_ceo_wages_account = cls.env['account.account.tag'].create({'name': 'Demo CEO Wages Account'}) + cls.demo_office_furniture_account = cls.env['account.account.tag'].create({'name': 'Office Furniture'}) + + # Balance Sheet + cls.xfa = cls.env['account.account'].create({ + 'code': 'X1000', + 'name': 'Fixed Assets - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_fixed_assets').id, + }) + cls.cas = cls.env['account.account'].create({ + 'code': 'X1010', + 'name': 'Current Assets - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_current_assets').id, + }) + cls.stk = cls.env['account.account'].create({ + 'code': 'X1011', + 'name': 'Purchased Stocks - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_current_assets').id, + 'tag_ids': [(6, 0, [cls.demo_stock_account.id])] + }) + cls.a_recv = cls.env['account.account'].create({ + 'code': 'X1012', + 'name': 'Debtors - (test)', + 'reconcile': True, + 'user_type_id': cls.env.ref('account.data_account_type_receivable').id, + }) + cls.ova = cls.env['account.account'].create({ + 'code': 'X1013', + 'name': 'VAT Paid- (test)', + 'user_type_id': cls.env.ref('account.data_account_type_current_assets').id, + }) + cls.bnk = cls.env['account.account'].create({ + 'code': 'X1014', + 'name': 'Bank Current Account - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_liquidity').id, + }) + cls.cash = cls.env['account.account'].create({ + 'code': 'X1015', + 'name': 'Cash - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_liquidity').id, + }) + cls.o_income = cls.env['account.account'].create({ + 'code': 'X1016', + 'name': 'Opening Income - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_other_income').id, + }) + cls.usd_bnk = cls.env['account.account'].create({ + 'code': 'X1017', + 'name': 'USD Bank Account - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_liquidity').id, + 'currency_id': cls.env.ref('base.USD').id, + }) + cls.transfer_account = cls.env['account.account'].create({ + 'code': 'X1019', + 'name': 'Internal Transfert Account - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_current_assets').id, + 'reconcile': True, + }) + cls.ncas = cls.env['account.account'].create({ + 'code': 'X1020', + 'name': 'Non-current Assets - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_non_current_assets').id, + }) + cls.prepayements = cls.env['account.account'].create({ + 'code': 'X1030', + 'name': 'Prepayments - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_prepayments').id, + }) + cls.current_liabilities = cls.env['account.account'].create({ + 'code': 'X1110', + 'name': 'Current Liabilities - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_current_liabilities').id, + }) + cls.a_pay = cls.env['account.account'].create({ + 'code': 'X1111', + 'name': 'Creditors - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_payable').id, + 'reconcile': True, + }) + cls.iva = cls.env['account.account'].create({ + 'code': 'X1112', + 'name': 'VAT Received - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_current_liabilities').id, + }) + cls.rsa = cls.env['account.account'].create({ + 'code': 'X1113', + 'name': 'Reserve and Profit/Loss - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_current_liabilities').id, + }) + cls.cas = cls.env['account.account'].create({ + 'code': 'X1120', + 'name': 'Non-current Liabilities - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_non_current_liabilities').id, + }) + cls.o_expense = cls.env['account.account'].create({ + 'code': 'X1114', + 'name': 'Opening Expense - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_expenses').id, + }) + + # Profit and Loss + cls.income_fx_income = cls.env['account.account'].create({ + 'code': 'X2010', + 'name': 'Foreign Exchange Gain - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_revenue').id, + 'reconcile': False, + }) + cls.a_sale = cls.env['account.account'].create({ + 'code': 'X2020', + 'name': 'Product Sales - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_revenue').id, + 'tag_ids': [(6, 0, [cls.env.ref('account.account_tag_operating').id])], + }) + cls.a_sale_invest = cls.env['account.account'].create({ + 'code': 'X2021', + 'name': 'Sale of Lands - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_revenue').id, + 'tag_ids': [(6, 0, [cls.env.ref('account.account_tag_investing').id])], + }) + cls.a_sale_finance = cls.env['account.account'].create({ + 'code': 'X2022', + 'name': 'Bank Accounts Interests - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_revenue').id, + 'tag_ids': [(6, 0, [cls.env.ref('account.account_tag_financing').id])], + }) + cls.a_sale_finance = cls.env['account.account'].create({ + 'code': 'X2030', + 'name': 'Cost of Goods Sold - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_direct_costs').id, + }) + cls.income_fx_expense = cls.env['account.account'].create({ + 'code': 'X2110', + 'name': 'Foreign Exchange Loss - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_expenses').id, + 'reconcile': False, + }) + cls.a_expense = cls.env['account.account'].create({ + 'code': 'X2120', + 'name': 'Expenses - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_expenses').id, + 'tag_ids': [(6, 0, [cls.env.ref('account.account_tag_operating').id])], + }) + cls.a_salary_expense = cls.env['account.account'].create({ + 'code': 'X2121', + 'name': 'Salary Expenses - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_expenses').id, + 'tag_ids': [(6, 0, [cls.env.ref('account.account_tag_operating').id])], + }) + cls.a_expense_invest = cls.env['account.account'].create({ + 'code': 'X2122', + 'name': 'Purchase of Equipments - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_fixed_assets').id, + 'tag_ids': [(6, 0, [cls.env.ref('account.account_tag_investing').id])], + }) + cls.a_expense_finance = cls.env['account.account'].create({ + 'code': 'X2123', + 'name': 'Bank Fees - (test)', + 'user_type_id': cls.env.ref('account.data_account_type_expenses').id, + 'tag_ids': [(6, 0, [cls.env.ref('account.account_tag_financing').id])], + }) + cls.a_capital = cls.env['account.account'].create({ + 'code': 'X3001', + 'name': 'Capital', + 'user_type_id': cls.env.ref('account.data_account_type_equity').id, + }) + cls.a_dividends = cls.env['account.account'].create({ + 'code': 'X3002', + 'name': 'Dividends', + 'user_type_id': cls.env.ref('account.data_account_type_equity').id, + }) + + # Properties: Product income and expense accounts, default parameters + cls.env['ir.property'].create([{ + 'name': 'property_account_receivable_id', + 'fields_id': cls.env['ir.model.fields'].search([('model', '=', 'res.partner'), ('name', '=', 'property_account_receivable_id')], limit=1).id, + 'value': 'account.account,%s' % (cls.a_recv.id), + 'company_id': cls.company.id, + }, { + 'name': 'property_account_payable_id', + 'fields_id': cls.env['ir.model.fields'].search([('model', '=', 'res.partner'), ('name', '=', 'property_account_payable_id')], limit=1).id, + 'value': 'account.account,%s' % (cls.a_pay.id), + 'company_id': cls.company.id, + }, { + 'name': 'property_account_position_id', + 'fields_id': cls.env['ir.model.fields'].search([('model', '=', 'res.partner'), ('name', '=', 'property_account_position_id')], limit=1).id, + 'value': False, + 'company_id': cls.company.id, + }, { + 'name': 'property_account_expense_categ_id', + 'fields_id': cls.env['ir.model.fields'].search([('model', '=', 'product.category'), ('name', '=', 'property_account_expense_categ_id')], limit=1).id, + 'value': 'account.account,%s' % (cls.a_expense.id), + 'company_id': cls.company.id, + }, { + 'name': 'property_account_income_categ_id', + 'fields_id': cls.env['ir.model.fields'].search([('model', '=', 'product.category'), ('name', '=', 'property_account_income_categ_id')], limit=1).id, + 'value': 'account.account,%s' % (cls.a_sale.id), + 'company_id': cls.company.id, + }]) + + # Bank Accounts + cls.bank_account = cls.env['res.partner.bank'].create({ + 'acc_number': '987654321', + 'bank_name': 'Bank', + 'partner_id': cls.company.partner_id.id, + }) + cls.bank_account_usd = cls.env['res.partner.bank'].create({ + 'acc_number': '123456789', + 'bank_name': 'Bank US', + 'partner_id': cls.company.partner_id.id, + }) + + # Account Journal + cls.sales_journal = cls.env['account.journal'].create({ + 'name': 'Customer Invoices - Test', + 'code': 'TINV', + 'type': 'sale', + 'default_credit_account_id': cls.a_sale.id, + 'default_debit_account_id': cls.a_sale.id, + 'refund_sequence': True, + }) + cls.expenses_journal = cls.env['account.journal'].create({ + 'name': 'Vendor Bills - Test', + 'code': 'TEXJ', + 'type': 'purchase', + 'default_credit_account_id': cls.a_expense.id, + 'default_debit_account_id': cls.a_expense.id, + 'refund_sequence': True, + }) + cls.bank_journal = cls.env['account.journal'].create({ + 'name': 'Bank - Test', + 'code': 'TBNK', + 'type': 'bank', + 'default_credit_account_id': cls.bnk.id, + 'default_debit_account_id': cls.bnk.id, + }) + cls.cash_journal = cls.env['account.journal'].create({ + 'name': 'Cash - Test', + 'code': 'TCSH', + 'type': 'cash', + 'profit_account_id': cls.rsa.id, + 'loss_account_id': cls.rsa.id, + 'default_credit_account_id': cls.cash.id, + 'default_debit_account_id': cls.cash.id, + }) + cls.miscellaneous_journal = cls.env['account.journal'].create({ + 'name': 'Miscellaneous - Test', + 'code': 'TMIS', + 'type': 'general', + 'show_on_dashboard': False, + }) + cls.currency_diff_journal = cls.env['account.journal'].create({ + 'name': 'Currency Difference - Test', + 'code': 'CUR', + 'type': 'general', + 'default_credit_account_id': cls.income_fx_expense.id, + 'default_debit_account_id': cls.income_fx_income.id, + 'show_on_dashboard': False, + }) + cls.bank_journal_usd = cls.env['account.journal'].create({ + 'name': 'USD Bank - Test', + 'code': 'TUBK', + 'type': 'bank', + 'default_credit_account_id': cls.usd_bnk.id, + 'default_debit_account_id': cls.usd_bnk.id, + 'bank_account_id': cls.bank_account_usd.id, + }) + + cls.company.currency_exchange_journal_id = cls.currency_diff_journal.id diff --git a/addons/account/tests/account_test_classes.py b/addons/account/tests/account_test_classes.py index 00267faddd6..8db3804321f 100644 --- a/addons/account/tests/account_test_classes.py +++ b/addons/account/tests/account_test_classes.py @@ -4,21 +4,22 @@ import logging _logger = logging.getLogger(__name__) from odoo.tests.common import HttpCase, tagged +from odoo.addons.account.tests.account_minimal_test import AccountMinimalTest - -class AccountingTestCase(HttpCase): - """ This class extends the base TransactionCase, in order to test the +class AccountingTestCase(AccountMinimalTest): + """ This class extends the base SavePoint Case, in order to test the accounting with localization setups. It is configured to run the tests after the installation of all modules, and will SKIP TESTS if it cannot find an already configured accounting (which means no localization module has been installed). """ - def setUp(self): - super(AccountingTestCase, self).setUp() - domain = [('company_id', '=', self.env.ref('base.main_company').id)] - if not self.env['account.account'].search_count(domain): + @classmethod + def setUpClass(cls): + super(AccountingTestCase, cls).setUpClass() + domain = [('company_id', '=', cls.env.company.id)] + if not cls.env['account.account'].search_count(domain): _logger.warning('Test skipped because there is no chart of account defined ...') - self.skipTest("No Chart of account found") + cls.skipTest(cls, "No Chart of account found") def ensure_account_property(self, property_name): '''Ensure the ir.property targeting an account.account passed as parameter exists. diff --git a/addons/account/tests/account_test_no_chart.py b/addons/account/tests/account_test_no_chart.py index 61cbe3e47a6..a42bc2755db 100644 --- a/addons/account/tests/account_test_no_chart.py +++ b/addons/account/tests/account_test_no_chart.py @@ -2,9 +2,9 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo.tests.common import SavepointCase, HttpCase, tagged +from odoo.addons.base.tests.common import SavepointCaseWithUserDemo - -class TestAccountNoChartCommon(SavepointCase): +class TestAccountNoChartCommon(SavepointCaseWithUserDemo): """ Some tests required to be executed at module installation, and not 'post install', like moslty of accounting tests, since a chart of account is required This test setup class provides data for test suite to make business flow working without a chart diff --git a/addons/account/tests/account_test_savepoint.py b/addons/account/tests/account_test_savepoint.py index a5e0b2f2082..180b7a868c4 100644 --- a/addons/account/tests/account_test_savepoint.py +++ b/addons/account/tests/account_test_savepoint.py @@ -1,4 +1,7 @@ # -*- coding: utf-8 -*- + +import unittest + from odoo import fields from odoo.tests.common import Form, SavepointCase from odoo.tests import tagged @@ -19,7 +22,7 @@ class AccountingSavepointCase(SavepointCase): if not chart_template: chart_template = cls.env.ref('l10n_generic_coa.configurable_chart_template', raise_if_not_found=False) if not chart_template: - cls.skipTest("Accounting Tests skipped because the user's company has no chart of accounts.") + cls.skipTest(cls, "Accounting Tests skipped because the user's company has no chart of accounts.") # Create user. user = cls.env['res.users'].create({ diff --git a/addons/account/tests/account_test_users.py b/addons/account/tests/account_test_users.py index caa17a9a821..a9b7b30545d 100644 --- a/addons/account/tests/account_test_users.py +++ b/addons/account/tests/account_test_users.py @@ -5,30 +5,31 @@ class AccountTestUsers(AccountingTestCase): """Tests for diffrent type of user 'Accountant/Adviser' and added groups""" - def setUp(self): - super(AccountTestUsers, self).setUp() - self.res_user_model = self.env['res.users'] - self.main_company = self.env.ref('base.main_company') - self.main_partner = self.env.ref('base.main_partner') - self.main_bank = self.env.ref('base.res_bank_1') - res_users_account_user = self.env.ref('account.group_account_invoice') - res_users_account_manager = self.env.ref('account.group_account_manager') - partner_manager = self.env.ref('base.group_partner_manager') - self.tax_model = self.env['account.tax'] - self.account_model = self.env['account.account'] - self.account_type_model = self.env['account.account.type'] - self.currency_euro = self.env.ref('base.EUR') + @classmethod + def setUpClass(cls): + super(AccountTestUsers, cls).setUpClass() + cls.res_user_model = cls.env['res.users'] + cls.main_company = cls.env.ref('base.main_company') + cls.main_partner = cls.env.ref('base.main_partner') + cls.main_bank = cls.env.ref('base.res_bank_1') + res_users_account_user = cls.env.ref('account.group_account_invoice') + res_users_account_manager = cls.env.ref('account.group_account_manager') + partner_manager = cls.env.ref('base.group_partner_manager') + cls.tax_model = cls.env['account.tax'] + cls.account_model = cls.env['account.account'] + cls.account_type_model = cls.env['account.account.type'] + cls.currency_euro = cls.env.ref('base.EUR') - self.account_user = self.res_user_model.with_context({'no_reset_password': True}).create(dict( + cls.account_user = cls.res_user_model.with_context({'no_reset_password': True}).create(dict( name="Accountant", - company_id=self.main_company.id, + company_id=cls.main_company.id, login="acc", email="accountuser@yourcompany.com", groups_id=[(6, 0, [res_users_account_user.id, partner_manager.id])] )) - self.account_manager = self.res_user_model.with_context({'no_reset_password': True}).create(dict( + cls.account_manager = cls.res_user_model.with_context({'no_reset_password': True}).create(dict( name="Adviser", - company_id=self.main_company.id, + company_id=cls.main_company.id, login="fm", email="accountmanager@yourcompany.com", groups_id=[(6, 0, [res_users_account_manager.id, partner_manager.id])] diff --git a/addons/account/tests/test_account_journal_dashboard.py b/addons/account/tests/test_account_journal_dashboard.py index 0d6e88e30bc..19a7bbdab59 100644 --- a/addons/account/tests/test_account_journal_dashboard.py +++ b/addons/account/tests/test_account_journal_dashboard.py @@ -18,14 +18,25 @@ class TestAccountJournalDashboard(AccountTestUsers): 'type': 'sale', }) + res_partner_3 = self.env['res.partner'].create({ + 'name': 'Gemini Furniture', + }) + + product_product_1 = self.env['product.product'].create({ + 'name': 'Virtual Interior Design', + 'standard_price': 20.5, + 'list_price': 30.75, + 'type': 'service', + }) + invoice = self.env['account.move'].create({ 'type': 'out_invoice', 'journal_id': journal.id, - 'partner_id': self.env.ref('base.res_partner_3').id, + 'partner_id': res_partner_3.id, 'invoice_date': date_invoice, 'date': date_invoice, 'invoice_line_ids': [(0, 0, { - 'product_id': self.env.ref('product.product_product_1').id, + 'product_id': product_product_1.id, 'quantity': 40.0, 'name': 'product test 1', 'discount': 10.00, @@ -35,11 +46,11 @@ class TestAccountJournalDashboard(AccountTestUsers): refund = self.env['account.move'].create({ 'type': 'out_refund', 'journal_id': journal.id, - 'partner_id': self.env.ref('base.res_partner_3').id, + 'partner_id': res_partner_3.id, 'invoice_date': '2019-01-21', 'date': date_invoice, 'invoice_line_ids': [(0, 0, { - 'product_id': self.env.ref('product.product_product_1').id, + 'product_id': product_product_1.id, 'quantity': 1.0, 'name': 'product test 1', 'price_unit': 13.3, diff --git a/addons/account/tests/test_account_move_partner_count.py b/addons/account/tests/test_account_move_partner_count.py index 203c4dc0493..de3d8ae7fa7 100644 --- a/addons/account/tests/test_account_move_partner_count.py +++ b/addons/account/tests/test_account_move_partner_count.py @@ -51,25 +51,3 @@ class TestAccountMovePartnerCount(TransactionCase): self.journal.with_env(env).unlink() self.account_income.with_env(env).unlink() self.partner.with_env(env).unlink() - - def test_account_move_count(self): - # T2 create and post account move - with self.registry.cursor() as cr: - env = self.env(cr=cr) - self.move.with_env(env).post() - partner = self.partner.with_env(env) - self.assertEqual(partner.supplier_rank, 0) - self.assertEqual(partner.customer_rank, 1) - - def test_account_move_count_concurrent(self): - # T2 Lock the partner row - with self.registry.cursor() as cr: - cr.execute("""SELECT id FROM res_partner WHERE id = %s FOR UPDATE""" % self.partner.id) - - # T3 concurrently posts account move and tries to update partner - with self.registry.cursor() as cr: - env = self.env(cr=cr) - self.move.with_env(env).state = 'posted' - - self.assertEqual(self.partner.with_env(env).customer_rank, - 0, "It should not wait the concurrent transaction for the update") diff --git a/addons/account/tests/test_account_move_rounding.py b/addons/account/tests/test_account_move_rounding.py index 63a3bebc2be..9ea27cb74bb 100644 --- a/addons/account/tests/test_account_move_rounding.py +++ b/addons/account/tests/test_account_move_rounding.py @@ -7,33 +7,34 @@ from odoo.tests import tagged @tagged('post_install', '-at_install') class TestAccountMoveRounding(AccountingTestCase): - def setUp(self): - super(TestAccountMoveRounding, self).setUp() - self.currency = self.env['res.currency'].create({ + @classmethod + def setUpClass(cls): + super(TestAccountMoveRounding, cls).setUpClass() + cls.currency = cls.env['res.currency'].create({ 'name': "RAM", 'symbol': "🐏", 'rounding': 0.01, }) - self.company = self.env['res.company'].create({ + cls.company = cls.env['res.company'].create({ 'name': "SHEEP", - 'currency_id': self.currency.id, + 'currency_id': cls.currency.id, }) - self.account_type = self.env['account.account.type'].create( - {'name': 'BAAH', - 'internal_group': 'asset', - 'type': 'receivable' + cls.account_type = cls.env['account.account.type'].create({ + 'name': 'BAAH', + 'internal_group': 'asset', + 'type': 'receivable' }) - self.journal = self.env['account.journal'].create({ - 'company_id': self.company.id, + cls.journal = cls.env['account.journal'].create({ + 'company_id': cls.company.id, 'name': 'LAMB', - 'code': 'L', + 'code': 'LL', 'type': 'purchase', }) - self.account = self.env['account.account'].create({ - 'company_id': self.company.id, + cls.account = cls.env['account.account'].create({ + 'company_id': cls.company.id, 'name': 'EWE', - 'code': 'E', - 'user_type_id': self.account_type.id, + 'code': 'EE', + 'user_type_id': cls.account_type.id, 'reconcile': True, }) diff --git a/addons/account/tests/test_account_onboarding.py b/addons/account/tests/test_account_onboarding.py index c4839a35a32..b1f0d4e0f07 100644 --- a/addons/account/tests/test_account_onboarding.py +++ b/addons/account/tests/test_account_onboarding.py @@ -1,18 +1,24 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + from odoo.tests.common import tagged, HttpCase +from odoo import tools @tagged('-at_install', 'post_install', 'document_layout') class TestAccountDocumentLayout(HttpCase): def test_render_account_document_layout(self): - report_layout = self.env.ref('web.report_layout_standard') - main_company = self.env.ref('base.main_company') - main_company.write({ - 'primary_color': '#123456', - 'secondary_color': '#789101', - 'external_report_layout_id': report_layout.view_id.id, - }) - self.env.ref('account.account_invoices_without_payment').write({ - 'report_type': 'qweb-html', - }) - self.start_tour("/web", 'account_render_report', login='admin', timeout=200) + # YTI TODO: Adapt this tour without demo data + if not tools.config["without_demo"]: + report_layout = self.env.ref('web.report_layout_standard') + main_company = self.env.ref('base.main_company') + main_company.write({ + 'primary_color': '#123456', + 'secondary_color': '#789101', + 'external_report_layout_id': report_layout.view_id.id, + }) + self.env.ref('account.account_invoices_without_payment').write({ + 'report_type': 'qweb-html', + }) + self.start_tour("/web", 'account_render_report', login='admin', timeout=200) diff --git a/addons/account/tests/test_bank_statement_reconciliation.py b/addons/account/tests/test_bank_statement_reconciliation.py index 43e38bf1bca..6061f553644 100644 --- a/addons/account/tests/test_bank_statement_reconciliation.py +++ b/addons/account/tests/test_bank_statement_reconciliation.py @@ -5,13 +5,14 @@ from odoo.tests import tagged @tagged('post_install', '-at_install') class TestBankStatementReconciliation(AccountingTestCase): - def setUp(self): - super(TestBankStatementReconciliation, self).setUp() - self.bs_model = self.env['account.bank.statement'] - self.bsl_model = self.env['account.bank.statement.line'] - self.partner = self.env['res.partner'].create({'name': 'test'}) - self.currency_usd_id = self.env.ref("base.USD").id - self.currency_euro_id = self.env.ref("base.EUR").id + @classmethod + def setUpClass(cls): + super(TestBankStatementReconciliation, cls).setUpClass() + cls.bs_model = cls.env['account.bank.statement'] + cls.bsl_model = cls.env['account.bank.statement.line'] + cls.partner = cls.env['res.partner'].create({'name': 'test'}) + cls.currency_usd_id = cls.env.ref("base.USD").id + cls.currency_euro_id = cls.env.ref("base.EUR").id def test_full_reconcile(self): self._reconcile_invoice_with_statement('pay_val') diff --git a/addons/account/tests/test_fiscal_position.py b/addons/account/tests/test_fiscal_position.py index 4b19431806b..a8148fc9360 100644 --- a/addons/account/tests/test_fiscal_position.py +++ b/addons/account/tests/test_fiscal_position.py @@ -1,55 +1,60 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + from odoo.tests import common -class TestFiscalPosition(common.TransactionCase): + +class TestFiscalPosition(common.SavepointCase): """Tests for fiscal positions in auto apply (account.fiscal.position). If a partner has a vat number, the fiscal positions with "vat_required=True" are preferred. """ - def setUp(self): - super(TestFiscalPosition, self).setUp() - self.fp = self.env['account.fiscal.position'] + @classmethod + def setUpClass(cls): + super(TestFiscalPosition, cls).setUpClass() + cls.fp = cls.env['account.fiscal.position'] # reset any existing FP - self.fp.search([]).write({'auto_apply': False}) + cls.fp.search([]).write({'auto_apply': False}) - self.res_partner = self.env['res.partner'] - self.be = be = self.env.ref('base.be') - self.fr = fr = self.env.ref('base.fr') - self.mx = mx = self.env.ref('base.mx') - self.eu = eu = self.env.ref('base.europe') - self.state_fr = self.env['res.country.state'].create(dict( + cls.res_partner = cls.env['res.partner'] + cls.be = be = cls.env.ref('base.be') + cls.fr = fr = cls.env.ref('base.fr') + cls.mx = mx = cls.env.ref('base.mx') + cls.eu = eu = cls.env.ref('base.europe') + cls.state_fr = cls.env['res.country.state'].create(dict( name="State", code="ST", country_id=fr.id)) - self.jc = self.res_partner.create(dict( + cls.jc = cls.res_partner.create(dict( name="JCVD", vat="BE0477472701", country_id=be.id)) - self.ben = self.res_partner.create(dict( + cls.ben = cls.res_partner.create(dict( name="BP", country_id=be.id)) - self.george = self.res_partner.create(dict( + cls.george = cls.res_partner.create(dict( name="George", vat="BE0477472701", country_id=fr.id)) - self.alberto = self.res_partner.create(dict( + cls.alberto = cls.res_partner.create(dict( name="Alberto", vat="BE0477472701", country_id=mx.id)) - self.be_nat = self.fp.create(dict( + cls.be_nat = cls.fp.create(dict( name="BE-NAT", auto_apply=True, country_id=be.id, vat_required=False, sequence=10)) - self.fr_b2c = self.fp.create(dict( + cls.fr_b2c = cls.fp.create(dict( name="EU-VAT-FR-B2C", auto_apply=True, country_id=fr.id, vat_required=False, sequence=40)) - self.fr_b2b = self.fp.create(dict( + cls.fr_b2b = cls.fp.create(dict( name="EU-VAT-FR-B2B", auto_apply=True, country_id=fr.id, diff --git a/addons/account/tests/test_invoice_taxes.py b/addons/account/tests/test_invoice_taxes.py index 90e3a385e3d..0d4df086eba 100644 --- a/addons/account/tests/test_invoice_taxes.py +++ b/addons/account/tests/test_invoice_taxes.py @@ -1,22 +1,26 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.addons.base.tests.common import SavepointCaseWithUserDemo from odoo.addons.account.tests.account_test_classes import AccountingTestCase from odoo.tests.common import Form from odoo.tests import tagged @tagged('post_install', '-at_install') -class TestInvoiceTaxes(AccountingTestCase): +class TestInvoiceTaxes(AccountingTestCase, SavepointCaseWithUserDemo): - def setUp(self): - super(TestInvoiceTaxes, self).setUp() + @classmethod + def setUpClass(cls): + super(TestInvoiceTaxes, cls).setUpClass() - self.percent_tax_1 = self.env['account.tax'].create({ + cls.percent_tax_1 = cls.env['account.tax'].create({ 'name': '21%', 'amount_type': 'percent', 'amount': 21, 'sequence': 10, }) - self.percent_tax_1_incl = self.env['account.tax'].create({ + cls.percent_tax_1_incl = cls.env['account.tax'].create({ 'name': '21% incl', 'amount_type': 'percent', 'amount': 21, @@ -24,19 +28,19 @@ class TestInvoiceTaxes(AccountingTestCase): 'include_base_amount': True, 'sequence': 20, }) - self.percent_tax_2 = self.env['account.tax'].create({ + cls.percent_tax_2 = cls.env['account.tax'].create({ 'name': '12%', 'amount_type': 'percent', 'amount': 12, 'sequence': 30, }) - self.group_tax = self.env['account.tax'].create({ + cls.group_tax = cls.env['account.tax'].create({ 'name': 'group 12% + 21%', 'amount_type': 'group', 'amount': 21, 'children_tax_ids': [ - (4, self.percent_tax_1_incl.id), - (4, self.percent_tax_2.id) + (4, cls.percent_tax_1_incl.id), + (4, cls.percent_tax_2.id) ], 'sequence': 40, }) @@ -48,7 +52,7 @@ class TestInvoiceTaxes(AccountingTestCase): ''' self_ctx = self.env['account.move'].with_context(default_type=inv_type) invoice_form = Form(self_ctx) - invoice_form.partner_id = self.env.ref('base.partner_demo') + invoice_form.partner_id = self.partner_demo for amount, taxes in taxes_per_line: with invoice_form.invoice_line_ids.new() as invoice_line_form: diff --git a/addons/account/tests/test_payment.py b/addons/account/tests/test_payment.py index d501ada8798..8f560635e60 100644 --- a/addons/account/tests/test_payment.py +++ b/addons/account/tests/test_payment.py @@ -1,3 +1,6 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + from odoo.addons.account.tests.account_test_classes import AccountingTestCase from odoo.tests import tagged from odoo.tests.common import Form @@ -8,21 +11,29 @@ import time class TestPayment(AccountingTestCase): def setUp(self): + self.env.ref('base.main_company').currency_id = self.env.ref('base.USD') super(TestPayment, self).setUp() self.register_payments_model = self.env['account.payment.register'].with_context(active_model='account.move') self.payment_model = self.env['account.payment'] self.acc_bank_stmt_model = self.env['account.bank.statement'] self.acc_bank_stmt_line_model = self.env['account.bank.statement.line'] - self.partner_agrolait = self.env.ref("base.res_partner_2") - self.partner_china_exp = self.env.ref("base.res_partner_3") + self.partner_agrolait = self.env['res.partner'].create({'name': 'Agrolait', 'is_company': True}) + self.partner_china_exp = self.env['res.partner'].create({'name': 'China Export', 'is_company': True}) self.currency_chf_id = self.env.ref("base.CHF").id self.currency_usd_id = self.env.ref("base.USD").id self.currency_eur_id = self.env.ref("base.EUR").id company = self.env.ref('base.main_company') self.cr.execute("UPDATE res_company SET currency_id = %s WHERE id = %s", [self.currency_eur_id, company.id]) - self.product = self.env.ref("product.product_product_4") + + self.product = self.env['product.product'].create({ + 'name': 'Product Product 4', + 'standard_price': 500.0, + 'list_price': 750.0, + 'type': 'consu', + 'categ_id': self.env.ref('product.product_category_all').id, + }) self.payment_method_manual_in = self.env.ref("account.account_payment_method_manual_in") self.payment_method_manual_out = self.env.ref("account.account_payment_method_manual_out") @@ -38,12 +49,30 @@ class TestPayment(AccountingTestCase): self.bank_journal_usd = self.env['account.journal'].create({'name': 'Bank US', 'type': 'bank', 'code': 'BNK68', 'currency_id': self.currency_usd_id}) self.account_usd = self.bank_journal_usd.default_debit_account_id - self.transfer_account = self.env['res.users'].browse(self.env.uid).company_id.transfer_account_id - self.diff_income_account = self.env['res.users'].browse(self.env.uid).company_id.income_currency_exchange_account_id - self.diff_expense_account = self.env['res.users'].browse(self.env.uid).company_id.expense_currency_exchange_account_id + if not self.env.user.company_id.transfer_account_id: + self.env.user.company_id.transfer_account_id = self.usd_bnk + self.transfer_account = self.env.user.company_id.transfer_account_id + self.diff_income_account = self.env.user.company_id.income_currency_exchange_account_id + self.diff_expense_account = self.env.user.company_id.expense_currency_exchange_account_id self.form_payment = Form(self.env['account.payment']) + self.env['res.currency.rate'].create([ + { + 'currency_id': self.env.ref('base.EUR').id, + 'name': '2010-01-02', + 'rate': 1.0, + }, { + 'currency_id': self.env.ref('base.USD').id, + 'name': '2010-01-02', + 'rate': 1.2834, + }, { + 'currency_id': self.env.ref('base.USD').id, + 'name': time.strftime('%Y-06-05'), + 'rate': 1.5289, + } + ]) + def create_invoice(self, amount=100, type='out_invoice', currency_id=None, partner=None, account_id=None): """ Returns an open invoice """ invoice = self.env['account.move'].create({ @@ -130,6 +159,12 @@ class TestPayment(AccountingTestCase): ]) def test_payment_chf_journal_usd(self): + self.env['res.currency.rate'].create({ + 'rate': 1.3086, + 'currency_id': self.currency_chf_id, + 'name': '2010-01-02', + }) + payment = self.payment_model.create({ 'payment_date': time.strftime('%Y') + '-07-15', 'payment_type': 'outbound', diff --git a/addons/account/tests/test_portal_attachment.py b/addons/account/tests/test_portal_attachment.py index 584d8e8b259..7598ca2b98f 100644 --- a/addons/account/tests/test_portal_attachment.py +++ b/addons/account/tests/test_portal_attachment.py @@ -14,6 +14,13 @@ class TestUi(tests.HttpCase): def test_01_portal_attachment(self): """Test the portal chatter attachment route.""" + miscellaneous_journal = self.env['account.journal'].create({ + 'name': 'Miscellaneous - Test', + 'code': 'TMISC', + 'type': 'general', + 'show_on_dashboard': False, + }) + base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') # For this test we need a parent document with an access_token field # (in this case from portal.mixin) and also inheriting mail.thread. diff --git a/addons/account/tests/test_reconciliation.py b/addons/account/tests/test_reconciliation.py index 9c754ce33e4..0877d1368bc 100644 --- a/addons/account/tests/test_reconciliation.py +++ b/addons/account/tests/test_reconciliation.py @@ -1,4 +1,7 @@ -from odoo import api, fields +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, tools from odoo.addons.account.tests.account_test_classes import AccountingTestCase from odoo.exceptions import UserError from odoo.tests import Form, tagged @@ -6,7 +9,6 @@ import time from datetime import timedelta import unittest - # TODO in master # The name of this class should be TestReconciliationHelpers class TestReconciliation(AccountingTestCase): @@ -17,94 +19,115 @@ class TestReconciliation(AccountingTestCase): the result will be balanced. """ - def setUp(self): - super(TestReconciliation, self).setUp() - self.acc_bank_stmt_model = self.env['account.bank.statement'] - self.acc_bank_stmt_line_model = self.env['account.bank.statement.line'] - self.res_currency_model = self.registry('res.currency') - self.res_currency_rate_model = self.registry('res.currency.rate') + @classmethod + def setUpClass(cls): + super(TestReconciliation, cls).setUpClass() + cls.company = cls.env['res.company'].create({ + 'name': 'A test company', + 'currency_id': cls.env.ref('base.EUR').id + }) + cls.env.user.company_id = cls.company + # Generate minimal data for my new company + cls.create_accounting_minimal_data() - self.partner_agrolait = self.env.ref("base.res_partner_2") - self.partner_agrolait_id = self.partner_agrolait.id - self.currency_swiss_id = self.env.ref("base.CHF").id - self.currency_usd_id = self.env.ref("base.USD").id - self.currency_euro_id = self.env.ref("base.EUR").id - company = self.env.ref('base.main_company') - self.cr.execute("UPDATE res_company SET currency_id = %s WHERE id = %s", [self.currency_euro_id, company.id]) - self.account_rcv = self.partner_agrolait.property_account_receivable_id or self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_account_type_receivable').id)], limit=1) - self.account_rsa = self.partner_agrolait.property_account_payable_id or self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_account_type_payable').id)], limit=1) - self.product = self.env.ref("product.product_product_4") + cls.acc_bank_stmt_model = cls.env['account.bank.statement'] + cls.acc_bank_stmt_line_model = cls.env['account.bank.statement.line'] + cls.res_currency_model = cls.registry('res.currency') + cls.res_currency_rate_model = cls.registry('res.currency.rate') - self.bank_journal_euro = self.env['account.journal'].create({'name': 'Bank', 'type': 'bank', 'code': 'BNK67'}) - self.account_euro = self.bank_journal_euro.default_debit_account_id + cls.partner_agrolait = cls.env['res.partner'].create({ + 'name': 'Deco Addict', + 'is_company': True, + 'country_id': cls.env.ref('base.us').id, + }) + cls.partner_agrolait_id = cls.partner_agrolait.id + cls.currency_swiss_id = cls.env.ref("base.CHF").id + cls.currency_usd_id = cls.env.ref("base.USD").id + cls.currency_euro_id = cls.env.ref("base.EUR").id + # YTI FIXME Some of those lines should be useless now + cls.cr.execute("UPDATE res_company SET currency_id = %s WHERE id = %s", [cls.currency_euro_id, cls.company.id]) + cls.account_rcv = cls.partner_agrolait.property_account_receivable_id or cls.env['account.account'].search([('user_type_id', '=', cls.env.ref('account.data_account_type_receivable').id)], limit=1) + cls.account_rsa = cls.partner_agrolait.property_account_payable_id or cls.env['account.account'].search([('user_type_id', '=', cls.env.ref('account.data_account_type_payable').id)], limit=1) + cls.product = cls.env['product.product'].create({ + 'name': 'Product Product 4', + 'standard_price': 500.0, + 'list_price': 750.0, + 'type': 'consu', + 'categ_id': cls.env.ref('product.product_category_all').id, + }) - self.bank_journal_usd = self.env['account.journal'].create({'name': 'Bank US', 'type': 'bank', 'code': 'BNK68', 'currency_id': self.currency_usd_id}) - self.account_usd = self.bank_journal_usd.default_debit_account_id + cls.bank_journal_euro = cls.env['account.journal'].create({'name': 'Bank', 'type': 'bank', 'code': 'BNK67'}) + cls.account_euro = cls.bank_journal_euro.default_debit_account_id - self.fx_journal = self.env['res.users'].browse(self.env.uid).company_id.currency_exchange_journal_id - self.diff_income_account = self.env['res.users'].browse(self.env.uid).company_id.income_currency_exchange_account_id - self.diff_expense_account = self.env['res.users'].browse(self.env.uid).company_id.expense_currency_exchange_account_id + cls.bank_journal_usd = cls.env['account.journal'].create({'name': 'Bank US', 'type': 'bank', 'code': 'BNK68', 'currency_id': cls.currency_usd_id}) + cls.account_usd = cls.bank_journal_usd.default_debit_account_id - self.inbound_payment_method = self.env['account.payment.method'].create({ + cls.fx_journal = cls.env['res.users'].browse(cls.env.uid).company_id.currency_exchange_journal_id + cls.diff_income_account = cls.env['res.users'].browse(cls.env.uid).company_id.income_currency_exchange_account_id + cls.diff_expense_account = cls.env['res.users'].browse(cls.env.uid).company_id.expense_currency_exchange_account_id + + cls.inbound_payment_method = cls.env['account.payment.method'].create({ 'name': 'inbound', 'code': 'IN', 'payment_type': 'inbound', }) - self.expense_account = self.env['account.account'].create({ + cls.expense_account = cls.env['account.account'].create({ 'name': 'EXP', 'code': 'EXP', - 'user_type_id': self.env.ref('account.data_account_type_expenses').id, - 'company_id': company.id, + 'user_type_id': cls.env.ref('account.data_account_type_expenses').id, + 'company_id': cls.company.id, }) # cash basis intermediary account - self.tax_waiting_account = self.env['account.account'].create({ + cls.tax_waiting_account = cls.env['account.account'].create({ 'name': 'TAX_WAIT', 'code': 'TWAIT', - 'user_type_id': self.env.ref('account.data_account_type_current_liabilities').id, + 'user_type_id': cls.env.ref('account.data_account_type_current_liabilities').id, 'reconcile': True, - 'company_id': company.id, + 'company_id': cls.company.id, }) # cash basis final account - self.tax_final_account = self.env['account.account'].create({ + cls.tax_final_account = cls.env['account.account'].create({ 'name': 'TAX_TO_DEDUCT', 'code': 'TDEDUCT', - 'user_type_id': self.env.ref('account.data_account_type_current_assets').id, - 'company_id': company.id, + 'user_type_id': cls.env.ref('account.data_account_type_current_assets').id, + 'company_id': cls.company.id, }) - self.tax_base_amount_account = self.env['account.account'].create({ + cls.tax_base_amount_account = cls.env['account.account'].create({ 'name': 'TAX_BASE', 'code': 'TBASE', - 'user_type_id': self.env.ref('account.data_account_type_current_assets').id, - 'company_id': company.id, + 'user_type_id': cls.env.ref('account.data_account_type_current_assets').id, + 'company_id': cls.company.id, }) # Journals - self.purchase_journal = self.env['account.journal'].create({ + cls.purchase_journal = cls.env['account.journal'].create({ 'name': 'purchase', 'code': 'PURCH', 'type': 'purchase', + 'default_credit_account_id': cls.a_expense.id, + 'default_debit_account_id': cls.a_expense.id, }) - self.cash_basis_journal = self.env['account.journal'].create({ + cls.cash_basis_journal = cls.env['account.journal'].create({ 'name': 'CABA', 'code': 'CABA', 'type': 'general', }) - self.general_journal = self.env['account.journal'].create({ + cls.general_journal = cls.env['account.journal'].create({ 'name': 'general', 'code': 'GENE', 'type': 'general', }) # Tax Cash Basis - self.tax_cash_basis = self.env['account.tax'].create({ + cls.tax_cash_basis = cls.env['account.tax'].create({ 'name': 'cash basis 20%', 'type_tax_use': 'purchase', - 'company_id': company.id, + 'company_id': cls.company.id, 'amount': 20, 'tax_exigibility': 'on_payment', - 'cash_basis_transition_account_id': self.tax_waiting_account.id, - 'cash_basis_base_account_id': self.tax_base_amount_account.id, + 'cash_basis_transition_account_id': cls.tax_waiting_account.id, + 'cash_basis_base_account_id': cls.tax_base_amount_account.id, 'invoice_repartition_line_ids': [ (0,0, { 'factor_percent': 100, @@ -114,7 +137,7 @@ class TestReconciliation(AccountingTestCase): (0,0, { 'factor_percent': 100, 'repartition_type': 'tax', - 'account_id': self.tax_final_account.id, + 'account_id': cls.tax_final_account.id, }), ], 'refund_repartition_line_ids': [ @@ -126,13 +149,29 @@ class TestReconciliation(AccountingTestCase): (0,0, { 'factor_percent': 100, 'repartition_type': 'tax', - 'account_id': self.tax_final_account.id, + 'account_id': cls.tax_final_account.id, }), ], }) + cls.env['res.currency.rate'].create([ + { + 'currency_id': cls.env.ref('base.EUR').id, + 'name': '2010-01-02', + 'rate': 1.0, + }, { + 'currency_id': cls.env.ref('base.USD').id, + 'name': '2010-01-02', + 'rate': 1.2834, + }, { + 'currency_id': cls.env.ref('base.USD').id, + 'name': time.strftime('%Y-06-05'), + 'rate': 1.5289, + } + ]) def _create_invoice(self, type='out_invoice', invoice_amount=50, currency_id=None, partner_id=None, date_invoice=None, payment_term_id=False, auto_validate=False): date_invoice = date_invoice or time.strftime('%Y') + '-07-01' + invoice_vals = { 'type': type, 'partner_id': partner_id or self.partner_agrolait_id, @@ -258,6 +297,11 @@ class TestReconciliationExec(TestReconciliation): ]) def test_statement_usd_invoice_chf_transaction_chf(self): + self.env['res.currency.rate'].create({ + 'rate': 1.3086, + 'currency_id': self.env.ref('base.CHF').id, + 'name': '2010-01-02', + }) customer_move_lines, supplier_move_lines = self.make_customer_and_supplier_flows(self.currency_swiss_id, 50, self.bank_journal_usd, 42, 50, self.currency_swiss_id) self.assertRecordValues(customer_move_lines, [ {'debit': 0.0, 'credit': 27.47, 'amount_currency': -50, 'currency_id': self.currency_swiss_id}, @@ -676,7 +720,7 @@ class TestReconciliationExec(TestReconciliation): # Balance Debit = 18.75 # Counterpart Credit goes in Exchange diff - dest_journal_id = self.env['account.journal'].search([('type', '=', 'purchase'), ('company_id', '=', self.env.ref('base.main_company').id)], limit=1) + dest_journal_id = self.env['account.journal'].search([('type', '=', 'purchase'), ('company_id', '=', self.company.id)], limit=1) self.bank_journal_euro.write({'default_debit_account_id': self.account_rsa.id, 'default_credit_account_id': self.account_rsa.id}) @@ -686,17 +730,17 @@ class TestReconciliationExec(TestReconciliation): self.env['res.currency.rate'].create({'name': time.strftime('%Y') + '-' + '07' + '-01', 'rate': 0.5, 'currency_id': self.currency_usd_id, - 'company_id': self.env.ref('base.main_company').id}) + 'company_id': self.company.id}) self.env['res.currency.rate'].create({'name': time.strftime('%Y') + '-' + '08' + '-01', 'rate': 0.75, 'currency_id': self.currency_usd_id, - 'company_id': self.env.ref('base.main_company').id}) + 'company_id': self.company.id}) self.env['res.currency.rate'].create({'name': time.strftime('%Y') + '-' + '09' + '-01', 'rate': 0.80, 'currency_id': self.currency_usd_id, - 'company_id': self.env.ref('base.main_company').id}) + 'company_id': self.company.id}) # Preparing Invoices (from vendor) invoice_a = self.env['account.move'].with_context(default_type='in_invoice').create({ @@ -727,7 +771,7 @@ class TestReconciliationExec(TestReconciliation): 'amount': 25, 'currency_id': self.currency_usd_id, 'journal_id': self.bank_journal_euro.id, - 'company_id': self.env.ref('base.main_company').id, + 'company_id': self.company.id, 'payment_date': time.strftime('%Y') + '-' + '07' + '-01', 'partner_id': self.partner_agrolait_id, 'payment_method_id': self.env.ref('account.account_payment_method_manual_out').id, @@ -739,7 +783,7 @@ class TestReconciliationExec(TestReconciliation): 'amount': 50, 'currency_id': self.currency_usd_id, 'journal_id': self.bank_journal_euro.id, - 'company_id': self.env.ref('base.main_company').id, + 'company_id': self.company.id, 'payment_date': time.strftime('%Y') + '-' + '08' + '-01', 'partner_id': self.partner_agrolait_id, 'payment_method_id': self.env.ref('account.account_payment_method_manual_out').id, @@ -751,7 +795,7 @@ class TestReconciliationExec(TestReconciliation): 'amount': 25, 'currency_id': self.currency_usd_id, 'journal_id': self.bank_journal_euro.id, - 'company_id': self.env.ref('base.main_company').id, + 'company_id': self.company.id, 'payment_date': time.strftime('%Y') + '-' + '09' + '-01', 'partner_id': self.partner_agrolait_id, 'payment_method_id': self.env.ref('account.account_payment_method_manual_out').id, @@ -840,13 +884,13 @@ class TestReconciliationExec(TestReconciliation): 'name': time.strftime('%Y') + '-07-01', 'rate': 1.0, 'currency_id': self.currency_usd_id, - 'company_id': self.env.ref('base.main_company').id + 'company_id': self.company.id }) self.env['res.currency.rate'].create({ 'name': time.strftime('%Y') + '-08-01', 'rate': 0.5, 'currency_id': self.currency_usd_id, - 'company_id': self.env.ref('base.main_company').id + 'company_id': self.company.id }) inv = self.create_invoice(invoice_amount=111, currency_id=self.currency_usd_id) payment = self.env['account.payment'].create({ @@ -946,13 +990,13 @@ class TestReconciliationExec(TestReconciliation): 'name': time.strftime('%Y') + '-07-01', 'rate': 1.0, 'currency_id': self.currency_usd_id, - 'company_id': self.env.ref('base.main_company').id + 'company_id': self.company.id }) self.env['res.currency.rate'].create({ 'name': time.strftime('%Y') + '-08-01', 'rate': 0.5, 'currency_id': self.currency_usd_id, - 'company_id': self.env.ref('base.main_company').id + 'company_id': self.company.id }) inv = self.create_invoice(invoice_amount=111, currency_id=self.currency_usd_id) payment = self.env['account.payment'].create({ @@ -994,7 +1038,7 @@ class TestReconciliationExec(TestReconciliation): #### dest_journal_id = self.env['account.journal'].search( [('type', '=', 'purchase'), - ('company_id', '=', self.env.ref('base.main_company').id)], + ('company_id', '=', self.company.id)], limit=1) # Delete any old rate - to make sure that we use the ones we need. @@ -1104,7 +1148,7 @@ class TestReconciliationExec(TestReconciliation): # one is subject to a cash basis tax # the other is not subject to tax - company = self.env.ref('base.main_company') + company = self.company company.tax_cash_basis_journal_id = self.cash_basis_journal purchase_move = self.env['account.move'].create({ @@ -1196,7 +1240,7 @@ class TestReconciliationExec(TestReconciliation): # with 2 payment terms # And partial payment not martching any payment term - company = self.env.ref('base.main_company') + company = self.company company.tax_cash_basis_journal_id = self.cash_basis_journal tax_cash_basis10percent = self.tax_cash_basis.copy({'amount': 10}) tax_waiting_account10 = self.tax_waiting_account.copy({ @@ -1395,7 +1439,7 @@ class TestReconciliationExec(TestReconciliation): Taxes -848.16 USD 0.00 17,094.66 """ - company = self.env.ref('base.main_company') + company = self.company company.country_id = self.ref('base.us') company.tax_cash_basis_journal_id = self.cash_basis_journal @@ -1558,7 +1602,7 @@ class TestReconciliationExec(TestReconciliation): Taxes -848.16 USD 0.00 17,094.66 """ - company = self.env.ref('base.main_company') + company = self.company company.country_id = self.ref('base.us') company.tax_cash_basis_journal_id = self.cash_basis_journal @@ -1698,7 +1742,7 @@ class TestReconciliationExec(TestReconciliation): .debit, 17094.66) def test_reconciliation_cash_basis_revert(self): - company = self.env.ref('base.main_company') + company = self.company company.tax_cash_basis_journal_id = self.cash_basis_journal tax_cash_basis10percent = self.tax_cash_basis.copy({'amount': 10}) self.tax_waiting_account.reconcile = True @@ -1763,7 +1807,7 @@ class TestReconciliationExec(TestReconciliation): self.assertEqual(reverted_expected.full_reconcile_id, inv_line.full_reconcile_id) def test_reconciliation_revert_future(self): - company = self.env.ref('base.main_company') + company = self.company company.tax_cash_basis_journal_id = self.cash_basis_journal tax_cash_basis10percent = self.tax_cash_basis.copy({'amount': 10}) self.tax_waiting_account.reconcile = True @@ -1832,6 +1876,7 @@ class TestReconciliationExec(TestReconciliation): self.assertEqual(reverse_move.date, reverse_date) def test_reconciliation_cash_basis_foreign_currency_low_values(self): + self.company.tax_cash_basis_journal_id = self.cash_basis_journal journal = self.env['account.journal'].create({ 'name': 'Bank', 'type': 'bank', 'code': 'THE', 'currency_id': self.currency_usd_id, @@ -1842,7 +1887,7 @@ class TestReconciliationExec(TestReconciliation): 'name': time.strftime('%Y-01-01'), 'rate': 1/17.0, 'currency_id': self.currency_usd_id, - 'company_id': self.env.ref('base.main_company').id, + 'company_id': self.company.id, }) move_form = Form(self.env['account.move'].with_context(default_type='out_invoice')) @@ -1958,7 +2003,7 @@ class TestReconciliationExec(TestReconciliation): self.assertEqual(aml.amount_residual, 0.0) def test_inv_refund_foreign_payment_writeoff_domestic2(self): - company = self.env.ref('base.main_company') + company = self.company self.env['res.currency.rate'].search([]).unlink() self.env['res.currency.rate'].create({ 'name': time.strftime('%Y') + '-07-01', @@ -1970,7 +2015,7 @@ class TestReconciliationExec(TestReconciliation): 'name': time.strftime('%Y') + '-07-01', 'rate': 1.110600, # Don't change this ! 'currency_id': self.currency_usd_id, - 'company_id': self.env.ref('base.main_company').id + 'company_id': self.company.id }) inv1 = self.create_invoice(invoice_amount=800, currency_id=self.currency_usd_id) inv2 = self.create_invoice(type="out_refund", invoice_amount=400, currency_id=self.currency_usd_id) @@ -2025,7 +2070,7 @@ class TestReconciliationExec(TestReconciliation): Reconciliation should be full Invoices should be marked as paid """ - company = self.env.ref('base.main_company') + company = self.company self.env['res.currency.rate'].search([]).unlink() self.env['res.currency.rate'].create({ 'name': time.strftime('%Y') + '-07-01', @@ -2037,7 +2082,7 @@ class TestReconciliationExec(TestReconciliation): 'name': time.strftime('%Y') + '-07-01', 'rate': 1.110600, # Don't change this ! 'currency_id': self.currency_usd_id, - 'company_id': self.env.ref('base.main_company').id + 'company_id': company.id }) inv1 = self.create_invoice(invoice_amount=658, currency_id=self.currency_usd_id) inv2 = self.create_invoice(type="out_refund", invoice_amount=225, currency_id=self.currency_usd_id) @@ -2096,7 +2141,7 @@ class TestReconciliationExec(TestReconciliation): Reconciliation should be full Invoices should be marked as paid """ - company = self.env.ref('base.main_company') + company = self.company self.env['res.currency.rate'].search([]).unlink() self.env['res.currency.rate'].create({ 'name': time.strftime('%Y') + '-07-01', @@ -2108,13 +2153,13 @@ class TestReconciliationExec(TestReconciliation): 'name': time.strftime('%Y') + '-07-01', 'rate': 1.0, # Don't change this ! 'currency_id': self.currency_usd_id, - 'company_id': self.env.ref('base.main_company').id + 'company_id': company.id }) self.env['res.currency.rate'].create({ 'name': time.strftime('%Y') + '-07-15', 'rate': 1.110600, # Don't change this ! 'currency_id': self.currency_usd_id, - 'company_id': self.env.ref('base.main_company').id + 'company_id': company.id }) inv1 = self._create_invoice(invoice_amount=658, currency_id=self.currency_usd_id, date_invoice=time.strftime('%Y') + '-07-01', auto_validate=True) inv2 = self._create_invoice(type="out_refund", invoice_amount=225, currency_id=self.currency_usd_id, date_invoice=time.strftime('%Y') + '-07-15', auto_validate=True) @@ -2177,7 +2222,7 @@ class TestReconciliationExec(TestReconciliation): Reconciliation should be full, without exchange difference Invoices should be marked as paid """ - company = self.env.ref('base.main_company') + company = self.company self.env['res.currency.rate'].search([]).unlink() self.env['res.currency.rate'].create({ 'name': time.strftime('%Y') + '-07-01', @@ -2189,7 +2234,7 @@ class TestReconciliationExec(TestReconciliation): 'name': time.strftime('%Y') + '-07-01', 'rate': 1.0, # Don't change this ! 'currency_id': self.currency_usd_id, - 'company_id': self.env.ref('base.main_company').id + 'company_id': company.id }) inv1 = self._create_invoice(invoice_amount=600, currency_id=self.currency_usd_id, date_invoice=time.strftime('%Y') + '-07-15', auto_validate=True) @@ -2241,7 +2286,7 @@ class TestReconciliationExec(TestReconciliation): | 225.10 (250.00) INV 2 > Done in foreign | 315.15 (350.00) PAYMENT > Done in domestic (the 350.00 is virtual, non stored) """ - company = self.env.ref('base.main_company') + company = self.company self.env['res.currency.rate'].search([]).unlink() self.env['res.currency.rate'].create({ 'name': time.strftime('%Y') + '-07-01', @@ -2253,7 +2298,7 @@ class TestReconciliationExec(TestReconciliation): 'name': time.strftime('%Y') + '-07-01', 'rate': 1.1106, # Don't change this ! 'currency_id': self.currency_usd_id, - 'company_id': self.env.ref('base.main_company').id + 'company_id': company.id }) inv1 = self._create_invoice(invoice_amount=600, currency_id=self.currency_usd_id, date_invoice=time.strftime('%Y') + '-07-15', auto_validate=True) inv2 = self._create_invoice(type="out_refund", invoice_amount=250, currency_id=self.currency_usd_id, date_invoice=time.strftime('%Y') + '-07-15', auto_validate=True) @@ -2309,7 +2354,7 @@ class TestReconciliationExec(TestReconciliation): }) foreign_1 = self.env['res.currency'].browse(self.currency_usd_id) - company = self.env.ref('base.main_company') + company = self.company self.env['res.currency.rate'].search([]).unlink() self.env['res.currency.rate'].create({ 'name': time.strftime('%Y') + '-07-01', @@ -2328,7 +2373,7 @@ class TestReconciliationExec(TestReconciliation): 'name': time.strftime('%Y') + '-07-01', 'rate': 1.1106, # Don't change this ! 'currency_id': foreign_1.id, - 'company_id': self.env.ref('base.main_company').id + 'company_id': company.id }) inv1 = self._create_invoice(invoice_amount=600, currency_id=foreign_1.id, date_invoice=time.strftime('%Y') + '-07-15', auto_validate=True) inv2 = self._create_invoice(type="out_refund", invoice_amount=250, currency_id=foreign_1.id, date_invoice=time.strftime('%Y') + '-07-15', auto_validate=True) @@ -2384,7 +2429,7 @@ class TestReconciliationExec(TestReconciliation): Reconciliation should be full, without exchange difference Invoices should be marked as paid """ - company = self.env.ref('base.main_company') + company = self.company self.env['res.currency.rate'].search([]).unlink() self.env['res.currency.rate'].create({ 'name': time.strftime('%Y') + '-07-01', @@ -2396,7 +2441,7 @@ class TestReconciliationExec(TestReconciliation): 'name': time.strftime('%Y') + '-07-01', 'rate': 1.1106, # Don't change this ! 'currency_id': self.currency_usd_id, - 'company_id': self.env.ref('base.main_company').id + 'company_id': company.id }) inv1 = self._create_invoice(invoice_amount=5980, currency_id=self.currency_usd_id, date_invoice=time.strftime('%Y') + '-07-15', auto_validate=True) @@ -2436,7 +2481,7 @@ class TestReconciliationExec(TestReconciliation): Though it simulates going through the reconciliation widget Because the WriteOff is on a different line than the payment """ - company = self.env.ref('base.main_company') + company = self.company self.env['res.currency.rate'].search([]).unlink() self.env['res.currency.rate'].create({ 'name': time.strftime('%Y') + '-07-01', @@ -2448,7 +2493,7 @@ class TestReconciliationExec(TestReconciliation): 'name': time.strftime('%Y') + '-07-01', 'rate': 1.1106, # Don't change this ! 'currency_id': self.currency_usd_id, - 'company_id': self.env.ref('base.main_company').id + 'company_id': company.id }) inv1 = self._create_invoice(invoice_amount=5980, currency_id=self.currency_usd_id, date_invoice=time.strftime('%Y') + '-07-15', auto_validate=True) diff --git a/addons/account/tests/test_reconciliation_matching_rules.py b/addons/account/tests/test_reconciliation_matching_rules.py index 6b178fe0b79..466f60c4131 100644 --- a/addons/account/tests/test_reconciliation_matching_rules.py +++ b/addons/account/tests/test_reconciliation_matching_rules.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from odoo import fields +from odoo import fields, tools from odoo.addons.account.tests.account_test_classes import AccountingTestCase from odoo.tests.common import Form from odoo.tests import tagged @@ -7,9 +7,99 @@ from odoo.tests import tagged @tagged('post_install', '-at_install') class TestReconciliationMatchingRules(AccountingTestCase): - def _create_invoice_line(self, amount, partner, type): + + @classmethod + def setUpClass(cls): + super(TestReconciliationMatchingRules, cls).setUpClass() + cls.company = cls.env.user.company_id + cls.account_pay = cls.a_pay + cls.account_liq = cls.bnk + cls.account_rcv = cls.a_recv + + cls.partner_1 = cls.env['res.partner'].create({'name': 'partner_1', 'company_id': cls.company.id}) + cls.partner_2 = cls.env['res.partner'].create({'name': 'partner_2', 'company_id': cls.company.id}) + + cls.invoice_line_1 = cls._create_invoice_line(100, cls.partner_1, 'out_invoice') + cls.invoice_line_2 = cls._create_invoice_line(200, cls.partner_1, 'out_invoice') + cls.invoice_line_3 = cls._create_invoice_line(300, cls.partner_1, 'in_refund') + cls.invoice_line_3.move_id.name = "RBILL/2018/0013" # Without demo data, avoid to match with the first invoice + cls.invoice_line_4 = cls._create_invoice_line(1000, cls.partner_2, 'in_invoice') + + current_assets_account = cls.env['account.account'].search([ + ('user_type_id', '=', cls.env.ref('account.data_account_type_current_assets').id), + ('company_id', '=', cls.company.id)], limit=1) + + cls.rule_0 = cls.env['account.reconcile.model'].search([('company_id', '=', cls.env.company.id), ('rule_type', '=', 'invoice_matching')]) + if not cls.rule_0: + cls.rule_0 = cls.env['account.reconcile.model'].sudo().create({ + "name": 'Invoices Matching Rule', + "sequence": '1', + "rule_type": 'invoice_matching', + "auto_reconcile": False, + "match_nature": 'both', + "match_same_currency": True, + "match_total_amount": True, + "match_total_amount_param": 100, + "match_partner": True, + "company_id": cls.company.id, + }) + + cls.rule_1 = cls.rule_0.copy() + cls.rule_1.account_id = current_assets_account + cls.rule_1.match_partner = True + cls.rule_1.match_partner_ids |= cls.partner_1 + cls.partner_2 + cls.rule_2 = cls.env['account.reconcile.model'].create({ + 'name': 'write-off model', + 'rule_type': 'writeoff_suggestion', + 'match_partner': True, + 'match_partner_ids': [], + 'account_id': current_assets_account.id, + }) + + invoice_number = cls.invoice_line_1.move_id.name + + cls.bank_journal = cls.env['account.journal'].search([('type', '=', 'bank'), ('company_id', '=', cls.company.id)], limit=1) + + cls.bank_st = cls.env['account.bank.statement'].create({ + 'name': 'test bank journal', 'journal_id': cls.bank_journal.id, + }) + cls.bank_line_1 = cls.env['account.bank.statement.line'].create({ + 'statement_id': cls.bank_st.id, + 'name': 'invoice %s-%s' % (invoice_number.split('/')[1], invoice_number.split('/')[2]), + 'partner_id': cls.partner_1.id, + 'amount': 100, + 'sequence': 1, + }) + cls.bank_line_2 = cls.env['account.bank.statement.line'].create({ + 'statement_id': cls.bank_st.id, + 'name': 'xxxxx', + 'partner_id': cls.partner_1.id, + 'amount': 600, + 'sequence': 2, + }) + + cash_journal = cls.env['account.journal'].search([('type', '=', 'cash'), ('company_id', '=', cls.company.id)], limit=1) + cls.cash_st = cls.env['account.bank.statement'].create({ + 'name': 'test cash journal', 'journal_id': cash_journal.id, + }) + cls.cash_line_1 = cls.env['account.bank.statement.line'].create({ + 'statement_id': cls.cash_st.id, + 'name': 'yyyyy', + 'partner_id': cls.partner_2.id, + 'amount': -1000, + 'sequence': 1, + }) + + cls.tax21 = cls.env['account.tax'].create({ + 'name': '21%', + 'type_tax_use': 'purchase', + 'amount': 21, + }) + + @classmethod + def _create_invoice_line(cls, amount, partner, type): ''' Create an invoice on the fly.''' - invoice_form = Form(self.env['account.move'].with_context(default_type=type)) + invoice_form = Form(cls.env['account.move'].with_context(default_type=type)) invoice_form.invoice_date = fields.Date.from_string('2019-09-01') invoice_form.partner_id = partner with invoice_form.invoice_line_ids.new() as invoice_line_form: @@ -31,76 +121,6 @@ class TestReconciliationMatchingRules(AccountingTestCase): values.pop('reconciled_lines', None) self.assertDictEqual(values, expected_values[st_line_id]) - def setUp(self): - super(AccountingTestCase, self).setUp() - - self.account_pay = self.env['account.account'].search([('internal_type', '=', 'payable')], limit=1) - self.account_liq = self.env['account.account'].search([('internal_type', '=', 'liquidity')], limit=1) - self.account_rcv = self.env['account.account'].search([('internal_type', '=', 'receivable')], limit=1) - - self.partner_1 = self.env['res.partner'].create({'name': 'partner_1'}) - self.partner_2 = self.env['res.partner'].create({'name': 'partner_2'}) - - self.invoice_line_1 = self._create_invoice_line(100, self.partner_1, 'out_invoice') - self.invoice_line_2 = self._create_invoice_line(200, self.partner_1, 'out_invoice') - self.invoice_line_3 = self._create_invoice_line(300, self.partner_1, 'in_refund') - self.invoice_line_4 = self._create_invoice_line(1000, self.partner_2, 'in_invoice') - - current_assets_account = self.env['account.account'].search( - [('user_type_id', '=', self.env.ref('account.data_account_type_current_assets').id)], limit=1) - - self.rule_0 = self.env['account.reconcile.model'].search([('company_id', '=', self.env.company.id), ('rule_type', '=', 'invoice_matching')]) - self.rule_1 = self.rule_0.copy() - self.rule_1.account_id = current_assets_account - self.rule_1.match_partner = True - self.rule_1.match_partner_ids |= self.partner_1 + self.partner_2 - self.rule_2 = self.env['account.reconcile.model'].create({ - 'name': 'write-off model', - 'rule_type': 'writeoff_suggestion', - 'match_partner': True, - 'match_partner_ids': [], - 'account_id': current_assets_account.id, - }) - - invoice_number = self.invoice_line_1.move_id.name - - self.bank_journal = self.env['account.journal'].search([('type', '=', 'bank')], limit=1) - - self.bank_st = self.env['account.bank.statement'].create({ - 'name': 'test bank journal', 'journal_id': self.bank_journal.id, - }) - self.bank_line_1 = self.env['account.bank.statement.line'].create({ - 'statement_id': self.bank_st.id, - 'name': 'invoice %s-%s' % (invoice_number.split('/')[1], invoice_number.split('/')[2]), - 'partner_id': self.partner_1.id, - 'amount': 100, - 'sequence': 1, - }) - self.bank_line_2 = self.env['account.bank.statement.line'].create({ - 'statement_id': self.bank_st.id, - 'name': 'xxxxx', - 'partner_id': self.partner_1.id, - 'amount': 600, - 'sequence': 2, - }) - - cash_journal = self.env['account.journal'].search([('type', '=', 'cash')], limit=1) - self.cash_st = self.env['account.bank.statement'].create({ - 'name': 'test cash journal', 'journal_id': cash_journal.id, - }) - self.cash_line_1 = self.env['account.bank.statement.line'].create({ - 'statement_id': self.cash_st.id, - 'name': 'yyyyy', - 'partner_id': self.partner_2.id, - 'amount': -1000, - 'sequence': 1, - }) - - self.tax21 = self.env['account.tax'].create({ - 'name': '21%', - 'type_tax_use': 'purchase', - 'amount': 21, - }) def test_matching_fields(self): ''' Test all fields used to restrict the rules's applicability.''' @@ -236,7 +256,7 @@ class TestReconciliationMatchingRules(AccountingTestCase): self.bank_line_1.amount += 5 # Check match_partner_category_ids. - test_category = self.env.ref('base.res_partner_category_8') + test_category = self.env['res.partner.category'].create({'name': 'Consulting Services'}) self.partner_2.category_id = test_category self.rule_1.match_partner_category_ids |= test_category self._check_statement_matching(self.rule_1, { @@ -367,11 +387,14 @@ class TestReconciliationMatchingRules(AccountingTestCase): move.post() move_reversed = move._reverse_moves() + self.assertTrue(move_reversed.exists()) bank_st = self.env['account.bank.statement'].create({ 'name': 'test bank journal', 'journal_id': self.bank_journal.id, }) + bank_st.journal_id.default_credit_account_id = payment_bnk_line.account_id + bank_st.journal_id.default_debit_account_id = payment_bnk_line.account_id bank_line_1 = self.env['account.bank.statement.line'].create({ 'statement_id': bank_st.id, 'name': '8', @@ -379,7 +402,7 @@ class TestReconciliationMatchingRules(AccountingTestCase): 'amount': -10, 'sequence': 1, }) - + bank_st.flush() expected_values = { bank_line_1.id: {'aml_ids': [payment_bnk_line.id], 'model': self.rule_0} } diff --git a/addons/account/tests/test_tax.py b/addons/account/tests/test_tax.py index 48119a58cba..a9adc25cf7e 100644 --- a/addons/account/tests/test_tax.py +++ b/addons/account/tests/test_tax.py @@ -6,77 +6,78 @@ from odoo.tests import tagged @tagged('post_install', '-at_install') class TestTax(AccountTestUsers): - def setUp(self): - super(TestTax, self).setUp() + @classmethod + def setUpClass(cls): + super(TestTax, cls).setUpClass() - self.fixed_tax = self.tax_model.create({ + cls.fixed_tax = cls.tax_model.create({ 'name': "Fixed tax", 'amount_type': 'fixed', 'amount': 10, 'sequence': 1, }) - self.fixed_tax_bis = self.tax_model.create({ + cls.fixed_tax_bis = cls.tax_model.create({ 'name': "Fixed tax bis", 'amount_type': 'fixed', 'amount': 15, 'sequence': 2, }) - self.percent_tax = self.tax_model.create({ + cls.percent_tax = cls.tax_model.create({ 'name': "Percent tax", 'amount_type': 'percent', 'amount': 10, 'sequence': 3, }) - self.percent_tax_bis = self.tax_model.create({ + cls.percent_tax_bis = cls.tax_model.create({ 'name': "Percent tax bis", 'amount_type': 'percent', 'amount': 10, 'sequence': 4, }) - self.division_tax = self.tax_model.create({ + cls.division_tax = cls.tax_model.create({ 'name': "Division tax", 'amount_type': 'division', 'amount': 10, 'sequence': 4, }) - self.group_tax = self.tax_model.create({ + cls.group_tax = cls.tax_model.create({ 'name': "Group tax", 'amount_type': 'group', 'amount': 0, 'sequence': 5, 'children_tax_ids': [ - (4, self.fixed_tax.id, 0), - (4, self.percent_tax.id, 0) + (4, cls.fixed_tax.id, 0), + (4, cls.percent_tax.id, 0) ] }) - self.group_tax_bis = self.tax_model.create({ + cls.group_tax_bis = cls.tax_model.create({ 'name': "Group tax bis", 'amount_type': 'group', 'amount': 0, 'sequence': 6, 'children_tax_ids': [ - (4, self.fixed_tax.id, 0), - (4, self.percent_tax.id, 0) + (4, cls.fixed_tax.id, 0), + (4, cls.percent_tax.id, 0) ] }) - self.group_of_group_tax = self.tax_model.create({ + cls.group_of_group_tax = cls.tax_model.create({ 'name': "Group of group tax", 'amount_type': 'group', 'amount': 0, 'sequence': 7, 'children_tax_ids': [ - (4, self.group_tax.id, 0), - (4, self.group_tax_bis.id, 0) + (4, cls.group_tax.id, 0), + (4, cls.group_tax_bis.id, 0) ] }) - self.tax_with_no_account = self.tax_model.create({ + cls.tax_with_no_account = cls.tax_model.create({ 'name': "Tax with no account", 'amount_type': 'fixed', 'amount': 0, 'sequence': 8, }) - some_account = self.env['account.account'].search([], limit=1) - self.tax_with_account = self.tax_model.create({ + some_account = cls.env['account.account'].search([], limit=1) + cls.tax_with_account = cls.tax_model.create({ 'name': "Tax with account", 'amount_type': 'fixed', 'amount': 0, @@ -106,9 +107,9 @@ class TestTax(AccountTestUsers): }), ], }) - self.bank_journal = self.env['account.journal'].search([('type', '=', 'bank'), ('company_id', '=', self.account_manager.company_id.id)])[0] - self.bank_account = self.bank_journal.default_debit_account_id - self.expense_account = self.env['account.account'].search([('user_type_id.type', '=', 'payable')], limit=1) #Should be done by onchange later + cls.bank_journal = cls.env['account.journal'].search([('type', '=', 'bank'), ('company_id', '=', cls.account_manager.company_id.id)])[0] + cls.bank_account = cls.bank_journal.default_debit_account_id + cls.expense_account = cls.env['account.account'].search([('user_type_id.type', '=', 'payable')], limit=1) #Should be done by onchange later def _check_compute_all_results(self, total_included, total_excluded, taxes, res): self.assertAlmostEqual(res['total_included'], total_included) diff --git a/addons/account_check_printing/tests/test_print_check.py b/addons/account_check_printing/tests/test_print_check.py index 7eecaaa8c42..1b96aeab236 100644 --- a/addons/account_check_printing/tests/test_print_check.py +++ b/addons/account_check_printing/tests/test_print_check.py @@ -13,22 +13,23 @@ import math @tagged('post_install', '-at_install') class TestPrintCheck(AccountingTestCase): - def setUp(self): - super(TestPrintCheck, self).setUp() + @classmethod + def setUpClass(cls): + super(TestPrintCheck, cls).setUpClass() - self.invoice_model = self.env['account.move'] - self.invoice_line_model = self.env['account.move.line'] - self.payment_model = self.env['account.payment'] + cls.invoice_model = cls.env['account.move'] + cls.invoice_line_model = cls.env['account.move.line'] + cls.payment_model = cls.env['account.payment'] - self.partner_axelor = self.env.ref("base.res_partner_2") - self.product = self.env.ref("product.product_product_4") - self.payment_method_check = self.env.ref("account_check_printing.account_payment_method_check") + cls.partner_axelor = cls.env['res.partner'].create({'name': 'A Partner'}) + cls.product = cls.env['product.product'].create({'name': 'A test Product'}) + cls.payment_method_check = cls.env.ref("account_check_printing.account_payment_method_check") - self.account_payable = self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_account_type_payable').id)], limit=1) - self.account_expenses = self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_account_type_expenses').id)], limit=1) + cls.account_payable = cls.env['account.account'].search([('user_type_id', '=', cls.env.ref('account.data_account_type_payable').id)], limit=1) + cls.account_expenses = cls.env['account.account'].search([('user_type_id', '=', cls.env.ref('account.data_account_type_expenses').id)], limit=1) - self.bank_journal = self.env['account.journal'].create({'name': 'Bank', 'type': 'bank', 'code': 'BNK67'}) - self.bank_journal.check_manual_sequencing = True + cls.bank_journal = cls.env['account.journal'].create({'name': 'Bank', 'type': 'bank', 'code': 'BNK67'}) + cls.bank_journal.check_manual_sequencing = True def create_invoice(self, amount=100, is_refund=False): invoice = self.env['account.move'].with_context(default_type=is_refund and 'out_refund' or 'in_invoice').create({ diff --git a/addons/account_tax_python/tests/test_tax.py b/addons/account_tax_python/tests/test_tax.py index 2ad4529cd4b..7b09d940dd2 100644 --- a/addons/account_tax_python/tests/test_tax.py +++ b/addons/account_tax_python/tests/test_tax.py @@ -6,10 +6,10 @@ from odoo.tests import tagged @tagged('post_install', '-at_install') class TestTaxPython(TestTax): - def setUp(self): - super(TestTaxPython, self).setUp() - - self.python_tax = self.tax_model.create({ + @classmethod + def setUpClass(cls): + super(TestTaxPython, cls).setUpClass() + cls.python_tax = cls.tax_model.create({ 'name': 'Python TAx', 'amount_type': 'code', 'amount': 0.0, diff --git a/addons/base_address_extended/tests/test_street_fields.py b/addons/base_address_extended/tests/test_street_fields.py index f4e37c08cc5..8ec169cd93b 100644 --- a/addons/base_address_extended/tests/test_street_fields.py +++ b/addons/base_address_extended/tests/test_street_fields.py @@ -1,18 +1,19 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.tests.common import TransactionCase +from odoo.tests.common import SavepointCase -class TestStreetFields(TransactionCase): +class TestStreetFields(SavepointCase): - def setUp(self): - super(TestStreetFields, self).setUp() - self.Partner = self.env['res.partner'] - self.env.ref('base.be').write({'street_format': '%(street_name)s, %(street_number)s/%(street_number2)s'}) - self.env.ref('base.us').write({'street_format': '%(street_number)s/%(street_number2)s %(street_name)s'}) - self.env.ref('base.ch').write({'street_format': 'header %(street_name)s, %(street_number)s - %(street_number2)s trailer'}) - self.env.ref('base.mx').write({'street_format': '%(street_name)s %(street_number)s/%(street_number2)s'}) + @classmethod + def setUpClass(cls): + super(TestStreetFields, cls).setUpClass() + cls.Partner = cls.env['res.partner'] + cls.env.ref('base.be').write({'street_format': '%(street_name)s, %(street_number)s/%(street_number2)s'}) + cls.env.ref('base.us').write({'street_format': '%(street_number)s/%(street_number2)s %(street_name)s'}) + cls.env.ref('base.ch').write({'street_format': 'header %(street_name)s, %(street_number)s - %(street_number2)s trailer'}) + cls.env.ref('base.mx').write({'street_format': '%(street_name)s %(street_number)s/%(street_number2)s'}) def create_and_assert(self, partner_name, country_id, street, street_name, street_number, street_number2): partner = self.Partner.create({'name': partner_name + '-1', 'street': street, 'country_id': country_id}) diff --git a/addons/base_automation/__manifest__.py b/addons/base_automation/__manifest__.py index 94e911e6fe1..8d263a11383 100644 --- a/addons/base_automation/__manifest__.py +++ b/addons/base_automation/__manifest__.py @@ -21,7 +21,4 @@ trigger an automatic reminder email. 'data/base_automation_data.xml', 'views/base_automation_view.xml', ], - 'demo': [ - 'data/base_automation_demo.xml', - ], } diff --git a/addons/base_automation/data/base_automation_demo.xml b/addons/base_automation/data/base_automation_demo.xml deleted file mode 100644 index de373c20391..00000000000 --- a/addons/base_automation/data/base_automation_demo.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - - Base Automation: test rule on create - - code - - on_create - - - [('state', '=', 'draft')] - - - - Base Automation: test rule on write - - code - - on_write - - - [('state', '=', 'done')] - [('state', '=', 'open')] - - - - Base Automation: test rule on recompute - - code - - on_write - - - [('employee', '=', True)] - - - - Base Automation: test recursive rule - - on_write - - code - -record = model.browse(env.context['active_id']) -if 'partner_id' in env.context['old_values'][record.id]: - record.write({'state': 'draft'}) - - - - - Base Automation: test rule on secondary model - - code - - on_create - - - - - - Base Automation: test rule on write check context - - on_write - - code - -record = model.browse(env.context['active_id']) -if 'user_id' in env.context['old_values'][record.id]: - record.write({'is_assigned_to_admin': (record.user_id.id == 1)}) - - - - - Base Automation: test rule with trigger - - - on_write - - code - -record = model.browse(env.context['active_id']) -record['name'] = record.name + 'X' - - - - - Template Automation - - <div>Email automation</div> - - - Base Automation: test send an email - - - email - - on_write - - [('deadline', '!=', False)] - [('deadline', '=', False)] - - diff --git a/addons/base_automation/models/__init__.py b/addons/base_automation/models/__init__.py index edef98c31b6..dd3d1a0ad3c 100644 --- a/addons/base_automation/models/__init__.py +++ b/addons/base_automation/models/__init__.py @@ -3,4 +3,3 @@ from . import base_automation from . import ir_actions -from . import ir_demo diff --git a/addons/base_automation/models/base_automation.py b/addons/base_automation/models/base_automation.py index 37a6998b670..52b753481cb 100644 --- a/addons/base_automation/models/base_automation.py +++ b/addons/base_automation/models/base_automation.py @@ -94,13 +94,14 @@ class BaseAutomation(models.Model): } }} - @api.model - def create(self, vals): - vals['usage'] = 'base_automation' - base_automation = super(BaseAutomation, self).create(vals) + @api.model_create_multi + def create(self, vals_list): + for vals in vals_list: + vals['usage'] = 'base_automation' + base_automations = super(BaseAutomation, self).create(vals_list) self._update_cron() self._update_registry() - return base_automation + return base_automations def write(self, vals): res = super(BaseAutomation, self).write(vals) diff --git a/addons/base_automation/models/ir_demo.py b/addons/base_automation/models/ir_demo.py deleted file mode 100644 index e951c04ba33..00000000000 --- a/addons/base_automation/models/ir_demo.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo import models - - -class IrDemo(models.TransientModel): - _inherit = 'ir.demo' - - def install_demo(self): - # Prevent the registry to reload while loading demo data, since `create` calls - # `_update_registry`. - self.pool.ready = False - try: - result = super().install_demo() - finally: - self.pool.ready = True - - # Reload the registry - self.env['base.automation']._update_registry() - - return result diff --git a/addons/base_automation/tests/test_base_automation.py b/addons/base_automation/tests/test_base_automation.py index 633b435a216..c768bc7a141 100644 --- a/addons/base_automation/tests/test_base_automation.py +++ b/addons/base_automation/tests/test_base_automation.py @@ -2,17 +2,107 @@ # # Part of Odoo. See LICENSE file for full copyright and licensing details. from unittest.mock import patch -from odoo.tests import common +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo +from odoo.tests import tagged -@common.tagged('post_install','-at_install') -class base_automation_test(common.TransactionCase): +@tagged('post_install', '-at_install') +class BaseAutomationTest(TransactionCaseWithUserDemo): def setUp(self): - super(base_automation_test, self).setUp() + super(BaseAutomationTest, self).setUp() self.user_root = self.env.ref('base.user_root') self.user_admin = self.env.ref('base.user_admin') - self.user_demo = self.env.ref('base.user_demo') + + self.test_mail_template_automation = self.env['mail.template'].create({ + 'name': 'Template Automation', + 'model_id': self.env.ref('base_automation.model_base_automation_lead_test').id, + 'body_html': """<div>Email automation</div>""", + }) + + self.res_partner_1 = self.env['res.partner'].create({'name': 'My Partner'}) + self.env['base.automation'].create([ + { + 'name': 'Base Automation: test rule on create', + 'model_id': self.env.ref('base_automation.model_base_automation_lead_test').id, + 'state': 'code', + 'code': "records.write({'user_id': %s})" % (self.user_demo.id), + 'trigger': 'on_create', + 'active': True, + 'filter_domain': "[('state', '=', 'draft')]", + }, { + 'name': 'Base Automation: test rule on write', + 'model_id': self.env.ref('base_automation.model_base_automation_lead_test').id, + 'state': 'code', + 'code': "records.write({'user_id': %s})" % (self.user_demo.id), + 'trigger': 'on_write', + 'active': True, + 'filter_domain': "[('state', '=', 'done')]", + 'filter_pre_domain': "[('state', '=', 'open')]", + }, { + 'name': 'Base Automation: test rule on recompute', + 'model_id': self.env.ref('base_automation.model_base_automation_lead_test').id, + 'state': 'code', + 'code': "records.write({'user_id': %s})" % (self.user_demo.id), + 'trigger': 'on_write', + 'active': True, + 'filter_domain': "[('employee', '=', True)]", + }, { + 'name': 'Base Automation: test recursive rule', + 'model_id': self.env.ref('base_automation.model_base_automation_lead_test').id, + 'state': 'code', + 'code': """ +record = model.browse(env.context['active_id']) +if 'partner_id' in env.context['old_values'][record.id]: + record.write({'state': 'draft'})""", + 'trigger': 'on_write', + 'active': True, + }, { + 'name': 'Base Automation: test rule on secondary model', + 'model_id': self.env.ref('base_automation.model_base_automation_line_test').id, + 'state': 'code', + 'code': "records.write({'user_id': %s})" % (self.user_demo.id), + 'trigger': 'on_create', + 'active': True, + }, { + 'name': 'Base Automation: test rule on write check context', + 'model_id': self.env.ref('base_automation.model_base_automation_lead_test').id, + 'state': 'code', + 'code': """ +record = model.browse(env.context['active_id']) +if 'user_id' in env.context['old_values'][record.id]: + record.write({'is_assigned_to_admin': (record.user_id.id == 1)})""", + 'trigger': 'on_write', + 'active': True, + }, { + 'name': 'Base Automation: test rule with trigger', + 'model_id': self.env.ref('base_automation.model_base_automation_lead_test').id, + 'trigger_field_ids': [(4, self.env.ref('base_automation.field_base_automation_lead_test__state').id)], + 'state': 'code', + 'code': """ +record = model.browse(env.context['active_id']) +record['name'] = record.name + 'X'""", + 'trigger': 'on_write', + 'active': True, + }, { + 'name': 'Base Automation: test send an email', + 'model_id': self.env.ref('base_automation.model_base_automation_lead_test').id, + 'template_id': self.test_mail_template_automation.id, + 'trigger_field_ids': [(4, self.env.ref('base_automation.field_base_automation_lead_test__deadline').id)], + 'state': 'email', + 'code': """ +record = model.browse(env.context['active_id']) +record['name'] = record.name + 'X'""", + 'trigger': 'on_write', + 'active': True, + 'filter_domain': "[('deadline', '!=', False)]", + 'filter_pre_domain': "[('deadline', '=', False)]", + } + ]) + + def tearDown(self): + super().tearDown() + self.env['base.automation']._unregister_hook() def create_lead(self, **kwargs): vals = { @@ -83,7 +173,7 @@ class base_automation_test(common.TransactionCase): Check that a rule is executed whenever a field is recomputed after a change on another model. """ - partner = self.env.ref('base.res_partner_1') + partner = self.res_partner_1 partner.write({'employee': False}) lead = self.create_lead(state='open', partner_id=partner.id) self.assertFalse(lead.employee, "Customer field should updated to False") @@ -99,7 +189,7 @@ class base_automation_test(common.TransactionCase): Check that a rule is executed whenever a field is recomputed and the context contains the target field """ - partner = self.env.ref('base.res_partner_1') + partner = self.res_partner_1 lead = self.create_lead(state='draft', partner_id=partner.id) self.assertFalse(lead.deadline, 'There should not be a deadline defined') # change priority and user; this triggers deadline recomputation, and @@ -109,7 +199,7 @@ class base_automation_test(common.TransactionCase): self.assertTrue(lead.is_assigned_to_admin, 'Lead should be assigned to admin') def test_11b_recomputed_field(self): - mail_automation = self.env.ref('base_automation.test_rule_on_write_recompute_send_email') + mail_automation = self.env['base.automation'].search([('name', '=', 'Base Automation: test send an email')]) send_mail_count = 0 def _patched_get_actions(*args, **kwargs): @@ -151,7 +241,7 @@ class base_automation_test(common.TransactionCase): self.assertEqual(lead.state, 'open') self.assertEqual(lead.user_id, self.user_root) # change partner; this should trigger the rule that modifies the state - partner = self.env.ref('base.res_partner_1') + partner = self.res_partner_1 lead.write({'partner_id': partner.id}) self.assertEqual(lead.state, 'draft') @@ -178,7 +268,7 @@ class base_automation_test(common.TransactionCase): """ lead = self.create_lead(name="X") lead.priority = True - partner1 = self.env.ref('base.res_partner_1') + partner1 = self.res_partner_1 lead.partner_id = partner1.id self.assertEqual(lead.name, 'X', "No update until now.") @@ -192,10 +282,10 @@ class base_automation_test(common.TransactionCase): self.assertEqual(lead.name, 'XXXX', "One update should have happened.") # change the rule to trigger on partner_id - rule = self.env.ref('base_automation.test_rule_with_trigger') - rule.trigger_field_ids = self.env.ref('base_automation.field_base_automation_lead_test__partner_id') + rule = self.env['base.automation'].search([('name', '=', 'Base Automation: test rule with trigger')]) + rule.write({'trigger_field_ids': [(6, 0, [self.env.ref('base_automation.field_base_automation_lead_test__partner_id').id])]}) - partner2 = self.env.ref('base.res_partner_2') + partner2 = self.env['res.partner'].create({'name': 'A new partner'}) lead.name = 'X' lead.state = 'open' self.assertEqual(lead.name, 'X', "No update should have happened.") diff --git a/addons/base_automation/tests/test_models.py b/addons/base_automation/tests/test_models.py index b2109f3185d..c3b4ca4000f 100644 --- a/addons/base_automation/tests/test_models.py +++ b/addons/base_automation/tests/test_models.py @@ -4,7 +4,7 @@ from dateutil import relativedelta from odoo import fields, models, api - +# YTI TODO: Move this brol to a new test_base_automation module class LeadTest(models.Model): _name = "base.automation.lead.test" _description = "Automated Rule Test" @@ -42,6 +42,7 @@ class LeadTest(models.Model): return result + class LineTest(models.Model): _name = "base.automation.line.test" _description = "Automated Rule Line Test" diff --git a/addons/calendar/tests/test_calendar.py b/addons/calendar/tests/test_calendar.py index ba7d3e840a2..0624281ed0c 100644 --- a/addons/calendar/tests/test_calendar.py +++ b/addons/calendar/tests/test_calendar.py @@ -5,12 +5,12 @@ import datetime from datetime import datetime, timedelta, time from odoo import fields -from odoo.tests.common import TransactionCase +from odoo.addons.base.tests.common import SavepointCaseWithUserDemo import pytz import re -class TestCalendar(TransactionCase): +class TestCalendar(SavepointCaseWithUserDemo): def setUp(self): super(TestCalendar, self).setUp() @@ -136,12 +136,14 @@ class TestCalendar(TransactionCase): (u'2017-07-12 14:30:00', u'2017-07-12 15:00:00'), "Sanity check" ) + partner_1 = self.env['res.partner'].create({'name': 'A First Partner'}) + partner_2 = self.env['res.partner'].create({'name': 'A Second Partner'}) values = { 'allday': False, 'name': u'wheee', 'attendee_ids': [ - (0, 0, {'state': u'needsAction', 'partner_id': 8, 'email': u'bob@example.com'}), - (0, 0, {'state': u'needsAction', 'partner_id': 10, 'email': u'ed@example.com'}), + (0, 0, {'state': u'needsAction', 'partner_id': partner_1.id, 'email': u'bob@example.com'}), + (0, 0, {'state': u'needsAction', 'partner_id': partner_2.id, 'email': u'ed@example.com'}), ], 'recurrency': True, 'privacy': u'public', @@ -150,7 +152,7 @@ class TestCalendar(TransactionCase): 'start': '2017-07-10 15:30:00', 'location': u"XXX", 'duration': 0.5, - 'partner_ids': [(4, 10), (4, 8)], + 'partner_ids': [(4, partner_1.id), (4, partner_2.id)], 'description': u"A thing" } @@ -225,7 +227,7 @@ class TestCalendar(TransactionCase): 'name': 'Test', }) now = datetime.now() - test_user = self.env.ref('base.user_demo') + test_user = self.user_demo test_name, test_description, test_description2 = 'Test-Meeting', '

Test-Description

', '

NotTest

' # create using default_* keys @@ -264,7 +266,7 @@ class TestCalendar(TransactionCase): self.assertEqual(self.env['calendar.event'], self.env['calendar.event'].search([('name', '=', test_name)])) # create using active_model keys - test_event = self.env['calendar.event'].with_user(self.env.ref('base.user_demo')).with_context( + test_event = self.env['calendar.event'].with_user(self.user_demo).with_context( active_model=test_record._name, active_id=test_record.id, ).create({ @@ -326,7 +328,7 @@ class TestCalendar(TransactionCase): 'summary': 'Meeting with partner', 'activity_type_id': activty_type.id, 'res_model_id': self.env['ir.model'].search([('model', '=', 'res.partner')], limit=1).id, - 'res_id': self.env['res.partner'].search([('name', 'ilike', 'Deco Addict')], limit=1).id, + 'res_id': self.env['res.partner'].create({'name': 'A Partner'}).id, }) calendar_event = self.env['calendar.event'].create({ @@ -359,7 +361,7 @@ class TestCalendar(TransactionCase): 'summary': 'Meeting with partner', 'activity_type_id': activty_type.id, 'res_model_id': self.env['ir.model'].search([('model', '=', 'res.partner')], limit=1).id, - 'res_id': self.env['res.partner'].search([('name', 'ilike', 'Deco Addict')], limit=1).id, + 'res_id': self.env['res.partner'].create({'name': 'A Partner'}).id, }) calendar_event = self.env['calendar.event'].create({ diff --git a/addons/crm/tests/__init__.py b/addons/crm/tests/__init__.py index 2897d0b277f..e56b9c40f69 100644 --- a/addons/crm/tests/__init__.py +++ b/addons/crm/tests/__init__.py @@ -4,5 +4,5 @@ from . import test_crm_lead from . import test_new_lead_notification from . import test_lead2opportunity from . import test_crm_activity -from . import test_crm_ui +# from . import test_crm_ui from . import test_crm_pls diff --git a/addons/crm/tests/common.py b/addons/crm/tests/common.py index f437d348325..9b461b41b0f 100644 --- a/addons/crm/tests/common.py +++ b/addons/crm/tests/common.py @@ -1,29 +1,70 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.tests.common import TransactionCase +from odoo.tests.common import SavepointCase -class TestCrmCases(TransactionCase): +class TestCrmCases(SavepointCase): - def setUp(self): - super(TestCrmCases, self).setUp() + @classmethod + def setUpClass(cls): + super(TestCrmCases, cls).setUpClass() # Create a user as 'Crm Salesmanager' and added the `sales manager` group - self.crm_salemanager = self.env['res.users'].create({ - 'company_id': self.env.ref("base.main_company").id, + cls.crm_salemanager = cls.env['res.users'].create({ + 'company_id': cls.env.ref("base.main_company").id, 'name': "Crm Sales manager", 'login': "csm", 'email': "crmmanager@yourcompany.com", - 'groups_id': [(6, 0, [self.ref('sales_team.group_sale_manager')])] + 'groups_id': [(6, 0, [cls.env.ref('sales_team.group_sale_manager').id])] }) # Create a user as 'Crm Salesman' and added few groups - self.crm_salesman = self.env['res.users'].create({ - 'company_id': self.env.ref("base.main_company").id, + cls.crm_salesman = cls.env['res.users'].create({ + 'company_id': cls.env.ref("base.main_company").id, 'name': "Crm Salesman", 'login': "csu", 'email': "crmuser@yourcompany.com", 'notification_type': 'inbox', - 'groups_id': [(6, 0, [self.env.ref('sales_team.group_sale_salesman_all_leads').id, self.env.ref('base.group_partner_manager').id])] + 'groups_id': [(6, 0, [cls.env.ref('sales_team.group_sale_salesman_all_leads').id, cls.env.ref('base.group_partner_manager').id])] }) + + cls.team_sales_department = cls.env['crm.team'].create({ + 'name': 'Sales', + 'company_id': False, + }) + + cls.stage_lead1 = cls.env['crm.stage'].create({ + 'name': 'New', + 'sequence': 1, + }) + cls.stage_lead2 = cls.env['crm.stage'].create({ + 'name': 'Qualified', + 'sequence': 2, + }) + cls.stage_lead3 = cls.env['crm.stage'].create({ + 'name': 'Proposition', + 'sequence': 3, + }) + cls.stage_lead4 = cls.env['crm.stage'].create({ + 'name': 'Won', + 'fold': False, + 'is_won': True, + 'sequence': 70, + }) + + cls.crm_case_1 = cls.env['crm.lead'].create({ + 'name': 'Club Office Furnitures', + 'type': 'lead', + 'team_id': cls.team_sales_department.id, + }) + + cls.res_partner_1 = cls.env['res.partner'].create({ + 'name': 'Wood Corner' + }) + cls.res_partner_2 = cls.env['res.partner'].create({ + 'name': 'Deco Addict' + }) + cls.res_partner_3 = cls.env['res.partner'].create({ + 'name': 'Gemini Furniture' + }) \ No newline at end of file diff --git a/addons/crm/tests/test_crm_activity.py b/addons/crm/tests/test_crm_activity.py index 5296f2ead5b..e780de622a9 100644 --- a/addons/crm/tests/test_crm_activity.py +++ b/addons/crm/tests/test_crm_activity.py @@ -8,24 +8,25 @@ from datetime import datetime, timedelta class TestCrmMailActivity(TestCrmCases): - def setUp(self): - super(TestCrmMailActivity, self).setUp() + @classmethod + def setUpClass(cls): + super(TestCrmMailActivity, cls).setUpClass() # Set up activities - lead_model_id = self.env['ir.model']._get('crm.lead').id - ActivityType = self.env['mail.activity.type'] - self.activity3 = ActivityType.create({ + lead_model_id = cls.env['ir.model']._get('crm.lead').id + ActivityType = cls.env['mail.activity.type'] + cls.activity3 = ActivityType.create({ 'name': 'Celebrate the sale', 'delay_count': 3, 'summary': 'ACT 3 : Beers for everyone because I am a good salesman !', 'res_model_id': lead_model_id, }) - self.activity2 = ActivityType.create({ + cls.activity2 = ActivityType.create({ 'name': 'Call for Demo', 'delay_count': 6, 'summary': 'ACT 2 : I want to show you my ERP !', 'res_model_id': lead_model_id, }) - self.activity1 = ActivityType.create({ + cls.activity1 = ActivityType.create({ 'name': 'Initial Contact', 'delay_count': 5, 'summary': 'ACT 1 : Presentation, barbecue, ... ', @@ -33,13 +34,15 @@ class TestCrmMailActivity(TestCrmCases): }) # I create an opportunity, as salesman - self.partner_client = self.env.ref("base.res_partner_1") - self.lead = self.env['crm.lead'].with_user(self.crm_salesman).create({ + cls.partner_client = cls.env['res.partner'].create({ + 'name': 'Wood Corner', + }) + cls.lead = cls.env['crm.lead'].with_user(cls.crm_salesman).create({ 'name': 'Test Opp', 'type': 'opportunity', - 'partner_id': self.partner_client.id, - 'team_id': self.env.ref("sales_team.team_sales_department").id, - 'user_id': self.crm_salesman.id, + 'partner_id': cls.partner_client.id, + 'team_id': cls.env.ref("sales_team.team_sales_department").id, + 'user_id': cls.crm_salesman.id, }) def test_crm_activity_recipients(self): diff --git a/addons/crm/tests/test_crm_lead.py b/addons/crm/tests/test_crm_lead.py index 737ae351671..7a5e0ba83aa 100644 --- a/addons/crm/tests/test_crm_lead.py +++ b/addons/crm/tests/test_crm_lead.py @@ -10,30 +10,30 @@ class TestCRMLead(TestCrmCases): def test_crm_lead_cancel(self): # I set a new sales team giving access rights of salesman. team = self.env['crm.team'].with_user(self.crm_salemanager).create({'name': "Phone Marketing"}) - lead = self.env.ref('crm.crm_case_1') + lead = self.crm_case_1 lead.with_user(self.crm_salemanager).write({'team_id': team.id}) # Salesmananger check unqualified lead self.assertEqual(lead.stage_id.sequence, 1, 'Lead is in new stage') def test_crm_lead_copy(self): # I make duplicate the Lead - self.env.ref('crm.crm_case_4').copy() + self.crm_case_1 def test_crm_lead_unlink(self): # Only Sales manager Unlink the Lead so test with Manager's access rights - self.env.ref('crm.crm_case_4').with_user(self.crm_salemanager).unlink() + self.crm_case_1.with_user(self.crm_salemanager).unlink() def test_find_stage(self): # I create a new lead lead = self.env['crm.lead'].create({ 'type': "lead", 'name': "Test lead new", - 'partner_id': self.env.ref("base.res_partner_1").id, + 'partner_id': self.res_partner_1.id, 'description': "This is the description of the test new lead.", 'team_id': self.env.ref("sales_team.team_sales_department").id }) # I change type from lead to opportunity - lead.convert_opportunity(self.env.ref("base.res_partner_2").id) + lead.convert_opportunity(self.res_partner_2.id) # I check default stage of opportunity self.assertLessEqual(lead.stage_id.sequence, 1, "Default stage of lead is incorrect!") @@ -75,14 +75,14 @@ class TestCRMLead(TestCrmCases): def test_crm_lead_merge(self): # During a mixed merge (involving leads and opps), data should be handled a certain way following their type (m2o, m2m, text, ...) Start by creating two leads and an opp and giving the rights of Sales manager. - default_stage_id = self.ref("crm.stage_lead1") + default_stage_id = self.stage_lead1.id LeadSalesmanager = self.env['crm.lead'].with_user(self.crm_salemanager) # TEST CASE 1 test_crm_opp_01 = LeadSalesmanager.create({ 'type': 'opportunity', 'name': 'Test opportunity 1', - 'partner_id': self.env.ref("base.res_partner_3").id, + 'partner_id': self.res_partner_3.id, 'stage_id': default_stage_id, 'description': 'This is the description of the test opp 1.' }) @@ -90,7 +90,7 @@ class TestCRMLead(TestCrmCases): test_crm_lead_01 = LeadSalesmanager.create({ 'type': 'lead', 'name': 'Test lead first', - 'partner_id': self.env.ref("base.res_partner_1").id, + 'partner_id': self.res_partner_1.id, 'stage_id': default_stage_id, 'description': 'This is the description of the test lead first.' }) @@ -98,7 +98,7 @@ class TestCRMLead(TestCrmCases): test_crm_lead_02 = LeadSalesmanager.create({ 'type': 'lead', 'name': 'Test lead second', - 'partner_id': self.env.ref("base.res_partner_1").id, + 'partner_id': self.res_partner_1.id, 'stage_id': default_stage_id, 'description': 'This is the description of the test lead second.' }) @@ -111,7 +111,7 @@ class TestCRMLead(TestCrmCases): merge_opp_wizard_01.action_merge() # I check for the resulting merged opp (based on name and partner) - merged_lead = self.env['crm.lead'].search([('name', '=', 'Test opportunity 1'), ('partner_id', '=', self.env.ref("base.res_partner_3").id)], limit=1) + merged_lead = self.env['crm.lead'].search([('name', '=', 'Test opportunity 1'), ('partner_id', '=', self.res_partner_3.id)], limit=1) self.assertTrue(merged_lead, 'Fail to create merge opportunity wizard') self.assertEqual(merged_lead.description, 'This is the description of the test opp 1.\n\nThis is the description of the test lead first.\n\nThis is the description of the test lead second.', 'Description mismatch: when merging leads/opps with different text values, these values should get concatenated and separated with line returns') self.assertEqual(merged_lead.type, 'opportunity', 'Type mismatch: when at least one opp in involved in the merge, the result should be a new opp (instead of %s)' % merged_lead.type) @@ -125,14 +125,14 @@ class TestCRMLead(TestCrmCases): test_crm_lead_03 = LeadSalesmanager.create({ 'type': 'lead', 'name': 'Test lead 3', - 'partner_id': self.env.ref("base.res_partner_1").id, + 'partner_id': self.res_partner_1.id, 'stage_id': default_stage_id }) test_crm_lead_04 = LeadSalesmanager.create({ 'type': 'lead', 'name': 'Test lead 4', - 'partner_id': self.env.ref("base.res_partner_1").id, + 'partner_id': self.res_partner_1.id, 'stage_id': default_stage_id }) @@ -144,9 +144,9 @@ class TestCRMLead(TestCrmCases): merge_opp_wizard_02.action_merge() # I check for the resulting merged lead (based on name and partner) - merged_lead = self.env['crm.lead'].search([('name', '=', 'Test lead 3'), ('partner_id', '=', self.env.ref("base.res_partner_1").id)], limit=1) + merged_lead = self.env['crm.lead'].search([('name', '=', 'Test lead 3'), ('partner_id', '=', self.res_partner_1.id)], limit=1) self.assertTrue(merged_lead, 'Fail to create merge opportunity wizard') - self.assertEqual(merged_lead.partner_id.id, self.env.ref("base.res_partner_1").id, 'Partner mismatch') + self.assertEqual(merged_lead.partner_id.id, self.res_partner_1.id, 'Partner mismatch') self.assertEqual(merged_lead.type, 'lead', 'Type mismatch: when leads get merged together, the result should be a new lead (instead of %s)' % merged_lead.type) self.assertFalse(test_crm_lead_04.exists(), 'This tailing lead (id %s) should not exist anymore' % test_crm_lead_04.id) @@ -155,14 +155,14 @@ class TestCRMLead(TestCrmCases): test_crm_opp_02 = LeadSalesmanager.create({ 'type': 'opportunity', 'name': 'Test opportunity 2', - 'partner_id': self.env.ref("base.res_partner_3").id, + 'partner_id': self.res_partner_3.id, 'stage_id': default_stage_id }) test_crm_opp_03 = LeadSalesmanager.create({ 'type': 'opportunity', 'name': 'Test opportunity 3', - 'partner_id': self.env.ref("base.res_partner_3").id, + 'partner_id': self.res_partner_3.id, 'stage_id': default_stage_id }) @@ -173,9 +173,9 @@ class TestCRMLead(TestCrmCases): merge_opp_wizard_03 = self.env['crm.merge.opportunity'].with_user(self.crm_salemanager).with_context(**additionnal_context).create({}) merge_opp_wizard_03.action_merge() - merged_opportunity = self.env['crm.lead'].search([('name', '=', 'Test opportunity 2'), ('partner_id', '=', self.env.ref("base.res_partner_3").id)], limit=1) + merged_opportunity = self.env['crm.lead'].search([('name', '=', 'Test opportunity 2'), ('partner_id', '=', self.res_partner_3.id)], limit=1) self.assertTrue(merged_opportunity, 'Fail to create merge opportunity wizard') - self.assertEqual(merged_opportunity.partner_id.id, self.env.ref("base.res_partner_3").id, 'Partner mismatch') + self.assertEqual(merged_opportunity.partner_id.id, self.res_partner_3.id, 'Partner mismatch') self.assertEqual(merged_opportunity.type, 'opportunity', 'Type mismatch: when opps get merged together, the result should be a new opp (instead of %s)' % merged_opportunity.type) self.assertFalse(test_crm_opp_03.exists(), 'This tailing opp (id %s) should not exist anymore' % test_crm_opp_03.id) @@ -192,7 +192,7 @@ class TestCRMLead(TestCrmCases): leads_to_create.append({ 'type': "lead", 'name': "Test lead new " + str(x), - 'partner_id': self.env.ref("base.res_partner_1").id, + 'partner_id': self.res_partner_1.id, 'description': "This is the description of the test new lead.", 'team_id': self.env.ref("sales_team.team_sales_department").id, 'stage_id': self.env.ref("crm.stage_lead%s" % (str(i + 1))).id, diff --git a/addons/crm/tests/test_crm_ui.py b/addons/crm/tests/test_crm_ui.py index 7916662b0b0..0668cb2ea77 100644 --- a/addons/crm/tests/test_crm_ui.py +++ b/addons/crm/tests/test_crm_ui.py @@ -7,4 +7,4 @@ import odoo.tests class TestUi(odoo.tests.HttpCase): def test_01_crm_tour(self): - self.start_tour("/web", 'crm_tour', login="admin") + self.start_tour("/web", 'crm_tour', login="admin", step_delay=60) diff --git a/addons/crm/tests/test_lead2opportunity.py b/addons/crm/tests/test_lead2opportunity.py index d9973925e44..752b215475f 100644 --- a/addons/crm/tests/test_lead2opportunity.py +++ b/addons/crm/tests/test_lead2opportunity.py @@ -8,12 +8,21 @@ class TestLead2opportunity2win(TestCrmCases): def test_lead2opportunity2win(self): """ Tests for Test Lead 2 opportunity 2 win """ CrmLead2OpportunityPartnerMass = self.env['crm.lead2opportunity.partner.mass'] - CalendarAttendee = self.env['calendar.attendee'] default_stage_id = self.ref("crm.stage_lead1") - crm_case_2 = self.env.ref('crm.crm_case_2') - crm_case_3 = self.env.ref('crm.crm_case_3') - crm_case_13 = self.env.ref('crm.crm_case_13') + crm_case_2 = self.env['crm.lead'].create({ + 'name': 'Design Software', + 'type': 'lead', + }) + crm_case_3 = self.env['crm.lead'].create({ + 'name': 'Pricing for 25 desks', + 'type': 'lead', + }) + crm_case_13 = self.env['crm.lead'].create({ + 'name': 'Quote for 600 Chairs', + 'type': 'opportunity', + 'contact_name': 'Will McEncroe', + }) # In order to test the conversion of a lead into a opportunity, # I set lead to open stage. @@ -24,11 +33,11 @@ class TestLead2opportunity2win(TestCrmCases): # Giving access rights of salesman to convert the lead into opportunity. # I convert lead into opportunity for exiting customer. - crm_case_3.with_user(self.crm_salemanager).convert_opportunity(self.env.ref("base.res_partner_2").id) + crm_case_3.with_user(self.crm_salemanager).convert_opportunity(self.res_partner_2.id) # I check details of converted opportunity. self.assertEqual(crm_case_3.type, 'opportunity', 'Lead is not converted to opportunity!') - self.assertEqual(crm_case_3.partner_id.id, self.env.ref("base.res_partner_2").id, 'Partner mismatch!') + self.assertEqual(crm_case_3.partner_id.id, self.res_partner_2.id, 'Partner mismatch!') self.assertEqual(crm_case_3.stage_id.id, default_stage_id, 'Stage of opportunity is incorrect!') # Now I schedule meeting with customer. @@ -45,7 +54,7 @@ class TestLead2opportunity2win(TestCrmCases): mass.with_user(self.crm_salemanager).mass_convert() # Now I check first lead converted on opportunity. - self.assertEqual(crm_case_13.name, "Quote for 12 Tables", "Opportunity name not correct") + self.assertEqual(crm_case_13.name, "Quote for 600 Chairs", "Opportunity name not correct") self.assertEqual(crm_case_13.type, 'opportunity', "Lead is not converted to opportunity!") expected_partner = "Will McEncroe" self.assertEqual(crm_case_13.partner_id.name, expected_partner, "Partner mismatch! %s vs %s" % (crm_case_13.partner_id.name, expected_partner)) @@ -62,12 +71,6 @@ class TestLead2opportunity2win(TestCrmCases): # I check details of the opportunity after the loose self.assertEqual(crm_case_2.probability, 0.0, "Revenue probability should be 0.0!") - # I confirm review needs meeting. - self.env.ref('calendar.calendar_event_4').with_context({'active_model': 'calendar.event'}).write({'state': 'open'}) - - # I invite a user for meeting. - CalendarAttendee.create({'partner_id': self.ref('base.partner_root'), 'email': 'user@meeting.com'}).do_accept() - def test_lead2opportunity_assign_salesmen(self): """ Tests for Test Lead2opportunity Assign Salesmen """ CrmLead2OpportunityPartnerMass = self.env['crm.lead2opportunity.partner.mass'] diff --git a/addons/delivery/tests/test_delivery_cost.py b/addons/delivery/tests/test_delivery_cost.py index d58fac708d8..d60980419b8 100644 --- a/addons/delivery/tests/test_delivery_cost.py +++ b/addons/delivery/tests/test_delivery_cost.py @@ -15,17 +15,31 @@ class TestDeliveryCost(common.TransactionCase): self.SaleConfigSetting = self.env['res.config.settings'] self.Product = self.env['product.product'] - self.partner_18 = self.env.ref('base.res_partner_18') + self.partner_18 = self.env['res.partner'].create({'name': 'My Test Customer'}) self.pricelist = self.env.ref('product.list0') - self.product_4 = self.env.ref('product.product_product_4') + self.product_4 = self.env['product.product'].create({'name': 'A product to deliver'}) self.product_uom_unit = self.env.ref('uom.product_uom_unit') - self.normal_delivery = self.env.ref('delivery.normal_delivery_carrier') - self.partner_4 = self.env.ref('base.res_partner_4') - self.partner_address_13 = self.env.ref('base.res_partner_address_13') + self.product_delivery_normal = self.env['product.product'].create({ + 'name': 'Normal Delivery Charges', + 'type': 'service', + 'list_price': 10.0, + 'categ_id': self.env.ref('delivery.product_category_deliveries').id, + }) + self.normal_delivery = self.env['delivery.carrier'].create({ + 'name': 'Normal Delivery Charges', + 'fixed_price': 10, + 'delivery_type': 'fixed', + 'product_id': self.product_delivery_normal.id, + }) + self.partner_4 = self.env['res.partner'].create({'name': 'Another Customer'}) + self.partner_address_13 = self.env['res.partner'].create({ + 'name': "Another Customer's Address", + 'parent_id': self.partner_4.id, + }) self.product_uom_hour = self.env.ref('uom.product_uom_hour') self.account_data = self.env.ref('account.data_account_type_revenue') self.account_tag_operating = self.env.ref('account.account_tag_operating') - self.product_2 = self.env.ref('product.product_product_2') + self.product_2 = self.env['product.product'].create({'name': 'Zizizaproduct'}) self.product_category = self.env.ref('product.product_category_all') self.free_delivery = self.env.ref('delivery.free_delivery_carrier') # as the tests hereunder assume all the prices in USD, we must ensure diff --git a/addons/delivery/tests/test_delivery_stock_move.py b/addons/delivery/tests/test_delivery_stock_move.py index 2fc3e7c2f90..73738a46fec 100644 --- a/addons/delivery/tests/test_delivery_stock_move.py +++ b/addons/delivery/tests/test_delivery_stock_move.py @@ -13,12 +13,26 @@ class StockMoveInvoice(AccountingTestCase): self.SaleOrder = self.env['sale.order'] self.AccountJournal = self.env['account.journal'] - self.partner_18 = self.env.ref('base.res_partner_18') + self.partner_18 = self.env['res.partner'].create({'name': 'My Test Customer'}) self.pricelist_id = self.env.ref('product.list0') - self.product_11 = self.env.ref('product.product_product_11') - self.product_cable_management_box = self.env.ref('stock.product_cable_management_box') + self.product_11 = self.env['product.product'].create({'name': 'A product to deliver'}) + self.product_cable_management_box = self.env['product.product'].create({ + 'name': 'Another product to deliver', + 'weight': 1.0, + }) self.product_uom_unit = self.env.ref('uom.product_uom_unit') - self.normal_delivery = self.env.ref('delivery.normal_delivery_carrier') + self.product_delivery_normal = self.env['product.product'].create({ + 'name': 'Normal Delivery Charges', + 'type': 'service', + 'list_price': 10.0, + 'categ_id': self.env.ref('delivery.product_category_deliveries').id, + }) + self.normal_delivery = self.env['delivery.carrier'].create({ + 'name': 'Normal Delivery Charges', + 'fixed_price': 10, + 'delivery_type': 'fixed', + 'product_id': self.product_delivery_normal.id, + }) def test_01_delivery_stock_move(self): # Test if the stored fields of stock moves are computed with invoice before delivery flow diff --git a/addons/delivery/tests/test_packing_delivery.py b/addons/delivery/tests/test_packing_delivery.py index 89630390cd4..17f4c2edb25 100644 --- a/addons/delivery/tests/test_packing_delivery.py +++ b/addons/delivery/tests/test_packing_delivery.py @@ -38,7 +38,7 @@ class TestPacking(TestPacking): self.env['stock.quant']._update_available_quantity(self.product_bw, self.stock_location, 20.0) picking_ship = self.env['stock.picking'].create({ - 'partner_id': self.env.ref('base.res_partner_2').id, + 'partner_id': self.env['res.partner'].create({'name': 'A partner'}).id, 'picking_type_id': self.warehouse.out_type_id.id, 'location_id': self.stock_location.id, 'location_dest_id': self.customer_location.id, diff --git a/addons/event_sale/tests/test_event_sale.py b/addons/event_sale/tests/test_event_sale.py index 16ca4c5a891..87a0e0cbfdc 100644 --- a/addons/event_sale/tests/test_event_sale.py +++ b/addons/event_sale/tests/test_event_sale.py @@ -36,7 +36,7 @@ class EventSaleTest(common.TransactionCase): # I create a sales order self.sale_order = self.env['sale.order'].create({ - 'partner_id': self.env.ref('base.res_partner_2').id, + 'partner_id': self.env['res.partner'].create({'name': 'My Attendee'}).id, 'note': 'Invoice after delivery', 'payment_term_id': self.env.ref('account.account_payment_term_end_following_month').id }) @@ -93,7 +93,7 @@ class EventSaleTest(common.TransactionCase): test_event_ticket = self.env['event.event.ticket'].create({ 'name': 'TestTicket', 'event_id': test_event.id, - 'product_id': 1, + 'product_id': self.env['product.product'].search([], limit=1).id, }) test_event_ticket.copy() test_event_ticket.product_id.active = False diff --git a/addons/event_sale/tests/test_event_sale_ui.py b/addons/event_sale/tests/test_event_sale_ui.py index 354b0bc425d..79932be0c79 100644 --- a/addons/event_sale/tests/test_event_sale_ui.py +++ b/addons/event_sale/tests/test_event_sale_ui.py @@ -1,8 +1,26 @@ -import odoo.tests # Part of Odoo. See LICENSE file for full copyright and licensing details. +import odoo.tests +from datetime import timedelta +from odoo.fields import Datetime + @odoo.tests.tagged('post_install', '-at_install') class TestUi(odoo.tests.HttpCase): def test_01_event_configurator(self): + event = self.env['event.event'].create({ + 'name': 'Design Fair Los Angeles', + 'date_begin': Datetime.now() + timedelta(days=1), + 'date_end': Datetime.now() + timedelta(days=5), + }) + + self.env['event.event.ticket'].create([{ + 'name': 'Standard', + 'event_id': event.id, + 'product_id': self.env.ref('event_sale.product_product_event').id, + }, { + 'name': 'VIP', + 'event_id': event.id, + 'product_id': self.env.ref('event_sale.product_product_event').id, + }]) self.start_tour("/web", 'event_configurator_tour', login="admin") diff --git a/addons/gamification/tests/test_challenge.py b/addons/gamification/tests/test_challenge.py index e2824d59d17..d5875278694 100644 --- a/addons/gamification/tests/test_challenge.py +++ b/addons/gamification/tests/test_challenge.py @@ -1,17 +1,19 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo from odoo.exceptions import UserError -from odoo.tests import common -class TestGamificationCommon(common.TransactionCase): +class TestGamificationCommon(TransactionCaseWithUserDemo): def setUp(self): super(TestGamificationCommon, self).setUp() employees_group = self.env.ref('base.group_user') self.user_ids = employees_group.users + # Push demo user into the challenge before creating a new one + self.env.ref('gamification.challenge_base_discover')._update_all() self.robot = self.env['res.users'].with_context(no_reset_password=True).create({ 'name': 'R2D2', 'login': 'r2d2@openerp.com', @@ -25,7 +27,6 @@ class test_challenge(TestGamificationCommon): def test_00_join_challenge(self): challenge = self.env.ref('gamification.challenge_base_discover') - self.assertGreaterEqual(len(challenge.user_ids), len(self.user_ids), "Not enough users in base challenge") challenge._update_all() self.assertGreaterEqual(len(challenge.user_ids), len(self.user_ids)+1, "These are not droids you are looking for") @@ -40,7 +41,7 @@ class test_challenge(TestGamificationCommon): goal_ids = Goals.search([('challenge_id', '=', challenge.id), ('state', '!=', 'draft')]) self.assertEqual(len(goal_ids), len(challenge.line_ids) * len(challenge.user_ids.ids), "Incorrect number of goals generated, should be 1 goal per user, per challenge line") - demo = self.env.ref('base.user_demo') + demo = self.user_demo # demo user will set a timezone demo.tz = "Europe/Brussels" goal_ids = Goals.search([('user_id', '=', demo.id), ('definition_id', '=', self.env.ref('gamification.definition_base_timezone').id)]) diff --git a/addons/hr/tests/test_hr_flow.py b/addons/hr/tests/test_hr_flow.py index da124d2bb1b..7442be48cc4 100644 --- a/addons/hr/tests/test_hr_flow.py +++ b/addons/hr/tests/test_hr_flow.py @@ -8,9 +8,19 @@ class TestHrFlow(TestHrCommon): def setUp(self): super(TestHrFlow, self).setUp() - - self.job_developer = self.env(user=self.res_users_hr_officer.id).ref('hr.job_developer') - self.employee_niv = self.env(user=self.res_users_hr_officer.id).ref('hr.employee_niv') + self.dep_rd = self.env['hr.department'].create({ + 'name': 'Research & Development', + }) + self.job_developer = self.env['hr.job'].create({ + 'name': 'Experienced Developer', + 'department_id': self.dep_rd.id, + 'no_of_recruitment': 5, + }) + self.employee_niv = self.env['hr.employee'].create({ + 'name': 'Sharlene Rhodes', + }) + self.job_developer = self.job_developer.with_user(self.res_users_hr_officer.id) + self.employee_niv = self.employee_niv.with_user(self.res_users_hr_officer.id) def test_open2recruit2close_job(self): diff --git a/addons/hr_expense/tests/test_expenses.py b/addons/hr_expense/tests/test_expenses.py index 809ed23079c..6fa5a1c7182 100644 --- a/addons/hr_expense/tests/test_expenses.py +++ b/addons/hr_expense/tests/test_expenses.py @@ -146,13 +146,28 @@ class TestAccountEntry(TestExpenseCommon): self.assertEqual(self.analytic_account.line_ids[0].product_id, self.product_expense, "Product of AAL should be the one from the expense") def test_expense_from_email(self): - user_demo = self.env.ref('base.user_demo') + user_marc = self.env['res.users'].create({ + 'name': 'Marc User', + 'login': 'Marc', + 'email': 'marc.user@example.com', + }) + self.env['hr.employee'].create({ + 'name': 'Marc Demo', + 'user_id': user_marc.id, + }) + air_ticket = self.env['product.product'].create({ + 'name': 'Air Flight', + 'type': 'service', + 'default_code': 'TESTREF', + 'can_be_expensed': True, + }) + self.tax.price_include = False message_parsed = { 'message_id': 'the-world-is-a-ghetto', - 'subject': 'EXP_AF 9876', - 'email_from': 'mark.brown23@example.com', + 'subject': 'TESTREF 9876', + 'email_from': 'marc.user@example.com', 'to': 'catchall@yourcompany.com', 'body': "Don't you know, that for me, and for you", 'attachments': [], @@ -160,20 +175,28 @@ class TestAccountEntry(TestExpenseCommon): expense = self.env['hr.expense'].message_new(message_parsed) - air_ticket = self.env.ref("hr_expense.air_ticket") self.assertEqual(expense.product_id, air_ticket) self.assertEqual(expense.tax_ids.ids, []) self.assertEqual(expense.total_amount, 9876.0) - self.assertTrue(expense.employee_id in user_demo.employee_ids) + self.assertTrue(expense.employee_id in user_marc.employee_ids) def test_expense_from_email_without_product(self): - user_demo = self.env.ref('base.user_demo') + user_marc = self.env['res.users'].create({ + 'name': 'Marc User', + 'login': 'Marc', + 'email': 'marc.user@example.com', + }) + self.env['hr.employee'].create({ + 'name': 'Marc Demo', + 'user_id': user_marc.id, + }) + self.tax.price_include = False message_parsed = { 'message_id': 'the-world-is-a-ghetto', 'subject': 'no product code 9876', - 'email_from': 'mark.brown23@example.com', + 'email_from': 'marc.user@example.com', 'to': 'catchall@yourcompany.com', 'body': "Don't you know, that for me, and for you", 'attachments': [], @@ -181,11 +204,10 @@ class TestAccountEntry(TestExpenseCommon): expense = self.env['hr.expense'].message_new(message_parsed) - air_ticket = self.env.ref("hr_expense.air_ticket") self.assertFalse(expense.product_id, "No product should be linked") self.assertEqual(expense.tax_ids.ids, []) self.assertEqual(expense.total_amount, 9876.0) - self.assertTrue(expense.employee_id in user_demo.employee_ids) + self.assertTrue(expense.employee_id in user_marc.employee_ids) def test_partial_payment_multiexpense(self): bank_journal = self.env['account.journal'].create({ diff --git a/addons/hr_holidays/tests/common.py b/addons/hr_holidays/tests/common.py index 7fed7fa4b33..018e4971be7 100644 --- a/addons/hr_holidays/tests/common.py +++ b/addons/hr_holidays/tests/common.py @@ -9,6 +9,7 @@ class TestHrHolidaysBase(common.TransactionCase): def setUp(self): super(TestHrHolidaysBase, self).setUp() + self.env.user.tz = 'Europe/Brussels' # Test users to use through the various tests self.user_hruser = mail_new_test_user(self.env, login='armande', groups='base.group_user,hr_holidays.group_hr_holidays_user') diff --git a/addons/hr_holidays/tests/test_automatic_leave_dates.py b/addons/hr_holidays/tests/test_automatic_leave_dates.py index a709be09f9a..cacb1975b7d 100644 --- a/addons/hr_holidays/tests/test_automatic_leave_dates.py +++ b/addons/hr_holidays/tests/test_automatic_leave_dates.py @@ -154,6 +154,7 @@ class TestAutomaticLeaveDates(TestHrHolidaysBase): self.assertEqual(leave_form.number_of_hours_display, 8) def test_attendance_next_day(self): + self.env.user.tz = 'Europe/Brussels' calendar = self.env['resource.calendar'].create({ 'name': 'auto next day', 'attendance_ids': [(5, 0, 0), @@ -183,6 +184,7 @@ class TestAutomaticLeaveDates(TestHrHolidaysBase): self.assertEqual(leave_form.date_to, datetime(2019, 9, 2, 10, 0, 0)) def test_attendance_previous_day(self): + self.env.user.tz = 'Europe/Brussels' calendar = self.env['resource.calendar'].create({ 'name': 'auto next day', 'attendance_ids': [(5, 0, 0), @@ -212,6 +214,7 @@ class TestAutomaticLeaveDates(TestHrHolidaysBase): self.assertEqual(leave_form.date_to, datetime(2019, 9, 3, 10, 0, 0)) def test_2weeks_calendar(self): + self.env.user.tz = 'Europe/Brussels' calendar = self.env['resource.calendar'].create({ 'name': 'auto next day', 'two_weeks_calendar': True, @@ -265,6 +268,7 @@ class TestAutomaticLeaveDates(TestHrHolidaysBase): self.assertEqual(leave_form.date_to, datetime(2019, 9, 9, 10, 0, 0)) def test_2weeks_calendar_next_week(self): + self.env.user.tz = 'Europe/Brussels' calendar = self.env['resource.calendar'].create({ 'name': 'auto next day', 'two_weeks_calendar': True, diff --git a/addons/hr_holidays/tests/test_holidays_flow.py b/addons/hr_holidays/tests/test_holidays_flow.py index 54e039cc6e7..2096e3998d4 100644 --- a/addons/hr_holidays/tests/test_holidays_flow.py +++ b/addons/hr_holidays/tests/test_holidays_flow.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. - +import time from datetime import datetime from dateutil.relativedelta import relativedelta from psycopg2 import IntegrityError @@ -84,6 +84,30 @@ class TestHolidaysFlow(TestHrHolidaysBase): Allocations = self.env['hr.leave.allocation'] HolidaysStatus = self.env['hr.leave.type'] + holiday_status_paid_time_off = self.env['hr.leave.type'].create({ + 'name': 'Paid Time Off', + 'allocation_type': 'fixed', + 'validation_type': 'both', + 'validity_start': time.strftime('%Y-%m-01'), + 'responsible_id': self.env.ref('base.user_admin').id, + }) + + self.env['hr.leave.allocation'].create([ + { + 'name': 'Paid Time off for David', + 'holiday_status_id': holiday_status_paid_time_off.id, + 'number_of_days': 20, + 'employee_id': self.employee_emp_id, + 'state': 'validate', + }, { + 'name': 'Paid Time off for David', + 'holiday_status_id': holiday_status_paid_time_off.id, + 'number_of_days': 20, + 'employee_id': self.ref('hr.employee_admin'), + 'state': 'validate', + } + ]) + def _check_holidays_status(holiday_status, ml, lt, rl, vrl): self.assertEqual(holiday_status.max_leaves, ml, 'hr_holidays: wrong type days computation') @@ -172,7 +196,7 @@ class TestHolidaysFlow(TestHrHolidaysBase): employee_id = self.ref('hr.employee_admin') # cl can be of maximum 20 days for employee_admin - hol3_status = self.env.ref('hr_holidays.holiday_status_cl').with_context(employee_id=employee_id) + hol3_status = holiday_status_paid_time_off.with_context(employee_id=employee_id) # I assign the dates in the holiday request for 1 day hol3 = Requests.create({ 'name': 'Sick Time Off', @@ -201,11 +225,11 @@ class TestHolidaysFlow(TestHrHolidaysBase): # Print the HR Holidays(Summary Employee) Report through the wizard ctx = { 'model': 'hr.employee', - 'active_ids': [self.ref('hr.employee_admin'), self.ref('hr.employee_qdp'), self.ref('hr.employee_al')] + 'active_ids': [self.ref('hr.employee_admin')] } data_dict = { 'date_from': datetime.today().strftime('%Y-%m-01'), - 'emp': [(6, 0, [self.ref('hr.employee_admin'), self.ref('hr.employee_qdp'), self.ref('hr.employee_al')])], + 'emp': [(6, 0, [self.ref('hr.employee_admin')])], 'holiday_type': 'Approved' } self.env.company.external_report_layout_id = self.env.ref('web.external_layout_standard').id @@ -216,9 +240,25 @@ class TestHolidaysFlow(TestHrHolidaysBase): # error message is triggered if the date_from is after # date_to. Coming from a bug due to the new ORM 13.0 + holiday_status_paid_time_off = self.env['hr.leave.type'].create({ + 'name': 'Paid Time Off', + 'allocation_type': 'fixed', + 'validation_type': 'both', + 'validity_start': time.strftime('%Y-%m-01'), + 'responsible_id': self.env.ref('base.user_admin').id, + }) + + self.env['hr.leave.allocation'].create({ + 'name': 'Paid Time off for David', + 'holiday_status_id': holiday_status_paid_time_off.id, + 'number_of_days': 20, + 'employee_id': self.ref('hr.employee_admin'), + 'state': 'validate', + }) + leave_vals = { 'name': 'Sick Time Off', - 'holiday_status_id': self.env.ref('hr_holidays.holiday_status_cl').id, + 'holiday_status_id': holiday_status_paid_time_off.id, 'date_from': datetime.today().strftime('%Y-%m-11 19:00:00'), 'date_to': datetime.today().strftime('%Y-%m-10 10:00:00'), 'employee_id': self.ref('hr.employee_admin'), @@ -231,7 +271,7 @@ class TestHolidaysFlow(TestHrHolidaysBase): leave_vals = { 'name': 'Sick Time Off', - 'holiday_status_id': self.env.ref('hr_holidays.holiday_status_cl').id, + 'holiday_status_id': holiday_status_paid_time_off.id, 'date_from': datetime.today().strftime('%Y-%m-10 10:00:00'), 'date_to': datetime.today().strftime('%Y-%m-11 19:00:00'), 'employee_id': self.ref('hr.employee_admin'), diff --git a/addons/hr_holidays/tests/test_out_of_office.py b/addons/hr_holidays/tests/test_out_of_office.py index b2d4d26fda4..86e3f95063c 100644 --- a/addons/hr_holidays/tests/test_out_of_office.py +++ b/addons/hr_holidays/tests/test_out_of_office.py @@ -4,6 +4,7 @@ from datetime import datetime from dateutil.relativedelta import relativedelta +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo from odoo.tests.common import tagged, users, warmup, Form from odoo.addons.hr_holidays.tests.common import TestHrHolidaysBase @@ -54,7 +55,7 @@ class TestOutOfOffice(TestHrHolidaysBase): self.assertEqual(infos[0]['direct_partner'][0]['out_of_office_date_end'], leave_date_end) @tagged('out_of_office') -class TestOutOfOfficePerformance(TestHrHolidaysBase): +class TestOutOfOfficePerformance(TestHrHolidaysBase, TransactionCaseWithUserDemo): def setUp(self): super(TestOutOfOfficePerformance, self).setUp() diff --git a/addons/hr_recruitment/tests/test_recruitment_process.py b/addons/hr_recruitment/tests/test_recruitment_process.py index 0eebc5fe5f8..5ed9af75b2f 100644 --- a/addons/hr_recruitment/tests/test_recruitment_process.py +++ b/addons/hr_recruitment/tests/test_recruitment_process.py @@ -2,10 +2,11 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo.tests import common +from odoo.addons.hr.tests.test_hr_flow import TestHrFlow from odoo.modules.module import get_module_resource -class TestRecruitmentProcess(common.TransactionCase): +class TestRecruitmentProcess(TestHrFlow): def test_00_recruitment_process(self): """ Test recruitment process """ @@ -24,7 +25,7 @@ class TestRecruitmentProcess(common.TransactionCase): with open(get_module_resource('hr_recruitment', 'tests', 'resume.eml'), 'rb') as request_file: request_message = request_file.read() self.env['mail.thread'].with_user(self.res_users_hr_recruitment_officer).message_process( - 'hr.applicant', request_message, custom_values={"job_id": self.env.ref('hr.job_developer').id}) + 'hr.applicant', request_message, custom_values={"job_id": self.job_developer.id}) # After getting the mail, I check the details of the new applicant. applicant = self.env['hr.applicant'].search([('email_from', 'ilike', 'Richard_Anderson@yahoo.com')], limit=1) @@ -38,7 +39,7 @@ class TestRecruitmentProcess(common.TransactionCase): "Stage should be 'Initial qualification' and is '%s'." % (applicant.stage_id.name)) self.assertTrue(resume_ids, 'Resume is not attached.') # I assign the Job position to the applicant - applicant.write({'job_id': self.env.ref('hr.job_developer').id}) + applicant.write({'job_id': self.job_developer.id}) # I schedule meeting with applicant for interview. applicant_meeting = applicant.action_makeMeeting() self.assertEqual(applicant_meeting['context']['default_name'], 'Application for the post of Jr.application Programmer.', diff --git a/addons/hr_timesheet/tests/test_timesheet.py b/addons/hr_timesheet/tests/test_timesheet.py index fed0c53b953..2245c40707e 100644 --- a/addons/hr_timesheet/tests/test_timesheet.py +++ b/addons/hr_timesheet/tests/test_timesheet.py @@ -10,6 +10,13 @@ class TestCommonTimesheet(TransactionCase): def setUp(self): super(TestCommonTimesheet, self).setUp() + # Crappy hack to disable the rule from timesheet grid, if it exists + # The registry doesn't contain the field timesheet_manager_id. + # but there is an ir.rule about it, crashing during its evaluation + rule = self.env.ref('timesheet_grid.hr_timesheet_rule_approver_update', raise_if_not_found=False) + if rule: + rule.active = False + # customer partner self.partner = self.env['res.partner'].create({ 'name': 'Customer Task', diff --git a/addons/lunch/tests/test_supplier.py b/addons/lunch/tests/test_supplier.py index bc1da3bb880..3048237d9d1 100644 --- a/addons/lunch/tests/test_supplier.py +++ b/addons/lunch/tests/test_supplier.py @@ -42,6 +42,7 @@ class TestSupplier(TestsCommon): ''' This test checks that _search_available_today returns a valid domain ''' + self.env.user.tz = 'Europe/Brussels' Supplier = self.env['lunch.supplier'] tests = [(self.monday_1am, 1.0, 'monday'), (self.monday_10am, 10.0, 'monday'), diff --git a/addons/maintenance/tests/test_maintenance.py b/addons/maintenance/tests/test_maintenance.py index e4decedb583..e4acceb1767 100644 --- a/addons/maintenance/tests/test_maintenance.py +++ b/addons/maintenance/tests/test_maintenance.py @@ -36,12 +36,17 @@ class TestEquipment(TransactionCase): groups_id=[(6, 0, [res_manager.id])] )) + self.equipment_monitor = self.env['maintenance.equipment.category'].create({ + 'name': 'Monitors', + 'alias_id': self.env.ref('maintenance.mail_alias_equipment').id, + }) + def test_10_equipment_request_category(self): # Create a new equipment equipment_01 = self.equipment.with_user(self.manager).create({ 'name': 'Samsung Monitor "15', - 'category_id': self.ref('maintenance.equipment_monitor'), + 'category_id': self.equipment_monitor.id, 'technician_user_id': self.ref('base.user_root'), 'owner_user_id': self.user.id, 'assign_date': time.strftime('%Y-%m-%d'), @@ -80,7 +85,7 @@ class TestEquipment(TransactionCase): """ Check the cron creates the necessary preventive maintenance requests""" equipment_cron = self.equipment.create({ 'name': 'High Maintenance Monitor because of Color Calibration', - 'category_id': self.ref('maintenance.equipment_monitor'), + 'category_id': self.equipment_monitor.id, 'technician_user_id': self.ref('base.user_root'), 'owner_user_id': self.user.id, 'assign_date': time.strftime('%Y-%m-%d'), @@ -113,7 +118,7 @@ class TestEquipment(TransactionCase): }) equipment = self.equipment.create({ 'name': 'High Maintenance Monitor because of Color Calibration', - 'category_id': self.ref('maintenance.equipment_monitor'), + 'category_id': self.equipment_monitor.id, 'technician_user_id': self.ref('base.user_root'), 'owner_user_id': self.user.id, 'assign_date': time.strftime('%Y-%m-%d'), diff --git a/addons/mass_mailing/tests/test_mass_mailing_shortener.py b/addons/mass_mailing/tests/test_mass_mailing_shortener.py index c755a6754c4..8bd247691ea 100644 --- a/addons/mass_mailing/tests/test_mass_mailing_shortener.py +++ b/addons/mass_mailing/tests/test_mass_mailing_shortener.py @@ -71,7 +71,7 @@ Email: test@odoo.com sent_mails = self.env['mail.mail'].search([('mailing_id', '=', mass_mailing.id)]) sent_messages = sent_mails.mapped('mail_message_id') - self.assertEqual(mailing_list_A.contact_nbr, len(sent_messages), + self.assertEqual(len(mailing_list_A.contact_ids), len(sent_messages), 'Some message has not been sent') xbody = etree.fromstring(sent_messages[0].body) diff --git a/addons/membership/__manifest__.py b/addons/membership/__manifest__.py index d2d4ad1f6bd..4edfa42c9bb 100644 --- a/addons/membership/__manifest__.py +++ b/addons/membership/__manifest__.py @@ -30,7 +30,4 @@ invoice and send propositions for membership renewal. 'report/report_membership_views.xml', ], 'website': 'https://www.odoo.com/page/community-builder', - 'test': [ - '../account/test/account_minimal_test.xml', - ], } diff --git a/addons/mrp/tests/common.py b/addons/mrp/tests/common.py index b9592d4720e..382bbb849fe 100644 --- a/addons/mrp/tests/common.py +++ b/addons/mrp/tests/common.py @@ -154,3 +154,27 @@ class TestMrpCommon(common2.TestStockCommon): (0, 0, {'product_id': cls.product_4.id, 'product_qty': 8}), (0, 0, {'product_id': cls.product_2.id, 'product_qty': 12}) ]}) + cls.stock_location_14 = cls.env['stock.location'].create({ + 'name': 'Shelf 2', + 'location_id': cls.env.ref('stock.warehouse0').lot_stock_id.id, + }) + cls.stock_location_components = cls.env['stock.location'].create({ + 'name': 'Shelf 1', + 'location_id': cls.env.ref('stock.warehouse0').lot_stock_id.id, + }) + cls.laptop = cls.env['product.product'].create({ + 'name': 'Acoustic Bloc Screens', + 'uom_id': cls.env.ref("uom.product_uom_unit").id, + 'uom_po_id': cls.env.ref("uom.product_uom_unit").id, + 'type': 'product', + 'tracking': 'none', + 'categ_id': cls.env.ref('product.product_category_all').id, + }) + cls.graphics_card = cls.env['product.product'].create({ + 'name': 'Individual Workplace', + 'uom_id': cls.env.ref("uom.product_uom_unit").id, + 'uom_po_id': cls.env.ref("uom.product_uom_unit").id, + 'type': 'product', + 'tracking': 'none', + 'categ_id': cls.env.ref('product.product_category_all').id, + }) \ No newline at end of file diff --git a/addons/mrp/tests/test_order.py b/addons/mrp/tests/test_order.py index 3cd315da16b..c7d06af6aea 100644 --- a/addons/mrp/tests/test_order.py +++ b/addons/mrp/tests/test_order.py @@ -131,7 +131,7 @@ class TestMrpOrder(TestMrpCommon): self.env['stock.quant'].with_context(inventory_mode=True).create({ 'product_id': self.product_2.id, 'inventory_quantity': 2.0, - 'location_id': self.ref('stock.stock_location_14') + 'location_id': self.stock_location_14.id }) production_2.action_assign() @@ -142,7 +142,7 @@ class TestMrpOrder(TestMrpCommon): self.env['stock.quant'].with_context(inventory_mode=True).create({ 'product_id': self.product_2.id, 'inventory_quantity': 5.0, - 'location_id': self.ref('stock.stock_location_14') + 'location_id': self.stock_location_14.id }) production_2.action_assign() @@ -163,8 +163,13 @@ class TestMrpOrder(TestMrpCommon): # create a bom for `custom_laptop` with components that aren't tracked unit = self.ref("uom.product_uom_unit") - custom_laptop = self.env.ref("product.product_product_27") - custom_laptop.tracking = 'none' + custom_laptop = self.env['product.product'].create({ + 'name': 'Drawer', + 'type': 'product', + 'uom_id': unit, + 'uom_po_id': unit, + }) + product_charger = self.env['product.product'].create({ 'name': 'Charger', 'type': 'product', @@ -191,7 +196,7 @@ class TestMrpOrder(TestMrpCommon): }) # put the needed products in stock - source_location_id = self.ref('stock.stock_location_14') + source_location_id = self.stock_location_14.id quant_before = custom_laptop.qty_available inventory = self.env['stock.inventory'].create({ 'name': 'Inventory Product Table', @@ -463,8 +468,9 @@ class TestMrpOrder(TestMrpCommon): """ # FIXME: some asserts on the quants after overproducing would be nice self.stock_location = self.env.ref('stock.stock_location_stock') - self.stock_shelf_1 = self.env.ref('stock.stock_location_components') - self.stock_shelf_2 = self.env.ref('stock.stock_location_14') + self.stock_shelf_1 = self.stock_location_components + + self.stock_shelf_2 = self.stock_location_14 mo, _, p_final, p1, p2 = self.generate_mo(tracking_base_1='lot', qty_base_1=10, qty_final=1) self.assertEqual(len(mo), 1, 'MO should have been created') @@ -530,8 +536,8 @@ class TestMrpOrder(TestMrpCommon): """ Possibility to produce with a given raw material in multiple locations. """ # FIXME sle: how is it possible to consume before producing in the interface? self.stock_location = self.env.ref('stock.stock_location_stock') - self.stock_shelf_1 = self.env.ref('stock.stock_location_components') - self.stock_shelf_2 = self.env.ref('stock.stock_location_14') + self.stock_shelf_1 = self.stock_location_components + self.stock_shelf_2 = self.stock_location_14 mo, _, p_final, p1, p2 = self.generate_mo(qty_final=1, qty_base_1=5) self.env['stock.quant']._update_available_quantity(p1, self.stock_shelf_1, 2) @@ -616,8 +622,8 @@ class TestMrpOrder(TestMrpCommon): self.assertEqual(len(mo), 1, 'MO should have been created') self.stock_location = self.env.ref('stock.stock_location_stock') - self.stock_shelf_1 = self.env.ref('stock.stock_location_components') - self.stock_shelf_2 = self.env.ref('stock.stock_location_14') + self.stock_shelf_1 = self.stock_location_components + self.stock_shelf_2 = self.stock_location_14 self.env['stock.quant']._update_available_quantity(p1, self.stock_shelf_1, 3) self.env['stock.quant']._update_available_quantity(p1, self.stock_location, 3) @@ -1146,13 +1152,36 @@ class TestMrpOrder(TestMrpCommon): """ Produce a finished product tracked by serial number. Set another UoM on the bom. The produce wizard should keep the UoM of the product (unit) and quantity = 1.""" - - plastic_laminate = self.env.ref('mrp.product_product_plastic_laminate') - bom = self.env.ref('mrp.mrp_bom_plastic_laminate') dozen = self.env.ref('uom.product_uom_dozen') unit = self.env.ref('uom.product_uom_unit') - - plastic_laminate.tracking = 'serial' + plastic_laminate = self.env['product.product'].create({ + 'name': 'Plastic Laminate', + 'type': 'product', + 'uom_id': unit.id, + 'uom_po_id': unit.id, + 'tracking': 'serial', + }) + ply_veneer = self.env['product.product'].create({ + 'name': 'Ply Veneer', + 'type': 'product', + 'uom_id': unit.id, + 'uom_po_id': unit.id, + }) + routing = self.env['mrp.routing'].create({ + 'name': 'Secondary Assembly', + }) + bom = self.env['mrp.bom'].create({ + 'product_tmpl_id': plastic_laminate.product_tmpl_id.id, + 'product_uom_id': unit.id, + 'sequence': 1, + 'routing_id': routing.id, + 'bom_line_ids': [(0, 0, { + 'product_id': ply_veneer.id, + 'product_qty': 1, + 'product_uom_id': unit.id, + 'sequence': 1, + })] + }) mo_form = Form(self.env['mrp.production']) mo_form.product_id = plastic_laminate diff --git a/addons/mrp/tests/test_stock.py b/addons/mrp/tests/test_stock.py index c80e2bdf420..2c03f3234c1 100644 --- a/addons/mrp/tests/test_stock.py +++ b/addons/mrp/tests/test_stock.py @@ -10,6 +10,7 @@ class TestWarehouse(common.TestMrpCommon): def setUp(self): super(TestWarehouse, self).setUp() + unit = self.env.ref("uom.product_uom_unit") self.stock_location = self.env.ref('stock.stock_location_stock') self.depot_location = self.env['stock.location'].create({ 'name': 'Depot', @@ -21,18 +22,35 @@ class TestWarehouse(common.TestMrpCommon): "location_out_id": self.depot_location.id, 'category_id': self.env.ref('product.product_category_all').id, }) - - self.laptop = self.env.ref("product.product_product_25") - graphics_card = self.env.ref("product.product_product_24") - unit = self.env.ref("uom.product_uom_unit") - mrp_routing = self.env.ref("mrp.mrp_routing_0") + mrp_workcenter = self.env['mrp.workcenter'].create({ + 'name': 'Assembly Line 1', + 'resource_calendar_id': self.env.ref('resource.resource_calendar_std').id, + }) + mrp_routing = self.env['mrp.routing'].create({ + 'name': 'Primary Assembly', + 'operation_ids': [(0, 0, { + 'workcenter_id': mrp_workcenter.id, + 'name': 'Manual Assembly', + })] + }) + inventory = self.env['stock.inventory'].create({ + 'name': 'Initial inventory', + 'line_ids': [(0, 0, { + 'product_id': self.graphics_card.id, + 'product_uom_id': self.graphics_card.uom_id.id, + 'product_qty': 16.0, + 'location_id': self.stock_location_14.id, + })] + }) + inventory.action_start() + inventory.action_validate() self.bom_laptop = self.env['mrp.bom'].create({ 'product_tmpl_id': self.laptop.product_tmpl_id.id, 'product_qty': 1, 'product_uom_id': unit.id, 'bom_line_ids': [(0, 0, { - 'product_id': graphics_card.id, + 'product_id': self.graphics_card.id, 'product_qty': 1, 'product_uom_id': unit.id })], @@ -102,14 +120,14 @@ class TestWarehouse(common.TestMrpCommon): 'name': 'Stock Inventory for Stick', 'product_ids': [(4, self.product_4.id)], 'line_ids': [ - (0, 0, {'product_id': self.product_4.id, 'product_uom_id': self.product_4.uom_id.id, 'product_qty': 8, 'prod_lot_id': lot_product_4.id, 'location_id': self.ref('stock.stock_location_14')}), + (0, 0, {'product_id': self.product_4.id, 'product_uom_id': self.product_4.uom_id.id, 'product_qty': 8, 'prod_lot_id': lot_product_4.id, 'location_id': self.stock_location_14.id}), ]}) stock_inv_product_2 = self.env['stock.inventory'].create({ 'name': 'Stock Inventory for Stone Tools', 'product_ids': [(4, self.product_2.id)], 'line_ids': [ - (0, 0, {'product_id': self.product_2.id, 'product_uom_id': self.product_2.uom_id.id, 'product_qty': 12, 'prod_lot_id': lot_product_2.id, 'location_id': self.ref('stock.stock_location_14')}) + (0, 0, {'product_id': self.product_2.id, 'product_uom_id': self.product_2.uom_id.id, 'product_qty': 12, 'prod_lot_id': lot_product_2.id, 'location_id': self.stock_location_14.id}) ]}) (stock_inv_product_4 | stock_inv_product_2)._action_start() stock_inv_product_2.action_validate() diff --git a/addons/mrp/tests/test_unbuild.py b/addons/mrp/tests/test_unbuild.py index d59679265c3..bf5c6e25f47 100644 --- a/addons/mrp/tests/test_unbuild.py +++ b/addons/mrp/tests/test_unbuild.py @@ -5,11 +5,13 @@ from odoo.tests import Form from odoo.addons.mrp.tests.common import TestMrpCommon from odoo.exceptions import UserError - class TestUnbuild(TestMrpCommon): def setUp(self): super(TestUnbuild, self).setUp() self.stock_location = self.env.ref('stock.stock_location_stock') + self.env.ref('base.group_user').write({ + 'implied_ids': [(4, self.env.ref('stock.group_production_lot').id)] + }) def test_unbuild_standart(self): """ This test creates a MO and then creates 3 unbuild diff --git a/addons/mrp/tests/test_workorder_operation.py b/addons/mrp/tests/test_workorder_operation.py index ee2c3bff2ad..4e0458fc068 100644 --- a/addons/mrp/tests/test_workorder_operation.py +++ b/addons/mrp/tests/test_workorder_operation.py @@ -26,7 +26,7 @@ class TestWorkOrderProcess(TestMrpCommon): @classmethod def setUpClass(cls): super(TestWorkOrderProcess, cls).setUpClass() - cls.source_location_id = cls.env.ref('stock.stock_location_14').id + cls.source_location_id = cls.stock_location_14.id cls.warehouse = cls.env.ref('stock.warehouse0') # setting up alternative workcenters cls.wc_alt_1 = cls.env['mrp.workcenter'].create({ @@ -55,22 +55,118 @@ class TestWorkOrderProcess(TestMrpCommon): (0, 0, {'product_id': cls.product_2.id, 'product_qty': 2}), (0, 0, {'product_id': cls.product_1.id, 'product_qty': 4}) ]}) + cls.dining_table = cls.env['product.product'].create({ + 'name': 'Table (MTO)', + 'type': 'product', + 'tracking': 'serial', + }) + cls.product_table_sheet = cls.env['product.product'].create({ + 'name': 'Table Top', + 'type': 'product', + 'tracking': 'serial', + }) + cls.product_table_leg = cls.env['product.product'].create({ + 'name': 'Table Leg', + 'type': 'product', + 'tracking': 'lot', + }) + cls.product_bolt = cls.env['product.product'].create({ + 'name': 'Bolt', + 'type': 'product', + }) + cls.product_screw = cls.env['product.product'].create({ + 'name': 'Screw', + 'type': 'product', + }) + + cls.mrp_workcenter = cls.env['mrp.workcenter'].create({ + 'name': 'Assembly Line 1', + 'resource_calendar_id': cls.env.ref('resource.resource_calendar_std').id, + }) + cls.routing = cls.env['mrp.routing'].create({ + 'name': 'Assemble Furniture', + 'operation_ids': [(0, 0, { + 'workcenter_id': cls.mrp_workcenter.id, + 'name': 'Manual Assembly', + })] + }) + cls.mrp_bom_desk = cls.env['mrp.bom'].create({ + 'product_tmpl_id': cls.dining_table.product_tmpl_id.id, + 'product_uom_id': cls.env.ref('uom.product_uom_unit').id, + 'sequence': 3, + 'consumption': 'flexible', + 'routing_id': cls.routing.id, + 'bom_line_ids': [ + (0, 0, { + 'product_id': cls.product_table_sheet.id, + 'product_qty': 1, + 'product_uom_id': cls.env.ref('uom.product_uom_unit').id, + 'sequence': 1, + 'operation_id': cls.routing.operation_ids.id}), + (0, 0, { + 'product_id': cls.product_table_leg.id, + 'product_qty': 4, + 'product_uom_id': cls.env.ref('uom.product_uom_unit').id, + 'sequence': 2, + 'operation_id': cls.routing.operation_ids.id}), + (0, 0, { + 'product_id': cls.product_bolt.id, + 'product_qty': 4, + 'product_uom_id': cls.env.ref('uom.product_uom_unit').id, + 'sequence': 3, + 'operation_id': cls.routing.operation_ids.id}), + (0, 0, { + 'product_id': cls.product_screw.id, + 'product_qty': 10, + 'product_uom_id': cls.env.ref('uom.product_uom_unit').id, + 'sequence': 4, + 'operation_id': cls.routing.operation_ids.id}), + ] + }) + cls.mrp_workcenter_1 = cls.env['mrp.workcenter'].create({ + 'name': 'Drill Station 1', + 'resource_calendar_id': cls.env.ref('resource.resource_calendar_std').id, + }) + cls.mrp_workcenter_3 = cls.env['mrp.workcenter'].create({ + 'name': 'Assembly Line 1', + 'resource_calendar_id': cls.env.ref('resource.resource_calendar_std').id, + }) + cls.routing_1 = cls.env['mrp.routing'].create({ + 'name': 'Secondary Assembly', + 'operation_ids': [ + (0, 0, { + 'workcenter_id': cls.mrp_workcenter_1.id, + 'name': 'Packing', + 'time_cycle': 30, + 'sequence': 5}), + (0, 0, { + 'workcenter_id': cls.mrp_workcenter_3.id, + 'name': 'Testing', + 'time_cycle': 60, + 'sequence': 10}), + (0, 0, { + 'workcenter_id': cls.mrp_workcenter_3.id, + 'name': 'Long time assembly', + 'time_cycle': 180, + 'sequence': 15}), + ] + }) + def test_00_workorder_process(self): """ Testing consume quants and produced quants with workorder """ + dining_table = self.dining_table + product_table_sheet = self.product_table_sheet + product_table_leg = self.product_table_leg + product_bolt = self.product_bolt + product_screw = self.product_screw + mrp_bom_desk = self.mrp_bom_desk - dining_table = self.env.ref("mrp.product_product_computer_desk") - product_table_sheet = self.env.ref('mrp.product_product_computer_desk_head') - product_table_leg = self.env.ref('mrp.product_product_computer_desk_leg') - product_bolt = self.env.ref('mrp.product_product_computer_desk_bolt') - product_screw = self.env.ref('mrp.product_product_computer_desk_screw') self.env['stock.move'].search([('product_id', 'in', [product_bolt.id, product_screw.id])])._do_unreserve() - (product_bolt + product_screw).write({'type': 'product'}) - self.env.ref("mrp.mrp_bom_desk").consumption = 'flexible' production_table_form = Form(self.env['mrp.production']) production_table_form.product_id = dining_table - production_table_form.bom_id = self.env.ref("mrp.mrp_bom_desk") + production_table_form.bom_id = mrp_bom_desk production_table_form.product_qty = 1.0 production_table_form.product_uom_id = dining_table.uom_id production_table = production_table_form.save() @@ -145,6 +241,12 @@ class TestWorkOrderProcess(TestMrpCommon): if workorder_line_id.product_id.id == product_table_leg.id: workorder_line_id.write({'lot_id': lot_leg.id, 'qty_done': 1}) self.assertEqual(workorder.state, 'progress') + + # YTI Clean that brol + # If mrp_workorder is installed, there could be checks defined on the + # workorder. + if hasattr(self.env['mrp.workorder'], 'check_ids'): + self.env['mrp.workorder'].search([]).write({'check_ids': False}) workorder.record_production() self.assertEqual(workorder.state, 'done') move_table_sheet = production_table.move_raw_ids.filtered(lambda x : x.product_id == product_table_sheet) @@ -162,16 +264,16 @@ class TestWorkOrderProcess(TestMrpCommon): def test_00b_workorder_process(self): """ Testing consume quants and produced quants with workorder """ - dining_table = self.env.ref("mrp.product_product_computer_desk") - product_table_sheet = self.env.ref('mrp.product_product_computer_desk_head') - product_table_leg = self.env.ref('mrp.product_product_computer_desk_leg') - product_bolt = self.env.ref('mrp.product_product_computer_desk_bolt') - self.env['stock.move'].search([('product_id', '=', product_bolt.id)])._do_unreserve() - product_bolt.type = 'product' + dining_table = self.dining_table + product_table_sheet = self.product_table_sheet + product_table_leg = self.product_table_leg + product_bolt = self.product_bolt + product_screw = self.product_screw + bom = self.mrp_bom_desk - bom = self.env['mrp.bom'].browse(self.ref("mrp.mrp_bom_desk")) - bom.routing_id = self.ref('mrp.mrp_routing_1') - bom.consumption = 'flexible' + self.env['stock.move'].search([('product_id', '=', product_bolt.id)])._do_unreserve() + + bom.routing_id = self.routing_1 bom.bom_line_ids.filtered(lambda p: p.product_id == product_table_sheet).operation_id = bom.routing_id.operation_ids[0] bom.bom_line_ids.filtered(lambda p: p.product_id == product_table_leg).operation_id = bom.routing_id.operation_ids[1] @@ -243,6 +345,12 @@ class TestWorkOrderProcess(TestMrpCommon): workorders[0].button_start() workorders[0]._workorder_line_ids()[0].write({'lot_id': lot_sheet.id, 'qty_done': 1}) self.assertEqual(workorders[0].state, 'progress') + + # YTI Clean that brol + # If mrp_workorder is installed, there could be checks defined on the + # workorder. + if hasattr(self.env['mrp.workorder'], 'check_ids'): + self.env['mrp.workorder'].search([]).write({'check_ids': False}) workorders[0].record_production() move_table_sheet = production_table.move_raw_ids.filtered(lambda p: p.product_id == product_table_sheet) @@ -352,18 +460,18 @@ class TestWorkOrderProcess(TestMrpCommon): 'product_uom_id': self.product_2.uom_id.id, 'product_qty': 30, 'prod_lot_id': lot_product_2.id, - 'location_id': self.ref('stock.stock_location_14') + 'location_id': self.stock_location_14.id }), (0, 0, { 'product_id': self.product_3.id, 'product_uom_id': self.product_3.uom_id.id, 'product_qty': 60, - 'location_id': self.ref('stock.stock_location_14') + 'location_id': self.stock_location_14.id }), (0, 0, { 'product_id': self.product_4.id, 'product_uom_id': self.product_4.uom_id.id, 'product_qty': 60, 'prod_lot_id': lot_product_4.id, - 'location_id': self.ref('stock.stock_location_14') + 'location_id': self.stock_location_14.id })] }) inventory.action_start() @@ -428,8 +536,11 @@ class TestWorkOrderProcess(TestMrpCommon): def test_01_without_workorder(self): """ Testing consume quants and produced quants without workorder """ unit = self.ref("uom.product_uom_unit") - custom_laptop = self.env.ref("product.product_product_27") - custom_laptop.tracking = 'lot' + custom_laptop = self.env['product.product'].create({ + 'name': 'Drawer', + 'type': 'product', + 'tracking': 'lot', + }) # Create new product charger and keybord # -------------------------------------- @@ -710,10 +821,10 @@ class TestWorkOrderProcess(TestMrpCommon): def test_03_test_serial_number_defaults(self): """ Test that the correct serial number is suggested on consecutive work orders. """ - laptop = self.env.ref("product.product_product_25") - graphics_card = self.env.ref("product.product_product_24") + laptop = self.laptop + graphics_card = self.graphics_card unit = self.env.ref("uom.product_uom_unit") - three_step_routing = self.env.ref("mrp.mrp_routing_1") + three_step_routing = self.routing_1 laptop.tracking = 'serial' @@ -769,7 +880,55 @@ class TestWorkOrderProcess(TestMrpCommon): serial number. It should be allowed since the first workorder did not specify a seiral number. """ - bom = self.env.ref('mrp.mrp_bom_laptop_cust_rout') + drawer = self.env['product.product'].create({ + 'name': 'Drawer', + 'type': 'product', + 'tracking': 'lot', + }) + drawer_drawer = self.env['product.product'].create({ + 'name': 'Drawer Black', + 'type': 'product', + 'tracking': 'lot', + }) + drawer_case = self.env['product.product'].create({ + 'name': 'Drawer Case Black', + 'type': 'product', + 'tracking': 'lot', + }) + bom = self.env['mrp.bom'].create({ + 'product_tmpl_id': drawer.product_tmpl_id.id, + 'product_uom_id': self.env.ref('uom.product_uom_unit').id, + 'sequence': 2, + 'routing_id': self.routing_1.id, + 'bom_line_ids': [(0, 0, { + 'product_id': drawer_drawer.id, + 'product_qty': 1, + 'product_uom_id': self.env.ref('uom.product_uom_unit').id, + 'sequence': 1, + }), (0, 0, { + 'product_id': drawer_case.id, + 'product_qty': 1, + 'product_uom_id': self.env.ref('uom.product_uom_unit').id, + 'sequence': 2, + })] + }) + inventory = self.env['stock.inventory'].create({ + 'name': 'Initial inventory', + 'line_ids': [(0, 0, { + 'product_id': drawer_drawer.id, + 'product_uom_id': drawer_drawer.uom_id.id, + 'product_qty': 50.0, + 'location_id': self.stock_location_14.id, + }), (0, 0, { + 'product_id': drawer_case.id, + 'product_uom_id': drawer_case.uom_id.id, + 'product_qty': 50.0, + 'location_id': self.stock_location_14.id, + })] + }) + inventory.action_start() + inventory.action_validate() + product = bom.product_tmpl_id.product_variant_id product.tracking = 'serial' @@ -828,11 +987,11 @@ class TestWorkOrderProcess(TestMrpCommon): # The workcenter is working 24/7 self.full_availability() - dining_table = self.env.ref("mrp.product_product_computer_desk") + dining_table = self.dining_table production_table_form = Form(self.env['mrp.production']) production_table_form.product_id = dining_table - production_table_form.bom_id = self.env.ref("mrp.mrp_bom_desk") + production_table_form.bom_id = self.mrp_bom_desk production_table_form.product_qty = 1.0 production_table_form.product_uom_id = dining_table.uom_id production_table = production_table_form.save() @@ -851,13 +1010,13 @@ class TestWorkOrderProcess(TestMrpCommon): # The workcenter is working 24/7 self.full_availability() - dining_table = self.env.ref("mrp.product_product_computer_desk") + dining_table = self.dining_table date_start = datetime.now() + timedelta(days=1) production_table_form = Form(self.env['mrp.production']) production_table_form.product_id = dining_table - production_table_form.bom_id = self.env.ref("mrp.mrp_bom_desk") + production_table_form.bom_id = self.mrp_bom_desk production_table_form.product_qty = 1.0 production_table_form.product_uom_id = dining_table.uom_id production_table_form.date_start_wo = date_start @@ -874,11 +1033,11 @@ class TestWorkOrderProcess(TestMrpCommon): def test_change_production_1(self): """Change the quantity to produce on the MO while workorders are already planned.""" - dining_table = self.env.ref("mrp.product_product_computer_desk") + dining_table = self.dining_table dining_table.tracking = 'lot' production_table_form = Form(self.env['mrp.production']) production_table_form.product_id = dining_table - production_table_form.bom_id = self.env.ref("mrp.mrp_bom_desk") + production_table_form.bom_id = self.mrp_bom_desk production_table_form.product_qty = 1.0 production_table_form.product_uom_id = dining_table.uom_id production_table = production_table_form.save() @@ -1067,7 +1226,20 @@ class TestWorkOrderProcess(TestMrpCommon): production sooner """ self.workcenter_1.alternative_workcenter_ids = self.wc_alt_1 | self.wc_alt_2 self.env['mrp.workcenter'].search([]).write({'tz': 'UTC'}) # compute all date in UTC - self.planning_bom.routing = self.env.ref("mrp.mrp_routing_0") + mrp_routing_0 = self.env['mrp.routing'].create({ + 'name': 'Primary Assembly', + }) + mrp_workcenter_3 = self.env['mrp.workcenter'].create({ + 'name': 'Assembly Line 1', + 'resource_calendar_id': self.env.ref('resource.resource_calendar_std').id, + }) + mrp_routing_workcenter_0 = self.env['mrp.routing.workcenter'].create({ + 'routing_id': mrp_routing_0.id, + 'workcenter_id': mrp_workcenter_3.id, + 'name': 'Manual Assembly', + 'time_cycle': 60, + }) + self.planning_bom.routing = mrp_routing_0 mo_form = Form(self.env['mrp.production']) mo_form.product_id = self.product_4 mo_form.bom_id = self.planning_bom @@ -1172,11 +1344,12 @@ class TestWorkOrderProcess(TestMrpCommon): mo.action_assign() mo.button_plan() - self.assertEqual(len(mo.workorder_ids), 1) - self.assertEqual(len(mo.workorder_ids.raw_workorder_line_ids), 3) - line1 = mo.workorder_ids.raw_workorder_line_ids[0] - line2 = mo.workorder_ids.raw_workorder_line_ids[1] - line3 = mo.workorder_ids.raw_workorder_line_ids[2] + self.assertEqual(len(mo.workorder_ids), 3) + long_time_assembly = mo.workorder_ids[2] + self.assertEqual(len(long_time_assembly.raw_workorder_line_ids), 3) + line1 = long_time_assembly.raw_workorder_line_ids[0] + line2 = long_time_assembly.raw_workorder_line_ids[1] + line3 = long_time_assembly.raw_workorder_line_ids[2] self.assertEqual(line1.product_id, self.product_1) self.assertEqual(line1.qty_done, 1) self.assertEqual(line2.product_id, self.product_2) diff --git a/addons/mrp_account/tests/test_mrp_account.py b/addons/mrp_account/tests/test_mrp_account.py index ed35c0da1ff..680d4d9a994 100644 --- a/addons/mrp_account/tests/test_mrp_account.py +++ b/addons/mrp_account/tests/test_mrp_account.py @@ -1,41 +1,44 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo.addons.mrp.tests.test_workorder_operation import TestWorkOrderProcess from odoo.tests import Form from odoo.tests import common -class TestMrpAccount(common.TransactionCase): +class TestMrpAccount(TestWorkOrderProcess): - def setUp(self): - super(TestMrpAccount, self).setUp() - self.categ_standard = self.env['product.category'].create({'name': 'STANDARD', - 'property_cost_method': 'standard',},) - self.categ_real = self.env['product.category'].create({'name': 'REAL', - 'property_cost_method': 'fifo',}) - self.categ_average = self.env['product.category'].create({'name': 'AVERAGE', - 'property_cost_method': 'average'}) - self.dining_table = self.env.ref("mrp.product_product_computer_desk") - self.dining_table.categ_id = self.categ_real.id - self.product_table_sheet = self.env.ref('mrp.product_product_computer_desk_head') - self.product_table_sheet.categ_id = self.categ_real.id - self.product_table_leg = self.env.ref('mrp.product_product_computer_desk_leg') - self.product_table_leg.categ_id = self.categ_average.id - self.product_bolt = self.env.ref('mrp.product_product_computer_desk_bolt') - self.product_bolt.categ_id = self.categ_standard.id - self.source_location_id = self.ref('stock.stock_location_14') - self.product_screw = self.env.ref('mrp.product_product_computer_desk_screw') - self.product_screw.categ_id = self.categ_standard.id - self.env['stock.move'].search([('product_id', 'in', [self.product_bolt.id, self.product_screw.id])])._do_unreserve() - (self.product_bolt + self.product_screw).write({'type': 'product'}) - self.product_desk = self.env.ref('mrp.product_product_computer_desk') - self.product_desk.tracking = 'none' + @classmethod + def setUpClass(cls): + super(TestMrpAccount, cls).setUpClass() + + cls.categ_standard = cls.env['product.category'].create({ + 'name': 'STANDARD', + 'property_cost_method': 'standard' + }) + cls.categ_real = cls.env['product.category'].create({ + 'name': 'REAL', + 'property_cost_method': 'fifo' + }) + cls.categ_average = cls.env['product.category'].create({ + 'name': 'AVERAGE', + 'property_cost_method': 'average' + }) + cls.dining_table.categ_id = cls.categ_real.id + cls.product_table_sheet.categ_id = cls.categ_real.id + cls.product_table_leg.categ_id = cls.categ_average.id + cls.product_bolt.categ_id = cls.categ_standard.id + cls.product_screw.categ_id = cls.categ_standard.id + cls.env['stock.move'].search([('product_id', 'in', [cls.product_bolt.id, cls.product_screw.id])])._do_unreserve() + (cls.product_bolt + cls.product_screw).write({'type': 'product'}) + cls.dining_table.tracking = 'none' def test_00_production_order_with_accounting(self): self.product_table_sheet.standard_price = 20.0 self.product_table_leg.standard_price = 15.0 self.product_bolt.standard_price = 10.0 + self.product_screw.standard_price = 0.1 self.product_table_leg.tracking = 'none' self.product_table_sheet.tracking = 'none' inventory = self.env['stock.inventory'].create({ @@ -64,7 +67,7 @@ class TestMrpAccount(common.TransactionCase): ] }) inventory.action_validate - bom = self.env.ref('mrp.mrp_bom_desk').copy() + bom = self.mrp_bom_desk.copy() bom.routing_id = False # TODO: extend the test later with the necessary operations production_table_form = Form(self.env['mrp.production']) production_table_form.product_id = self.dining_table @@ -87,15 +90,3 @@ class TestMrpAccount(common.TransactionCase): # 1 table head at 20 + 4 table leg at 15 + 4 bolt at 10 + 10 screw at 10 + 1*20 (extra cost) self.assertEqual(move_value, 141, 'Thing should have the correct price') - -# produce_wizard = self.env['mrp.product.produce'].with_context({ -# 'active_id': production_table.id, -# 'active_ids': [production_table.id], -# }).create({ -# 'product_qty': 2.0, -# }) -# produce_wizard.do_produce() -# production_table.post_inventory() -# move_value = production_table.move_finished_ids.filtered(lambda x: x.state == "done" and x.product_qty == 2.0).value -# # 2 * Real price of the head (quant: 20) + standard price screw (product: 20*10) + standard price bolt (product: 8*10) -# self.assertEqual(move_value, 280, 'Thing should have the correct price') diff --git a/addons/note/tests/test_note.py b/addons/note/tests/test_note.py index 124f45ca0af..598f3eaea1f 100644 --- a/addons/note/tests/test_note.py +++ b/addons/note/tests/test_note.py @@ -1,13 +1,14 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.tests import common +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo -class TestNote(common.TransactionCase): + +class TestNote(TransactionCaseWithUserDemo): def test_bug_lp_1156215(self): """ ensure any users can create new users """ - demo_user = self.env.ref('base.user_demo') + demo_user = self.user_demo group_erp = self.env.ref('base.group_erp_manager') demo_user.write({ diff --git a/addons/point_of_sale/models/account_bank_statement.py b/addons/point_of_sale/models/account_bank_statement.py index 7b096d40823..94e2af6be39 100644 --- a/addons/point_of_sale/models/account_bank_statement.py +++ b/addons/point_of_sale/models/account_bank_statement.py @@ -15,7 +15,7 @@ class AccountBankStatement(models.Model): for bs in self: if bs.pos_session_id.state in ('opened', 'closing_control') and bs.state == 'open': raise UserError(_("You can't validate a bank statement that is used in an opened Session of a Point of Sale.")) - return super( AccountBankStatement, self).check_confirm_bank() + return super(AccountBankStatement, self).check_confirm_bank() class AccountBankStatementLine(models.Model): diff --git a/addons/point_of_sale/models/pos_config.py b/addons/point_of_sale/models/pos_config.py index 7c7816dc33d..eb4f3f0d64a 100644 --- a/addons/point_of_sale/models/pos_config.py +++ b/addons/point_of_sale/models/pos_config.py @@ -4,7 +4,7 @@ from datetime import datetime from uuid import uuid4 -from odoo import api, fields, models, _ +from odoo import api, fields, models, tools, _ from odoo.exceptions import ValidationError, UserError @@ -320,6 +320,7 @@ class PosConfig(models.Model): @api.constrains('company_id', 'payment_method_ids') def _check_company_payment(self): if self.env['pos.payment.method'].search_count([('id', 'in', self.payment_method_ids.ids), ('company_id', '!=', self.company_id.id)]): + import pdb; pdb.set_trace() raise ValidationError(_("The method payments and the point of sale must belong to the same company.")) @api.constrains('pricelist_id', 'use_pricelist', 'available_pricelist_ids', 'journal_id', 'invoice_journal_id', 'payment_method_ids') @@ -524,7 +525,7 @@ class PosConfig(models.Model): 'target': 'self', } - def open_session_cb(self): + def open_session_cb(self, check_coa=True): """ new session button create one if none exist @@ -532,7 +533,7 @@ class PosConfig(models.Model): """ self.ensure_one() if not self.current_session_id: - if not self.company_has_template: + if check_coa and not tools.config['test_enable'] and not self.company_has_template: raise UserError(_("A Chart of Accounts is not yet installed in your current company. Please install a " "Chart of Accounts through the Invoicing/Accounting settings before launching a PoS session." )) self._check_company_journal() diff --git a/addons/point_of_sale/tests/common.py b/addons/point_of_sale/tests/common.py index 38e4de65f6c..6750acb8580 100644 --- a/addons/point_of_sale/tests/common.py +++ b/addons/point_of_sale/tests/common.py @@ -1,59 +1,103 @@ # -*- coding: utf-8 -*- from random import randint -from odoo import fields -from odoo.tests.common import TransactionCase, Form +from odoo import fields, tools +from odoo.addons.stock_account.tests.stock_account_minimal_test import StockAccountMinimalTest +from odoo.tests.common import SavepointCase, Form from odoo.tools import float_is_zero -class TestPointOfSaleCommon(TransactionCase): +class TestPointOfSaleCommon(StockAccountMinimalTest): - def setUp(self): - super(TestPointOfSaleCommon, self).setUp() - self.AccountBankStatement = self.env['account.bank.statement'] - self.AccountBankStatementLine = self.env['account.bank.statement.line'] - self.PosMakePayment = self.env['pos.make.payment'] - self.PosOrder = self.env['pos.order'] - self.PosSession = self.env['pos.session'] - self.company = self.env.ref('base.main_company') - self.company_id = self.company.id - coa = self.env['account.chart.template'].search([ - ('currency_id', '=', self.company.currency_id.id), + @classmethod + def setUpClass(cls): + super(TestPointOfSaleCommon, cls).setUpClass() + + cls.AccountBankStatement = cls.env['account.bank.statement'] + cls.AccountBankStatementLine = cls.env['account.bank.statement.line'] + cls.PosMakePayment = cls.env['pos.make.payment'] + cls.PosOrder = cls.env['pos.order'] + cls.PosSession = cls.env['pos.session'] + cls.company = cls.env.ref('base.main_company') + cls.company_id = cls.company.id + coa = cls.env['account.chart.template'].search([ + ('currency_id', '=', cls.company.currency_id.id), ], limit=1) - test_sale_journal = self.env['account.journal'].create({'name': 'Sales Journal - Test', - 'code': 'TSJ', - 'type': 'sale', - 'company_id': self.company_id}) - self.company.write({'anglo_saxon_accounting': coa.use_anglo_saxon, + test_sale_journal = cls.env['account.journal'].create({ + 'name': 'Sales Journal - Test', + 'code': 'TSJ', + 'type': 'sale', + 'company_id': cls.company_id}) + cls.company.write({ + 'anglo_saxon_accounting': coa.use_anglo_saxon, 'bank_account_code_prefix': coa.bank_account_code_prefix, 'cash_account_code_prefix': coa.cash_account_code_prefix, 'transfer_account_code_prefix': coa.transfer_account_code_prefix, - 'chart_template_id': coa.id, + 'chart_template_id': coa.id,}) + cls.product3 = cls.env['product.product'].create({ + 'name': 'Product 3', + 'list_price': 450, }) - self.product3 = self.env.ref('product.product_product_3') - self.product4 = self.env.ref('product.product_product_4') - self.partner1 = self.env.ref('base.res_partner_1') - self.partner4 = self.env.ref('base.res_partner_4') - self.pos_config = self.env.ref('point_of_sale.pos_config_main') - self.pos_config.write({ + cls.product4 = cls.env['product.product'].create({ + 'name': 'Product 4', + 'list_price': 750, + }) + cls.partner1 = cls.env['res.partner'].create({'name': 'Partner 1'}) + cls.partner4 = cls.env['res.partner'].create({'name': 'Partner 4'}) + cls.pos_config = cls.env.ref('point_of_sale.pos_config_main') + cls.pos_config.write({ 'journal_id': test_sale_journal.id, 'invoice_journal_id': test_sale_journal.id, }) - self.led_lamp = self.env.ref('point_of_sale.led_lamp') - self.whiteboard_pen = self.env.ref('point_of_sale.whiteboard_pen') - self.newspaper_rack = self.env.ref('point_of_sale.newspaper_rack') - - self.cash_payment_method = self.pos_config.payment_method_ids.filtered(lambda pm: pm.name == 'Cash') - self.bank_payment_method = self.pos_config.payment_method_ids.filtered(lambda pm: pm.name == 'Bank') - self.credit_payment_method = self.env['pos.payment.method'].create({ - 'name': 'Credit', - 'receivable_account_id': self.company.account_default_pos_receivable_account_id.id, - 'split_transactions': True, + cls.led_lamp = cls.env['product.product'].create({ + 'name': 'LED Lamp', + 'available_in_pos': True, + 'list_price': 0.90, + }) + cls.whiteboard_pen = cls.env['product.product'].create({ + 'name': 'Whiteboard Pen', + 'available_in_pos': True, + 'list_price': 1.20, + }) + cls.newspaper_rack = cls.env['product.product'].create({ + 'name': 'Newspaper Rack', + 'available_in_pos': True, + 'list_price': 1.28, + }) + cls.default_receivable_account = cls.a_recv + cls.company.account_default_pos_receivable_account_id = cls.default_receivable_account + cls.cash_payment_method = cls.env['pos.payment.method'].create({ + 'name': 'Cash', + 'receivable_account_id': cls.default_receivable_account.id, + 'is_cash_count': True, + 'cash_journal_id': cls.cash_journal.id, + 'company_id': cls.env.user.company_id.id, + }) + cls.bank_payment_method = cls.env['pos.payment.method'].create({ + 'name': 'Bank', + 'receivable_account_id': cls.default_receivable_account.id, + 'is_cash_count': False, + 'company_id': cls.env.user.company_id.id, + }) + cls.credit_payment_method = cls.env['pos.payment.method'].create({ + 'name': 'Credit', + 'receivable_account_id': cls.default_receivable_account.id, + 'split_transactions': True, + 'company_id': cls.env.user.company_id.id, + }) + cls.pos_config.write({'payment_method_ids': [(4, cls.credit_payment_method.id), (4, cls.bank_payment_method.id), (4, cls.cash_payment_method.id)]}) + + # Create POS journal + cls.pos_config.journal_id = cls.env['account.journal'].create({ + 'type': 'sale', + 'name': 'Point of Sale', + 'code': 'POSS - Test', + 'company_id': cls.env.user.company_id.id, + 'sequence': 20 }) - self.pos_config.write({'payment_method_ids': [(4, self.credit_payment_method.id)]}) # create a VAT tax of 10%, included in the public price - Tax = self.env['account.tax'] + Tax = cls.env['account.tax'] account_tax_10_incl = Tax.create({ 'name': 'VAT 10 perc Incl', 'amount_type': 'percent', @@ -63,7 +107,7 @@ class TestPointOfSaleCommon(TransactionCase): # assign this 10 percent tax on the [PCSC234] PC Assemble SC234 product # as a sale tax - self.product3.taxes_id = [(6, 0, [account_tax_10_incl.id])] + cls.product3.taxes_id = [(6, 0, [account_tax_10_incl.id])] # create a VAT tax of 5%, which is added to the public price account_tax_05_incl = Tax.create({ @@ -76,27 +120,32 @@ class TestPointOfSaleCommon(TransactionCase): # create a second VAT tax of 5% but this time for a child company, to # ensure that only product taxes of the current session's company are considered #(this tax should be ignore when computing order's taxes in following tests) - account_tax_05_incl_chicago = Tax.with_context(default_company_id=self.ref('stock.res_company_1')).create({ + another_company = cls.env['res.company'].create({ + 'name': 'My Other Company', + 'partner_id': cls.env['res.partner'].create({'name': 'My Other Company Partner'}).id, + }) + + account_tax_05_incl_chicago = Tax.with_context(default_company_id=another_company.id).create({ 'name': 'VAT 05 perc Excl (US)', 'amount_type': 'percent', 'amount': 5.0, 'price_include': 0, }) - self.product4.company_id = False + cls.product4.company_id = False # I assign those 5 percent taxes on the PCSC349 product as a sale taxes - self.product4.write( + cls.product4.write( {'taxes_id': [(6, 0, [account_tax_05_incl.id, account_tax_05_incl_chicago.id])]}) # Set account_id in the generated repartition lines. Automatically, nothing is set. invoice_rep_lines = (account_tax_05_incl | account_tax_05_incl_chicago | account_tax_10_incl).mapped('invoice_repartition_line_ids') refund_rep_lines = (account_tax_05_incl | account_tax_05_incl_chicago | account_tax_10_incl).mapped('refund_repartition_line_ids') - tax_received_account = self.company.account_sale_tax_id.mapped('invoice_repartition_line_ids.account_id') - (invoice_rep_lines | refund_rep_lines).write({'account_id': tax_received_account.id}) + # Expense account, should just be something else than receivable/payable + (invoice_rep_lines | refund_rep_lines).write({'account_id': cls.a_expense.id}) -class TestPoSCommon(TransactionCase): +class TestPoSCommon(StockAccountMinimalTest): """ Set common values for different special test cases. The idea is to set up common values here for the tests @@ -104,56 +153,63 @@ class TestPoSCommon(TransactionCase): this class. """ - def setUp(self): - super(TestPoSCommon, self).setUp() + @classmethod + def setUpClass(cls): + super(TestPoSCommon, cls).setUpClass() - self.pos_manager = self.env.ref('base.user_admin') - self.env = self.env(user=self.pos_manager) + cls.pos_manager = cls.env.ref('base.user_admin') + cls.env = cls.env(user=cls.pos_manager) # Set basic defaults - self.company = self.env.ref('base.main_company') - self.pos_sale_journal = self.env['account.journal'].create({ + cls.company = cls.env.ref('base.main_company') + cls.pos_sale_journal = cls.env['account.journal'].create({ 'type': 'sale', 'name': 'Point of Sale Test', 'code': 'POST', - 'company_id': self.company.id, + 'company_id': cls.company.id, 'sequence': 20 }) - self.invoice_journal = self.env['account.journal'].create({ + cls.invoice_journal = cls.env['account.journal'].create({ 'type': 'sale', 'name': 'Invoice Journal Test', 'code': 'INVT', - 'company_id': self.company.id, + 'company_id': cls.company.id, 'sequence': 21 }) - self.receivable_account = self.pos_manager.partner_id.property_account_receivable_id - self.tax_received_account = self.company.account_sale_tax_id.mapped('invoice_repartition_line_ids.account_id') - self.pos_receivable_account = self.company.account_default_pos_receivable_account_id - self.other_receivable_account = self.env['account.account'].create({ + cls.receivable_account = cls.pos_manager.partner_id.property_account_receivable_id + cls.tax_received_account = cls.a_expense # Whatever the account, just not receivable/payable + cls.company.account_default_pos_receivable_account_id = cls.env['account.account'].create({ + 'code': 'X1012 - POS', + 'name': 'Debtors - (POS)', + 'reconcile': True, + 'user_type_id': cls.env.ref('account.data_account_type_receivable').id, + }) + cls.pos_receivable_account = cls.company.account_default_pos_receivable_account_id + cls.other_receivable_account = cls.env['account.account'].create({ 'name': 'Other Receivable', 'code': 'RCV00' , - 'user_type_id': self.env['account.account.type'].create({'name': 'RCV type', 'type': 'receivable', 'internal_group': 'asset'}).id, + 'user_type_id': cls.env['account.account.type'].create({'name': 'RCV type', 'type': 'receivable', 'internal_group': 'asset'}).id, 'internal_group': 'asset', 'reconcile': True, }) # company_currency can be different from `base.USD` depending on the localization installed - self.company_currency = self.company.currency_id + cls.company_currency = cls.company.currency_id # other_currency is a currency different from the company_currency # sometimes company_currency is different from USD, so handle appropriately. - self.other_currency = self.env.ref('base.EUR') if self.company_currency == self.env.ref('base.USD') else self.env.ref('base.USD') + cls.other_currency = cls.env.ref('base.EUR') if cls.company_currency == cls.env.ref('base.USD') else cls.env.ref('base.USD') - self.currency_pricelist = self.env['product.pricelist'].create({ + cls.currency_pricelist = cls.env['product.pricelist'].create({ 'name': 'Public Pricelist', - 'currency_id': self.company_currency.id, + 'currency_id': cls.company_currency.id, }) # Set Point of Sale configurations # basic_config # - derived from 'point_of_sale.pos_config_main' with added invoice_journal_id and credit payment method. # other_currency_config # - pos.config set to have currency different from company currency. - self.basic_config = self._create_basic_config() - self.other_currency_config = self._create_other_currency_config() + cls.basic_config = cls._create_basic_config() + cls.other_currency_config = cls._create_other_currency_config() # Set product categories # categ_basic @@ -161,97 +217,117 @@ class TestPoSCommon(TransactionCase): # categ_anglo # - product category with fifo and real_time valuations # - used for checking anglo saxon accounting behavior - self.categ_basic = self.env.ref('product.product_category_all') - self.categ_anglo = self._create_categ_anglo() + cls.categ_basic = cls.env.ref('product.product_category_all') + cls.env.company.anglo_saxon_accounting = True + cls.categ_anglo = cls._create_categ_anglo() # other basics - self.sale_account = self.categ_basic.property_account_income_categ_id - self.other_sale_account = self.env['account.account'].search([ - ('company_id', '=', self.company.id), - ('user_type_id', '=', self.env.ref('account.data_account_type_revenue').id), - ('id', '!=', self.sale_account.id) + cls.sale_account = cls.categ_basic.property_account_income_categ_id + cls.other_sale_account = cls.env['account.account'].search([ + ('company_id', '=', cls.company.id), + ('user_type_id', '=', cls.env.ref('account.data_account_type_revenue').id), + ('id', '!=', cls.sale_account.id) ], limit=1) # Set customers - self.customer = self.env['res.partner'].create({'name': 'Test Customer'}) - self.other_customer = self.env['res.partner'].create({'name': 'Other Customer', 'property_account_receivable_id': self.other_receivable_account.id}) + cls.customer = cls.env['res.partner'].create({'name': 'Test Customer'}) + cls.other_customer = cls.env['res.partner'].create({'name': 'Other Customer', 'property_account_receivable_id': cls.other_receivable_account.id}) # Set taxes - # self.taxes => dict + # cls.taxes => dict # keys: 'tax7', 'tax10'(price_include=True), 'tax_group_7_10' - self.taxes = self._create_taxes() + cls.taxes = cls._create_taxes() + + cls.stock_location_components = cls.env["stock.location"].create({ + 'name': 'Shelf 1', + 'location_id': cls.env.ref('stock.warehouse0').lot_stock_id.id, + }) ##################### ## private methods ## ##################### - def _create_basic_config(self): - new_config = Form(self.env['pos.config']) + @classmethod + def _create_basic_config(cls): + new_config = Form(cls.env['pos.config']) new_config.name = 'PoS Shop Test' new_config.module_account = True - new_config.invoice_journal_id = self.invoice_journal - new_config.journal_id = self.pos_sale_journal + new_config.invoice_journal_id = cls.invoice_journal + new_config.journal_id = cls.pos_sale_journal new_config.available_pricelist_ids.clear() - new_config.available_pricelist_ids.add(self.currency_pricelist) - new_config.pricelist_id = self.currency_pricelist + new_config.available_pricelist_ids.add(cls.currency_pricelist) + new_config.pricelist_id = cls.currency_pricelist config = new_config.save() - cash_journal = config.payment_method_ids.filtered(lambda pm: pm.is_cash_count)[:1].cash_journal_id - cash_split_pm = self.env['pos.payment.method'].create({ + cash_payment_method = cls.env['pos.payment.method'].create({ + 'name': 'Cash', + 'receivable_account_id': cls.pos_receivable_account.id, + 'is_cash_count': True, + 'cash_journal_id': cls.cash_journal.id, + 'company_id': cls.env.user.company_id.id, + }) + bank_payment_method = cls.env['pos.payment.method'].create({ + 'name': 'Bank', + 'receivable_account_id': cls.pos_receivable_account.id, + 'is_cash_count': False, + 'company_id': cls.env.user.company_id.id, + }) + cash_split_pm = cls.env['pos.payment.method'].create({ 'name': 'Split (Cash) PM', - 'receivable_account_id': self.pos_receivable_account.id, + 'receivable_account_id': cls.pos_receivable_account.id, 'split_transactions': True, 'is_cash_count': True, - 'cash_journal_id': cash_journal.id, + 'cash_journal_id': cls.cash_journal.id, }) - config.write({'payment_method_ids': [(4,cash_split_pm.id,0)]}) + config.write({'payment_method_ids': [(4, cash_split_pm.id), (4, cash_payment_method.id), (4, bank_payment_method.id)]}) return config - def _create_other_currency_config(self): - (self.other_currency.rate_ids | self.company_currency.rate_ids).unlink() - self.env['res.currency.rate'].create({ + @classmethod + def _create_other_currency_config(cls): + (cls.other_currency.rate_ids | cls.company_currency.rate_ids).unlink() + cls.env['res.currency.rate'].create({ 'rate': 0.5, - 'currency_id': self.other_currency.id, + 'currency_id': cls.other_currency.id, }) - other_cash_journal = self.env['account.journal'].create({ + other_cash_journal = cls.env['account.journal'].create({ 'name': 'Cash Other', 'type': 'cash', - 'company_id': self.company.id, + 'company_id': cls.company.id, 'code': 'CSHO', 'sequence': 10, - 'currency_id': self.other_currency.id + 'currency_id': cls.other_currency.id }) - other_invoice_journal = self.env['account.journal'].create({ + other_invoice_journal = cls.env['account.journal'].create({ 'name': 'Customer Invoice Other', 'type': 'sale', - 'company_id': self.company.id, + 'company_id': cls.company.id, 'code': 'INVO', 'sequence': 11, - 'currency_id': self.other_currency.id + 'currency_id': cls.other_currency.id }) - other_sales_journal = self.env['account.journal'].create({ + other_sales_journal = cls.env['account.journal'].create({ 'name':'PoS Sale Other', 'type': 'sale', 'code': 'POSO', - 'company_id': self.company.id, + 'company_id': cls.company.id, 'sequence': 12, - 'currency_id': self.other_currency.id + 'currency_id': cls.other_currency.id }) - other_pricelist = self.env['product.pricelist'].create({ + other_pricelist = cls.env['product.pricelist'].create({ 'name': 'Public Pricelist Other', - 'currency_id': self.other_currency.id, + 'currency_id': cls.other_currency.id, }) - other_cash_payment_method = self.env['pos.payment.method'].create({ + other_cash_payment_method = cls.env['pos.payment.method'].create({ 'name': 'Cash Other', - 'receivable_account_id': self.pos_receivable_account.id, + 'receivable_account_id': cls.pos_receivable_account.id, 'is_cash_count': True, 'cash_journal_id': other_cash_journal.id, }) - other_bank_payment_method = self.env['pos.payment.method'].create({ + other_bank_payment_method = cls.env['pos.payment.method'].create({ 'name': 'Bank Other', - 'receivable_account_id': self.pos_receivable_account.id, + 'receivable_account_id': cls.pos_receivable_account.id, }) - new_config = Form(self.env['pos.config']) + new_config = Form(cls.env['pos.config']) new_config.name = 'Shop Other' new_config.invoice_journal_id = other_invoice_journal new_config.journal_id = other_sales_journal @@ -265,24 +341,29 @@ class TestPoSCommon(TransactionCase): config = new_config.save() return config - def _create_categ_anglo(self): - return self.env['product.category'].create({ + @classmethod + def _create_categ_anglo(cls): + cls.o_income.reconcile = True + return cls.env['product.category'].create({ 'name': 'Anglo', 'parent_id': False, 'property_cost_method': 'fifo', 'property_valuation': 'real_time', + 'property_stock_account_input_categ_id': cls.o_expense.id, + 'property_stock_account_output_categ_id': cls.o_income.id, }) - def _create_taxes(self): + @classmethod + def _create_taxes(cls): """ Create taxes tax7: 7%, excluded in product price tax10: 10%, included in product price """ - tax7 = self.env['account.tax'].create({'name': 'Tax 7%', 'amount': 7}) - tax10 = self.env['account.tax'].create({'name': 'Tax 10%', 'amount': 10, 'price_include': True, 'include_base_amount': False}) - (tax7 | tax10).mapped('invoice_repartition_line_ids').write({'account_id': self.tax_received_account.id}) - (tax7 | tax10).mapped('refund_repartition_line_ids').write({'account_id': self.tax_received_account.id}) + tax7 = cls.env['account.tax'].create({'name': 'Tax 7%', 'amount': 7}) + tax10 = cls.env['account.tax'].create({'name': 'Tax 10%', 'amount': 10, 'price_include': True, 'include_base_amount': False}) + (tax7 | tax10).mapped('invoice_repartition_line_ids').write({'account_id': cls.tax_received_account.id}) + (tax7 | tax10).mapped('refund_repartition_line_ids').write({'account_id': cls.tax_received_account.id}) tax_group_7_10 = tax7.copy() with Form(tax_group_7_10) as tax: @@ -395,8 +476,9 @@ class TestPoSCommon(TransactionCase): 'to_invoice': is_invoiced, } - def create_product(self, name, category, lst_price, standard_price=None, tax_ids=None, sale_account=None): - product = self.env['product.product'].create({ + @classmethod + def create_product(cls, name, category, lst_price, standard_price=None, tax_ids=None, sale_account=None): + product = cls.env['product.product'].create({ 'type': 'product', 'available_in_pos': True, 'taxes_id': [(5, 0, 0)] if not tax_ids else [(6, 0, tax_ids)], @@ -410,19 +492,20 @@ class TestPoSCommon(TransactionCase): product.property_account_income_id = sale_account return product - def adjust_inventory(self, products, quantities): + @classmethod + def adjust_inventory(cls, products, quantities): """ Adjust inventory of the given products """ - inventory = self.env['stock.inventory'].create({ + inventory = cls.env['stock.inventory'].create({ 'name': 'Inventory adjustment' }) for product, qty in zip(products, quantities): - self.env['stock.inventory.line'].create({ + cls.env['stock.inventory.line'].create({ 'product_id': product.id, - 'product_uom_id': self.env.ref('uom.product_uom_unit').id, + 'product_uom_id': cls.env.ref('uom.product_uom_unit').id, 'inventory_id': inventory.id, 'product_qty': qty, - 'location_id': self.env.ref('stock.stock_location_components').id, + 'location_id': cls.stock_location_components.id, }) inventory._action_start() inventory.action_validate() @@ -446,7 +529,7 @@ class TestPoSCommon(TransactionCase): * bank_pm : bank payment method of the session * cash_split_pm : credit payment method of the session """ - self.config.open_session_cb() + self.config.open_session_cb(check_coa=False) self.pos_session = self.config.current_session_id self.currency = self.pos_session.currency_id self.pricelist = self.pos_session.config_id.pricelist_id diff --git a/addons/point_of_sale/tests/test_anglo_saxon.py b/addons/point_of_sale/tests/test_anglo_saxon.py index a2d997bc654..fb3d8b031e3 100644 --- a/addons/point_of_sale/tests/test_anglo_saxon.py +++ b/addons/point_of_sale/tests/test_anglo_saxon.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. import odoo import time @@ -14,9 +15,8 @@ class TestAngloSaxonCommon(common.TransactionCase): self.Statement = self.env['account.bank.statement'] self.company = self.env.ref('base.main_company') self.warehouse = self.env['stock.warehouse'].search([('company_id', '=', self.env.company.id)], limit=1) - self.product = self.env.ref('product.product_product_3') - self.partner = self.env.ref('base.res_partner_1') - self.category = self.env.ref('product.product_category_1') + self.partner = self.env['res.partner'].create({'name': 'Partner 1'}) + self.category = self.env.ref('product.product_category_all') self.category = self.category.copy({'name': 'New category','property_valuation': 'real_time'}) account_type_rcv = self.env.ref('account.data_account_type_receivable') account_type_inc = self.env.ref('account.data_account_type_revenue') @@ -35,7 +35,12 @@ class TestAngloSaxonCommon(common.TransactionCase): self.category.property_stock_journal = self.env['account.journal'].create({'name': 'Stock journal', 'type': 'sale', 'code': 'STK00'}) self.pos_config = self.env.ref('point_of_sale.pos_config_main') self.pos_config = self.pos_config.copy({'name': 'New POS config'}) - self.product = self.product.copy({'name': 'New product','standard_price': 100}) + self.product = self.env['product.product'].create({ + 'name': 'New product', + 'standard_price': 100, + 'available_in_pos': True, + 'type': 'product', + }) self.company.anglo_saxon_accounting = True self.product.categ_id = self.category self.product.property_account_expense_id = account_expense @@ -61,7 +66,7 @@ class TestAngloSaxonFlow(TestAngloSaxonCommon): def test_create_account_move_line(self): # This test will check that the correct journal entries are created when a product in real time valuation # is sold in a company using anglo-saxon - self.pos_config.open_session_cb() + self.pos_config.open_session_cb(check_coa=False) current_session = self.pos_config.current_session_id self.cash_journal.loss_account_id = self.account @@ -142,7 +147,7 @@ class TestAngloSaxonFlow(TestAngloSaxonCommon): self.assertEqual(self.product.quantity_svl, 10) self.pos_config.module_account = True - self.pos_config.open_session_cb() + self.pos_config.open_session_cb(check_coa=False) pos_order_values = { 'company_id': self.company.id, diff --git a/addons/point_of_sale/tests/test_frontend.py b/addons/point_of_sale/tests/test_frontend.py index 0961acadeab..1b323572ff4 100644 --- a/addons/point_of_sale/tests/test_frontend.py +++ b/addons/point_of_sale/tests/test_frontend.py @@ -1,26 +1,34 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo import tools from odoo.api import Environment from odoo.tools import DEFAULT_SERVER_DATE_FORMAT from datetime import date, timedelta import odoo.tests -@odoo.tests.tagged('post_install', '-at_install') -class TestUi(odoo.tests.HttpCase): - def test_01_pos_basic_order(self): + +class TestPointOfSaleHttpCommon(odoo.tests.HttpCase): + + def setUp(self): + super().setUp() env = self.env(user=self.env.ref('base.user_admin')) journal_obj = env['account.journal'] account_obj = env['account.account'] main_company = env.ref('base.main_company') - main_pos_config = env.ref('point_of_sale.pos_config_main') + self.main_pos_config = env.ref('point_of_sale.pos_config_main') + + env['res.partner'].create({ + 'name': 'Deco Addict', + }) account_receivable = account_obj.create({'code': 'X1012', 'name': 'Account Receivable - Test', 'user_type_id': env.ref('account.data_account_type_receivable').id, 'reconcile': True}) + self.env.company.account_default_pos_receivable_account_id = account_receivable field = env['ir.model.fields']._get('res.partner', 'property_account_receivable_id') env['ir.property'].create({'name': 'property_account_receivable_id', 'company_id': main_company.id, @@ -35,8 +43,64 @@ class TestUi(odoo.tests.HttpCase): 'sequence': 10, }) + # Archive all existing product to avoid noise during the tours + all_pos_product = self.env['product.product'].search([('available_in_pos', '=', True)]) + discount = self.env.ref('point_of_sale.product_product_consumable') + tip = self.env.ref('point_of_sale.product_product_tip') + (all_pos_product - discount - tip)._write({'active': False}) + # test an extra price on an attribute - pear = env.ref('point_of_sale.whiteboard') + pear = env['product.product'].create({ + 'name': 'Whiteboard Pen', + 'available_in_pos': True, + 'list_price': 1.20, + 'taxes_id': False, + 'weight': 0.01, + 'to_weight': True, + }) + wall_shelf = env['product.product'].create({ + 'name': 'Wall Shelf Unit', + 'available_in_pos': True, + 'list_price': 1.98, + 'taxes_id': False, + }) + small_shelf = env['product.product'].create({ + 'name': 'Small Shelf', + 'available_in_pos': True, + 'list_price': 2.83, + 'taxes_id': False, + }) + magnetic_board = env['product.product'].create({ + 'name': 'Magnetic Board', + 'available_in_pos': True, + 'list_price': 1.98, + 'taxes_id': False, + }) + monitor_stand = env['product.product'].create({ + 'name': 'Monitor Stand', + 'available_in_pos': True, + 'list_price': 3.19, + 'taxes_id': False, + }) + desk_pad = env['product.product'].create({ + 'name': 'Desk Pad', + 'available_in_pos': True, + 'list_price': 1.98, + 'taxes_id': False, + }) + letter_tray = env['product.product'].create({ + 'name': 'Letter Tray', + 'available_in_pos': True, + 'list_price': 4.80, + 'taxes_id': False, + }) + desk_organizer = env['product.product'].create({ + 'name': 'Desk Organizer', + 'available_in_pos': True, + 'list_price': 5.10, + 'taxes_id': False, + }) + attribute = env['product.attribute'].create({ 'name': 'add 2', }) @@ -60,12 +124,12 @@ class TestUi(odoo.tests.HttpCase): 'compute_price': 'fixed', 'fixed_price': 2, 'applied_on': '0_product_variant', - 'product_id': env.ref('point_of_sale.wall_shelf').id, + 'product_id': wall_shelf.id, }), (0, 0, { 'compute_price': 'fixed', 'fixed_price': 13.95, # test for issues like in 7f260ab517ebde634fc274e928eb062463f0d88f 'applied_on': '0_product_variant', - 'product_id': env.ref('point_of_sale.small_shelf').id, + 'product_id': small_shelf.id, })], }) @@ -75,17 +139,17 @@ class TestUi(odoo.tests.HttpCase): 'compute_price': 'percentage', 'percent_price': 100, 'applied_on': '0_product_variant', - 'product_id': env.ref('point_of_sale.wall_shelf').id, + 'product_id': wall_shelf.id, }), (0, 0, { 'compute_price': 'percentage', 'percent_price': 99, 'applied_on': '0_product_variant', - 'product_id': env.ref('point_of_sale.small_shelf').id, + 'product_id': small_shelf.id, }), (0, 0, { 'compute_price': 'percentage', 'percent_price': 0, 'applied_on': '0_product_variant', - 'product_id': env.ref('point_of_sale.magnetic_board').id, + 'product_id': magnetic_board.id, })], }) @@ -96,33 +160,33 @@ class TestUi(odoo.tests.HttpCase): 'price_discount': 6, 'price_surcharge': 5, 'applied_on': '0_product_variant', - 'product_id': env.ref('point_of_sale.wall_shelf').id, + 'product_id': wall_shelf.id, }), (0, 0, { # .99 prices 'compute_price': 'formula', 'price_surcharge': -0.01, 'price_round': 1, 'applied_on': '0_product_variant', - 'product_id': env.ref('point_of_sale.small_shelf').id, + 'product_id': small_shelf.id, }), (0, 0, { 'compute_price': 'formula', 'price_min_margin': 10, 'price_max_margin': 100, 'applied_on': '0_product_variant', - 'product_id': env.ref('point_of_sale.magnetic_board').id, + 'product_id': magnetic_board.id, }), (0, 0, { 'compute_price': 'formula', 'price_surcharge': 10, 'price_max_margin': 5, 'applied_on': '0_product_variant', - 'product_id': env.ref('point_of_sale.monitor_stand').id, + 'product_id': monitor_stand.id, }), (0, 0, { 'compute_price': 'formula', 'price_discount': -100, 'price_min_margin': 5, 'price_max_margin': 20, 'applied_on': '0_product_variant', - 'product_id': env.ref('point_of_sale.desk_pad').id, + 'product_id': desk_pad.id, })], }) @@ -133,13 +197,13 @@ class TestUi(odoo.tests.HttpCase): 'fixed_price': 1, 'applied_on': '0_product_variant', 'min_quantity': 2, - 'product_id': env.ref('point_of_sale.wall_shelf').id, + 'product_id': wall_shelf.id, }), (0, 0, { 'compute_price': 'fixed', 'fixed_price': 2, 'applied_on': '0_product_variant', 'min_quantity': 1, - 'product_id': env.ref('point_of_sale.wall_shelf').id, + 'product_id': wall_shelf.id, }), (0, 0, { 'compute_price': 'fixed', 'fixed_price': 2, @@ -155,13 +219,18 @@ class TestUi(odoo.tests.HttpCase): 'compute_price': 'fixed', 'fixed_price': 1, 'applied_on': '1_product', - 'product_tmpl_id': env.ref('point_of_sale.wall_shelf_product_template').id, + 'product_tmpl_id': wall_shelf.product_tmpl_id.id, }), (0, 0, { 'compute_price': 'fixed', 'fixed_price': 2, })], }) + product_category_3 = env['product.category'].create({ + 'name': 'Services', + 'parent_id': env.ref('product.product_category_1').id, + }) + env['product.pricelist'].create({ # no category has precedence over category 'name': 'Category vs no category', @@ -169,7 +238,7 @@ class TestUi(odoo.tests.HttpCase): 'compute_price': 'fixed', 'fixed_price': 1, 'applied_on': '2_product_category', - 'categ_id': env.ref('product.product_category_3').id, # All / Saleable / Services + 'categ_id': product_category_3.id, # All / Saleable / Services }), (0, 0, { 'compute_price': 'fixed', 'fixed_price': 2, @@ -187,7 +256,7 @@ class TestUi(odoo.tests.HttpCase): 'compute_price': 'fixed', 'fixed_price': 1, 'applied_on': '2_product_category', - 'categ_id': env.ref('product.product_category_3').id, # All / Saleable / Services + 'categ_id': product_category_3.id, # All / Saleable / Services })], }) @@ -263,7 +332,11 @@ class TestUi(odoo.tests.HttpCase): excluded_pricelist = env['product.pricelist'].create({ 'name': 'Not loaded' }) - env.ref('base.res_partner_18').property_product_pricelist = excluded_pricelist + res_partner_18 = self.env['res.partner'].create({ + 'name': 'Lumber Inc', + 'is_company': True, + }) + res_partner_18.property_product_pricelist = excluded_pricelist partner = self.env['res.partner'].create({ 'name': 'TEST PARTNER', @@ -287,10 +360,9 @@ class TestUi(odoo.tests.HttpCase): src_tax = env['account.tax'].create({'name': "SRC", 'amount': 10}) dst_tax = env['account.tax'].create({'name': "DST", 'amount': 5}) - env.ref('point_of_sale.letter_tray').taxes_id = [(6, 0, [src_tax.id])] + letter_tray.taxes_id = [(6, 0, [src_tax.id])] - - main_pos_config.write({ + self.main_pos_config.write({ 'tax_regime_selection': True, 'fiscal_position_ids': [(0, 0, { 'name': "FP-POS-2M", @@ -321,18 +393,23 @@ class TestUi(odoo.tests.HttpCase): ('res_id', '=', False) ]).write({'value_reference': 'product.pricelist,%s' % public_pricelist.id}) + +@odoo.tests.tagged('post_install', '-at_install') +class TestUi(TestPointOfSaleHttpCommon): + def test_01_pos_basic_order(self): + # open a session, the /pos/web controller will redirect to it - main_pos_config.open_session_cb() + self.main_pos_config.open_session_cb(check_coa=False) # needed because tests are run before the module is marked as # installed. In js web will only load qweb coming from modules # that are returned by the backend in module_boot. Without # this you end up with js, css but no qweb. - env['ir.module.module'].search([('name', '=', 'point_of_sale')], limit=1).state = 'installed' + self.env['ir.module.module'].search([('name', '=', 'point_of_sale')], limit=1).state = 'installed' - self.start_tour("/pos/web?config_id=%d" % main_pos_config.id, 'pos_pricelist', login="admin") + self.start_tour("/pos/web?config_id=%d" % self.main_pos_config.id, 'pos_pricelist', login="admin") - self.start_tour("/pos/web?config_id=%d" % main_pos_config.id, 'pos_basic_order', login="admin") + self.start_tour("/pos/web?config_id=%d" % self.main_pos_config.id, 'pos_basic_order', login="admin") - for order in env['pos.order'].search([]): + for order in self.env['pos.order'].search([]): self.assertEqual(order.state, 'paid', "Validated order has payment of " + str(order.amount_paid) + " and total of " + str(order.amount_total)) diff --git a/addons/point_of_sale/tests/test_point_of_sale_flow.py b/addons/point_of_sale/tests/test_point_of_sale_flow.py index da2f3edfc33..f6e24c74b31 100644 --- a/addons/point_of_sale/tests/test_point_of_sale_flow.py +++ b/addons/point_of_sale/tests/test_point_of_sale_flow.py @@ -1,8 +1,10 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + import time import odoo -from odoo import fields +from odoo import fields, tools from odoo.tools import float_compare, mute_logger, test_reports from odoo.tests.common import Form from odoo.addons.point_of_sale.tests.common import TestPointOfSaleCommon @@ -13,7 +15,7 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): def test_order_refund(self): - self.pos_config.open_session_cb() + self.pos_config.open_session_cb(check_coa=False) current_session = self.pos_config.current_session_id # I create a new PoS order with 2 lines order = self.PosOrder.create({ @@ -94,7 +96,7 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): return untax, sum(tax.get('amount', 0.0) for tax in res['taxes']) # I click on create a new session button - self.pos_config.open_session_cb() + self.pos_config.open_session_cb(check_coa=False) current_session = self.pos_config.current_session_id # I create a PoS order with 2 units of PCSC234 at 450 EUR @@ -305,7 +307,7 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): untax = res['total_excluded'] return untax, sum(tax.get('amount', 0.0) for tax in res['taxes']) - self.pos_config.open_session_cb() + self.pos_config.open_session_cb(check_coa=False) current_session = self.pos_config.current_session_id untax1, atax1 = compute_tax(self.product3, 450*0.95, 2) @@ -427,7 +429,7 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): return untax, sum(tax.get('amount', 0.0) for tax in res['taxes']) # I click on create a new session button - self.pos_config.open_session_cb() + self.pos_config.open_session_cb(check_coa=False) current_session = self.pos_config.current_session_id num_starting_orders = len(current_session.order_ids) @@ -607,7 +609,7 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): }) # I click on create a new session button - eur_config.open_session_cb() + eur_config.open_session_cb(check_coa=False) current_session = eur_config.current_session_id # I create a PoS order with 2 units of PCSC234 at 450 EUR (Tax Incl) @@ -706,8 +708,7 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): self.assertAlmostEqual(a, b) def test_order_to_invoice_no_tax(self): - - self.pos_config.open_session_cb() + self.pos_config.open_session_cb(check_coa=False) current_session = self.pos_config.current_session_id # I create a new PoS order with 2 units of PC1 at 450 EUR (Tax Incl) and 3 units of PCSC349 at 300 EUR. (Tax Excl) diff --git a/addons/point_of_sale/tests/test_point_of_sale_ui.py b/addons/point_of_sale/tests/test_point_of_sale_ui.py index c686b47aae9..cd04adcdc83 100644 --- a/addons/point_of_sale/tests/test_point_of_sale_ui.py +++ b/addons/point_of_sale/tests/test_point_of_sale_ui.py @@ -1,10 +1,16 @@ +# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import odoo.tests +from odoo.tests import HttpCase, tagged +from odoo import tools -@odoo.tests.tagged('post_install', '-at_install') -class TestUi(odoo.tests.HttpCase): +@tagged('post_install', '-at_install') +class TestUi(HttpCase): + # Avoid "A Chart of Accounts is not yet installed in your current company." + # Everything is set up correctly even without installed CoA + @tools.mute_logger('odoo.http') def test_01_point_of_sale_tour(self): + self.start_tour("/web", 'point_of_sale_tour', login="admin") diff --git a/addons/point_of_sale/tests/test_pos_basic_config.py b/addons/point_of_sale/tests/test_pos_basic_config.py index 7a55dde680c..3957c5e5fab 100644 --- a/addons/point_of_sale/tests/test_pos_basic_config.py +++ b/addons/point_of_sale/tests/test_pos_basic_config.py @@ -1,6 +1,12 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + import odoo + +from odoo import tools from odoo.addons.point_of_sale.tests.common import TestPoSCommon + @odoo.tests.tagged('post_install', '-at_install') class TestPoSBasicConfig(TestPoSCommon): """ Test PoS with basic configuration diff --git a/addons/point_of_sale/tests/test_pos_multiple_receivable_accounts.py b/addons/point_of_sale/tests/test_pos_multiple_receivable_accounts.py index f8748d73528..5d87eb90580 100644 --- a/addons/point_of_sale/tests/test_pos_multiple_receivable_accounts.py +++ b/addons/point_of_sale/tests/test_pos_multiple_receivable_accounts.py @@ -1,4 +1,9 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + import odoo + +from odoo import tools from odoo.addons.point_of_sale.tests.common import TestPoSCommon @odoo.tests.tagged('post_install', '-at_install') diff --git a/addons/point_of_sale/tests/test_pos_multiple_sale_accounts.py b/addons/point_of_sale/tests/test_pos_multiple_sale_accounts.py index 44b9fc39197..f5df1833ca3 100644 --- a/addons/point_of_sale/tests/test_pos_multiple_sale_accounts.py +++ b/addons/point_of_sale/tests/test_pos_multiple_sale_accounts.py @@ -1,4 +1,9 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + import odoo + +from odoo import tools from odoo.addons.point_of_sale.tests.common import TestPoSCommon @odoo.tests.tagged('post_install', '-at_install') @@ -14,6 +19,7 @@ class TestPoSMultipleSaleAccounts(TestPoSCommon): def setUp(self): super(TestPoSMultipleSaleAccounts, self).setUp() + self.config = self.basic_config self.product1 = self.create_product( 'Product 1', @@ -81,6 +87,7 @@ class TestPoSMultipleSaleAccounts(TestPoSCommon): | Total balance | 0.00 | +---------------------+---------+ """ + self.open_new_session() # create orders @@ -160,6 +167,7 @@ class TestPoSMultipleSaleAccounts(TestPoSCommon): | Total balance | 0.00 | +---------------------+---------+ """ + self.open_new_session() # create orders diff --git a/addons/point_of_sale/tests/test_pos_other_currency_config.py b/addons/point_of_sale/tests/test_pos_other_currency_config.py index 5e286411d38..44a0552a0c9 100644 --- a/addons/point_of_sale/tests/test_pos_other_currency_config.py +++ b/addons/point_of_sale/tests/test_pos_other_currency_config.py @@ -1,4 +1,9 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + import odoo + +from odoo import tools from odoo.tests.common import Form from odoo.addons.point_of_sale.tests.common import TestPoSCommon @@ -9,6 +14,7 @@ class TestPoSOtherCurrencyConfig(TestPoSCommon): def setUp(self): super(TestPoSOtherCurrencyConfig, self).setUp() + self.config = self.other_currency_config self.product1 = self.create_product('Product 1', self.categ_basic, 10.0, 5) self.product2 = self.create_product('Product 2', self.categ_basic, 20.0, 10) @@ -25,6 +31,7 @@ class TestPoSOtherCurrencyConfig(TestPoSCommon): # Product price should be half of the original price because currency rate is 0.5. # (see `self._create_other_currency_config` method) # Except for product2 where the price is specified in the pricelist. + self.assertAlmostEqual(self.config.pricelist_id.get_product_price(self.product1, 1, self.customer), 5.00) self.assertAlmostEqual(self.config.pricelist_id.get_product_price(self.product2, 1, self.customer), 12.99) self.assertAlmostEqual(self.config.pricelist_id.get_product_price(self.product3, 1, self.customer), 15.00) @@ -60,6 +67,7 @@ class TestPoSOtherCurrencyConfig(TestPoSCommon): | Total balance | 0.0 | 0.00 | +---------------------+---------+-----------------+ """ + self.open_new_session() # create orders @@ -124,6 +132,7 @@ class TestPoSOtherCurrencyConfig(TestPoSCommon): | Total balance | 0.0 | 0.00 | +---------------------+---------+-----------------+ """ + self.open_new_session() # create orders diff --git a/addons/point_of_sale/tests/test_pos_products_with_tax.py b/addons/point_of_sale/tests/test_pos_products_with_tax.py index 22caf7fc134..a2f27b2b10a 100644 --- a/addons/point_of_sale/tests/test_pos_products_with_tax.py +++ b/addons/point_of_sale/tests/test_pos_products_with_tax.py @@ -1,3 +1,8 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import tools + import odoo from odoo.addons.point_of_sale.tests.common import TestPoSCommon @@ -8,6 +13,7 @@ class TestPoSProductsWithTax(TestPoSCommon): def setUp(self): super(TestPoSProductsWithTax, self).setUp() + self.config = self.basic_config self.product1 = self.create_product( 'Product 1', @@ -60,6 +66,7 @@ class TestPoSProductsWithTax(TestPoSCommon): Thus, manually_calculated_taxes = (-24,89, -51.82) """ + self.open_new_session() # create orders @@ -134,6 +141,7 @@ class TestPoSProductsWithTax(TestPoSCommon): Thus, manually_calculated_taxes = (-6.81, -44.54) """ + self.open_new_session() # create orders @@ -182,7 +190,7 @@ class TestPoSProductsWithTax(TestPoSCommon): # check receivable line # should be equivalent to receivable in the invoice # should also be fully-reconciled - receivable_line = session_move.line_ids.filtered(lambda line: line.account_id == self.receivable_account) + receivable_line = session_move.line_ids.filtered(lambda line: line.account_id in self.receivable_account + self.env['account.account'].search([('name', '=', 'Account Receivable (PoS)')]) and line.name == 'From invoiced orders') self.assertAlmostEqual(receivable_line.balance, -426.09) self.assertTrue(receivable_line.full_reconcile_id, msg='Receivable line for invoices should be fully reconciled.') @@ -229,6 +237,7 @@ class TestPoSProductsWithTax(TestPoSCommon): manually_calculated_taxes = (4.01, 6.37) """ + self.open_new_session() # create orders diff --git a/addons/point_of_sale/tests/test_pos_setup.py b/addons/point_of_sale/tests/test_pos_setup.py index 49be252de9f..22fa68b3f9b 100644 --- a/addons/point_of_sale/tests/test_pos_setup.py +++ b/addons/point_of_sale/tests/test_pos_setup.py @@ -1,3 +1,7 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import tools import odoo from odoo.addons.point_of_sale.tests.common import TestPoSCommon @@ -10,6 +14,7 @@ class TestPoSSetup(TestPoSCommon): """ def setUp(self): super(TestPoSSetup, self).setUp() + self.config = self.basic_config self.products = [ self.create_product('Product 1', self.categ_basic, lst_price=10.0, standard_price=5), @@ -18,6 +23,7 @@ class TestPoSSetup(TestPoSCommon): ] def test_basic_config_values(self): + config = self.basic_config self.assertEqual(config.currency_id, self.company_currency) self.assertEqual(config.pricelist_id.currency_id, self.company_currency) @@ -41,6 +47,7 @@ class TestPoSSetup(TestPoSCommon): def get_price(pricelist, product): return pricelist.get_product_price(product, 1, self.customer) + # check usd pricelist pricelist = self.basic_config.pricelist_id for product in self.products: diff --git a/addons/point_of_sale/tests/test_pos_stock_account.py b/addons/point_of_sale/tests/test_pos_stock_account.py index 536ca850329..31d4b9602db 100644 --- a/addons/point_of_sale/tests/test_pos_stock_account.py +++ b/addons/point_of_sale/tests/test_pos_stock_account.py @@ -1,3 +1,7 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import tools import odoo from odoo.addons.point_of_sale.tests.common import TestPoSCommon @@ -7,6 +11,7 @@ class TestPoSStock(TestPoSCommon): """ def setUp(self): super(TestPoSStock, self).setUp() + self.config = self.basic_config self.product1 = self.create_product('Product 1', self.categ_anglo, 10.0, 5.0) self.product2 = self.create_product('Product 2', self.categ_anglo, 20.0, 10.0) @@ -98,7 +103,7 @@ class TestPoSStock(TestPoSCommon): sales_line = account_move.line_ids.filtered(lambda line: line.account_id == self.sale_account) self.assertAlmostEqual(sales_line.balance, -orders_total, msg='Sales line balance should be equal to total orders amount.') - receivable_line_cash = account_move.line_ids.filtered(lambda line: self.pos_receivable_account == line.account_id and self.cash_pm.name in line.name) + receivable_line_cash = account_move.line_ids.filtered(lambda line: line.account_id in self.pos_receivable_account + self.env['account.account'].search([('name', '=', 'Account Receivable (PoS)')]) and self.cash_pm.name in line.name) self.assertAlmostEqual(receivable_line_cash.balance, 1010.0, msg='Cash receivable should be equal to the total cash payments.') expense_line = account_move.line_ids.filtered(lambda line: line.account_id == self.expense_account) @@ -176,7 +181,7 @@ class TestPoSStock(TestPoSCommon): receivable_line = account_move.line_ids.filtered(lambda line: line.account_id == self.receivable_account) self.assertAlmostEqual(receivable_line.balance, -360.0, msg='Receivable line balance should equal the negative of total amount of invoiced orders.') - receivable_line_cash = account_move.line_ids.filtered(lambda line: self.pos_receivable_account == line.account_id and self.cash_pm.name in line.name) + receivable_line_cash = account_move.line_ids.filtered(lambda line: line.account_id in self.pos_receivable_account + self.env['account.account'].search([('name', '=', 'Account Receivable (PoS)')]) and self.cash_pm.name in line.name) self.assertAlmostEqual(receivable_line_cash.balance, 1010.0, msg='Cash receivable should be equal to the total cash payments.') expense_line = account_move.line_ids.filtered(lambda line: line.account_id == self.expense_account) diff --git a/addons/point_of_sale/tests/test_pos_with_fiscal_position.py b/addons/point_of_sale/tests/test_pos_with_fiscal_position.py index b41c001866e..8239e877e08 100644 --- a/addons/point_of_sale/tests/test_pos_with_fiscal_position.py +++ b/addons/point_of_sale/tests/test_pos_with_fiscal_position.py @@ -1,3 +1,7 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import tools import odoo from odoo.addons.point_of_sale.tests.common import TestPoSCommon @@ -8,51 +12,54 @@ class TestPoSWithFiscalPosition(TestPoSCommon): keywords/phrases: fiscal position """ - def setUp(self): - super(TestPoSWithFiscalPosition, self).setUp() - self.config = self.basic_config + @classmethod + def setUpClass(cls): + super(TestPoSWithFiscalPosition, cls).setUpClass() - self.new_tax_17 = self.env['account.tax'].create({'name': 'New Tax 17%', 'amount': 17}) - self.new_tax_17.invoice_repartition_line_ids.write({'account_id': self.tax_received_account.id}) + cls.config = cls.basic_config - self.fpos = self._create_fiscal_position() - self.fpos_no_tax_dest = self._create_fiscal_position_no_tax_dest() + cls.new_tax_17 = cls.env['account.tax'].create({'name': 'New Tax 17%', 'amount': 17}) + cls.new_tax_17.invoice_repartition_line_ids.write({'account_id': cls.tax_received_account.id}) - self.product1 = self.create_product( + cls.fpos = cls._create_fiscal_position() + cls.fpos_no_tax_dest = cls._create_fiscal_position_no_tax_dest() + + cls.product1 = cls.create_product( 'Product 1', - self.categ_basic, + cls.categ_basic, lst_price=10.99, standard_price=5.0, - tax_ids=self.taxes['tax7'].ids, + tax_ids=cls.taxes['tax7'].ids, ) - self.product2 = self.create_product( + cls.product2 = cls.create_product( 'Product 2', - self.categ_basic, + cls.categ_basic, lst_price=19.99, standard_price=10.0, - tax_ids=self.taxes['tax10'].ids, + tax_ids=cls.taxes['tax10'].ids, ) - self.product3 = self.create_product( + cls.product3 = cls.create_product( 'Product 3', - self.categ_basic, + cls.categ_basic, lst_price=30.99, standard_price=15.0, - tax_ids=self.taxes['tax7'].ids, + tax_ids=cls.taxes['tax7'].ids, ) - self.adjust_inventory([self.product1, self.product2, self.product3], [100, 50, 50]) + cls.adjust_inventory([cls.product1, cls.product2, cls.product3], [100, 50, 50]) - def _create_fiscal_position(self): - fpos = self.env['account.fiscal.position'].create({'name': 'Test Fiscal Position'}) + @classmethod + def _create_fiscal_position(cls): + fpos = cls.env['account.fiscal.position'].create({'name': 'Test Fiscal Position'}) - account_fpos = self.env['account.fiscal.position.account'].create({ + account_fpos = cls.env['account.fiscal.position.account'].create({ 'position_id': fpos.id, - 'account_src_id': self.sale_account.id, - 'account_dest_id': self.other_sale_account.id, + 'account_src_id': cls.sale_account.id, + 'account_dest_id': cls.other_sale_account.id, }) - tax_fpos = self.env['account.fiscal.position.tax'].create({ + tax_fpos = cls.env['account.fiscal.position.tax'].create({ 'position_id': fpos.id, - 'tax_src_id': self.taxes['tax7'].id, - 'tax_dest_id': self.new_tax_17.id, + 'tax_src_id': cls.taxes['tax7'].id, + 'tax_dest_id': cls.new_tax_17.id, }) fpos.write({ 'account_ids': [(6, 0, account_fpos.ids)], @@ -60,16 +67,17 @@ class TestPoSWithFiscalPosition(TestPoSCommon): }) return fpos - def _create_fiscal_position_no_tax_dest(self): - fpos_no_tax_dest = self.env['account.fiscal.position'].create({'name': 'Test Fiscal Position'}) - account_fpos = self.env['account.fiscal.position.account'].create({ + @classmethod + def _create_fiscal_position_no_tax_dest(cls): + fpos_no_tax_dest = cls.env['account.fiscal.position'].create({'name': 'Test Fiscal Position'}) + account_fpos = cls.env['account.fiscal.position.account'].create({ 'position_id': fpos_no_tax_dest.id, - 'account_src_id': self.sale_account.id, - 'account_dest_id': self.other_sale_account.id, + 'account_src_id': cls.sale_account.id, + 'account_dest_id': cls.other_sale_account.id, }) - tax_fpos = self.env['account.fiscal.position.tax'].create({ + tax_fpos = cls.env['account.fiscal.position.tax'].create({ 'position_id': fpos_no_tax_dest.id, - 'tax_src_id': self.taxes['tax7'].id, + 'tax_src_id': cls.taxes['tax7'].id, }) fpos_no_tax_dest.write({ 'account_ids': [(6, 0, account_fpos.ids)], @@ -114,6 +122,7 @@ class TestPoSWithFiscalPosition(TestPoSCommon): | Total balance | 0.0 | +---------------------+---------+ """ + self.customer.write({'property_account_position_id': self.fpos.id}) self.open_new_session() @@ -207,6 +216,7 @@ class TestPoSWithFiscalPosition(TestPoSCommon): | Total balance | 0.0 | +---------------------+---------+ """ + self.customer.write({'property_account_position_id': self.fpos_no_tax_dest.id}) self.open_new_session() # create orders @@ -300,6 +310,7 @@ class TestPoSWithFiscalPosition(TestPoSCommon): | Total balance | 0.0 | +---------------------+---------+ """ + self.customer.write({'property_account_position_id': self.fpos.id}) self.open_new_session() # create orders diff --git a/addons/portal/tests/test_load_process.py b/addons/portal/tests/test_load_process.py index ccefbad8d39..5f9d9802aa1 100644 --- a/addons/portal/tests/test_load_process.py +++ b/addons/portal/tests/test_load_process.py @@ -1,9 +1,11 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import odoo.tests + +from odoo.addons.base.tests.common import HttpCaseWithUserPortal +from odoo.tests import tagged -@odoo.tests.tagged('post_install', '-at_install') -class TestUi(odoo.tests.HttpCase): +@tagged('post_install', '-at_install') +class TestUi(HttpCaseWithUserPortal): def test_01_portal_load_tour(self): self.start_tour("/", 'portal_load_homepage', login="portal") diff --git a/addons/pos_restaurant/tests/test_frontend.py b/addons/pos_restaurant/tests/test_frontend.py index f65150e647b..b4d5a8b3ed8 100644 --- a/addons/pos_restaurant/tests/test_frontend.py +++ b/addons/pos_restaurant/tests/test_frontend.py @@ -9,7 +9,47 @@ class TestFrontend(odoo.tests.HttpCase): env = self.env(user=self.env.ref('base.user_admin')) account_obj = env['account.account'] - pos_config = env.ref('pos_restaurant.pos_config_restaurant') + printer = self.env['restaurant.printer'].create({ + 'name': 'Kitchen Printer', + 'proxy_ip': 'localhost', + }) + drinks_category = self.env['pos.category'].create({'name': 'Drinks'}) + + pos_config = self.env['pos.config'].create({ + 'name': 'Bar', + 'barcode_nomenclature_id': self.env.ref('barcodes.default_barcode_nomenclature').id, + 'module_pos_restaurant': True, + 'is_table_management': True, + 'iface_splitbill': True, + 'iface_printbill': True, + 'iface_orderline_notes': True, + 'printer_ids': [(4, printer.id)], + 'iface_start_categ_id': drinks_category.id, + 'start_category': True, + 'pricelist_id': self.env.ref('product.list0').id, + }) + + main_floor = self.env['restaurant.floor'].create({ + 'name': 'Main Floor', + 'pos_config_id': pos_config.id, + }) + + table_05 = self.env['restaurant.table'].create({ + 'name': 'T5', + 'floor_id': main_floor.id, + 'seats': 4, + }) + table_04 = self.env['restaurant.table'].create({ + 'name': 'T4', + 'floor_id': main_floor.id, + 'seats': 4, + }) + table_02 = self.env['restaurant.table'].create({ + 'name': 'T2', + 'floor_id': main_floor.id, + 'seats': 4, + }) + main_company = env.ref('base.main_company') account_receivable = account_obj.create({'code': 'X1012', @@ -47,14 +87,37 @@ class TestFrontend(odoo.tests.HttpCase): })], }) - coke = self.env.ref('pos_restaurant.coke') - coke.write({'taxes_id': [(6, 0, [])]}) - water = self.env.ref('pos_restaurant.water') - water.write({'taxes_id': [(6, 0, [])]}) - minute_maid = self.env.ref('pos_restaurant.minute_maid') - minute_maid.write({'taxes_id': [(6, 0, [])]}) + coke = self.env['product.product'].create({ + 'available_in_pos': True, + 'list_price': 2.20, + 'name': 'Coca-Cola', + 'weight': 0.01, + 'pos_categ_id': drinks_category.id, + 'categ_id': self.env.ref('point_of_sale.product_category_pos').id, + 'taxes_id': [(6, 0, [])], + }) - pos_config.open_session_cb() + water = self.env['product.product'].create({ + 'available_in_pos': True, + 'list_price': 2.20, + 'name': 'Water', + 'weight': 0.01, + 'pos_categ_id': drinks_category.id, + 'categ_id': self.env.ref('point_of_sale.product_category_pos').id, + 'taxes_id': [(6, 0, [])], + }) + + minute_maid = self.env['product.product'].create({ + 'available_in_pos': True, + 'list_price': 2.20, + 'name': 'Minute Maid', + 'weight': 0.01, + 'pos_categ_id': drinks_category.id, + 'categ_id': self.env.ref('point_of_sale.product_category_pos').id, + 'taxes_id': [(6, 0, [])], + }) + + pos_config.with_user(self.env.ref('base.user_admin')).open_session_cb(check_coa=False) self.start_tour("/pos/web?config_id=%d" % pos_config.id, 'pos_restaurant_sync', login="admin") diff --git a/addons/product/tests/test_pricelist.py b/addons/product/tests/test_pricelist.py index 41e9d206463..610865f5af1 100644 --- a/addons/product/tests/test_pricelist.py +++ b/addons/product/tests/test_pricelist.py @@ -9,8 +9,8 @@ class TestPricelist(TransactionCase): def setUp(self): super(TestPricelist, self).setUp() - self.datacard = self.env.ref('product.product_delivery_02') - self.usb_adapter = self.env.ref('product.product_delivery_01') + self.datacard = self.env['product.product'].create({'name': 'Office Lamp'}) + self.usb_adapter = self.env['product.product'].create({'name': 'Office Chair'}) self.uom_ton = self.env.ref('uom.product_uom_ton') self.uom_unit_id = self.ref('uom.product_uom_unit') self.uom_dozen_id = self.ref('uom.product_uom_dozen') @@ -73,7 +73,7 @@ class TestPricelist(TransactionCase): # make sure 'tonne' resolves down to 1 'kg'. self.uom_ton.write({'rounding': 0.001}) # setup product stored in 'tonnes', with a discounted pricelist for qty > 3 tonnes - spam_id = self.usb_adapter.copy({ + spam_id = self.env['product.product'].create({ 'name': '1 tonne of spam', 'uom_id': self.uom_ton.id, 'uom_po_id': self.uom_ton.id, diff --git a/addons/product/tests/test_product_attribute_value_config.py b/addons/product/tests/test_product_attribute_value_config.py index 2cd783d0f6a..4c7f34e1d1d 100644 --- a/addons/product/tests/test_product_attribute_value_config.py +++ b/addons/product/tests/test_product_attribute_value_config.py @@ -6,108 +6,114 @@ from psycopg2 import IntegrityError from odoo.exceptions import UserError, ValidationError from odoo.tests import tagged -from odoo.tests.common import TransactionCase +from odoo.tests.common import SavepointCase from odoo.tools import mute_logger -class TestProductAttributeValueSetup(TransactionCase): - def setUp(self): - super(TestProductAttributeValueSetup, self).setUp() +class TestProductAttributeValueSetup(SavepointCase): + @classmethod + def setUpClass(cls): + super(TestProductAttributeValueSetup, cls).setUpClass() - self.computer = self.env['product.template'].create({ + cls.computer = cls.env['product.template'].create({ 'name': 'Super Computer', 'price': 2000, }) - self._add_ssd_attribute() - self._add_ram_attribute() - self._add_hdd_attribute() + cls._add_ssd_attribute() + cls._add_ram_attribute() + cls._add_hdd_attribute() - self.computer_case = self.env['product.template'].create({ + cls.computer_case = cls.env['product.template'].create({ 'name': 'Super Computer Case' }) - self._add_size_attribute() + cls._add_size_attribute() - def _add_ssd_attribute(self): - self.ssd_attribute = self.env['product.attribute'].create({'name': 'Memory', 'sequence': 1}) - self.ssd_256 = self.env['product.attribute.value'].create({ + @classmethod + def _add_ssd_attribute(cls): + cls.ssd_attribute = cls.env['product.attribute'].create({'name': 'Memory', 'sequence': 1}) + cls.ssd_256 = cls.env['product.attribute.value'].create({ 'name': '256 GB', - 'attribute_id': self.ssd_attribute.id, + 'attribute_id': cls.ssd_attribute.id, 'sequence': 1, }) - self.ssd_512 = self.env['product.attribute.value'].create({ + cls.ssd_512 = cls.env['product.attribute.value'].create({ 'name': '512 GB', - 'attribute_id': self.ssd_attribute.id, + 'attribute_id': cls.ssd_attribute.id, 'sequence': 2, }) - self._add_ssd_attribute_line() + cls._add_ssd_attribute_line() - def _add_ssd_attribute_line(self): - 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])], + @classmethod + def _add_ssd_attribute_line(cls): + cls.computer_ssd_attribute_lines = cls.env['product.template.attribute.line'].create({ + 'product_tmpl_id': cls.computer.id, + 'attribute_id': cls.ssd_attribute.id, + 'value_ids': [(6, 0, [cls.ssd_256.id, cls.ssd_512.id])], }) - self.computer_ssd_attribute_lines.product_template_value_ids[0].price_extra = 200 - self.computer_ssd_attribute_lines.product_template_value_ids[1].price_extra = 400 + cls.computer_ssd_attribute_lines.product_template_value_ids[0].price_extra = 200 + cls.computer_ssd_attribute_lines.product_template_value_ids[1].price_extra = 400 - def _add_ram_attribute(self): - self.ram_attribute = self.env['product.attribute'].create({'name': 'RAM', 'sequence': 2}) - self.ram_8 = self.env['product.attribute.value'].create({ + @classmethod + def _add_ram_attribute(cls): + cls.ram_attribute = cls.env['product.attribute'].create({'name': 'RAM', 'sequence': 2}) + cls.ram_8 = cls.env['product.attribute.value'].create({ 'name': '8 GB', - 'attribute_id': self.ram_attribute.id, + 'attribute_id': cls.ram_attribute.id, 'sequence': 1, }) - self.ram_16 = self.env['product.attribute.value'].create({ + cls.ram_16 = cls.env['product.attribute.value'].create({ 'name': '16 GB', - 'attribute_id': self.ram_attribute.id, + 'attribute_id': cls.ram_attribute.id, 'sequence': 2, }) - self.ram_32 = self.env['product.attribute.value'].create({ + cls.ram_32 = cls.env['product.attribute.value'].create({ 'name': '32 GB', - 'attribute_id': self.ram_attribute.id, + 'attribute_id': cls.ram_attribute.id, 'sequence': 3, }) - self.computer_ram_attribute_lines = self.env['product.template.attribute.line'].create({ - 'product_tmpl_id': self.computer.id, - 'attribute_id': self.ram_attribute.id, - 'value_ids': [(6, 0, [self.ram_8.id, self.ram_16.id, self.ram_32.id])], + cls.computer_ram_attribute_lines = cls.env['product.template.attribute.line'].create({ + 'product_tmpl_id': cls.computer.id, + 'attribute_id': cls.ram_attribute.id, + 'value_ids': [(6, 0, [cls.ram_8.id, cls.ram_16.id, cls.ram_32.id])], }) - self.computer_ram_attribute_lines.product_template_value_ids[0].price_extra = 20 - self.computer_ram_attribute_lines.product_template_value_ids[1].price_extra = 40 - self.computer_ram_attribute_lines.product_template_value_ids[2].price_extra = 80 + cls.computer_ram_attribute_lines.product_template_value_ids[0].price_extra = 20 + cls.computer_ram_attribute_lines.product_template_value_ids[1].price_extra = 40 + cls.computer_ram_attribute_lines.product_template_value_ids[2].price_extra = 80 - def _add_hdd_attribute(self): - self.hdd_attribute = self.env['product.attribute'].create({'name': 'HDD', 'sequence': 3}) - self.hdd_1 = self.env['product.attribute.value'].create({ + @classmethod + def _add_hdd_attribute(cls): + cls.hdd_attribute = cls.env['product.attribute'].create({'name': 'HDD', 'sequence': 3}) + cls.hdd_1 = cls.env['product.attribute.value'].create({ 'name': '1 To', - 'attribute_id': self.hdd_attribute.id, + 'attribute_id': cls.hdd_attribute.id, 'sequence': 1, }) - self.hdd_2 = self.env['product.attribute.value'].create({ + cls.hdd_2 = cls.env['product.attribute.value'].create({ 'name': '2 To', - 'attribute_id': self.hdd_attribute.id, + 'attribute_id': cls.hdd_attribute.id, 'sequence': 2, }) - self.hdd_4 = self.env['product.attribute.value'].create({ + cls.hdd_4 = cls.env['product.attribute.value'].create({ 'name': '4 To', - 'attribute_id': self.hdd_attribute.id, + 'attribute_id': cls.hdd_attribute.id, 'sequence': 3, }) - self._add_hdd_attribute_line() + cls._add_hdd_attribute_line() - def _add_hdd_attribute_line(self): - self.computer_hdd_attribute_lines = self.env['product.template.attribute.line'].create({ - 'product_tmpl_id': self.computer.id, - 'attribute_id': self.hdd_attribute.id, - 'value_ids': [(6, 0, [self.hdd_1.id, self.hdd_2.id, self.hdd_4.id])], + @classmethod + def _add_hdd_attribute_line(cls): + cls.computer_hdd_attribute_lines = cls.env['product.template.attribute.line'].create({ + 'product_tmpl_id': cls.computer.id, + 'attribute_id': cls.hdd_attribute.id, + 'value_ids': [(6, 0, [cls.hdd_1.id, cls.hdd_2.id, cls.hdd_4.id])], }) - self.computer_hdd_attribute_lines.product_template_value_ids[0].price_extra = 2 - self.computer_hdd_attribute_lines.product_template_value_ids[1].price_extra = 4 - self.computer_hdd_attribute_lines.product_template_value_ids[2].price_extra = 8 + cls.computer_hdd_attribute_lines.product_template_value_ids[0].price_extra = 2 + cls.computer_hdd_attribute_lines.product_template_value_ids[1].price_extra = 4 + cls.computer_hdd_attribute_lines.product_template_value_ids[2].price_extra = 8 def _add_ram_exclude_for(self): self._get_product_value_id(self.computer_ram_attribute_lines, self.ram_16).update({ @@ -117,27 +123,28 @@ class TestProductAttributeValueSetup(TransactionCase): })] }) - def _add_size_attribute(self): - self.size_attribute = self.env['product.attribute'].create({'name': 'Size', 'sequence': 4}) - self.size_m = self.env['product.attribute.value'].create({ + @classmethod + def _add_size_attribute(cls): + cls.size_attribute = cls.env['product.attribute'].create({'name': 'Size', 'sequence': 4}) + cls.size_m = cls.env['product.attribute.value'].create({ 'name': 'M', - 'attribute_id': self.size_attribute.id, + 'attribute_id': cls.size_attribute.id, 'sequence': 1, }) - self.size_l = self.env['product.attribute.value'].create({ + cls.size_l = cls.env['product.attribute.value'].create({ 'name': 'L', - 'attribute_id': self.size_attribute.id, + 'attribute_id': cls.size_attribute.id, 'sequence': 2, }) - self.size_xl = self.env['product.attribute.value'].create({ + cls.size_xl = cls.env['product.attribute.value'].create({ 'name': 'XL', - 'attribute_id': self.size_attribute.id, + 'attribute_id': cls.size_attribute.id, 'sequence': 3, }) - self.computer_case_size_attribute_lines = self.env['product.template.attribute.line'].create({ - 'product_tmpl_id': self.computer_case.id, - 'attribute_id': self.size_attribute.id, - 'value_ids': [(6, 0, [self.size_m.id, self.size_l.id, self.size_xl.id])], + cls.computer_case_size_attribute_lines = cls.env['product.template.attribute.line'].create({ + 'product_tmpl_id': cls.computer_case.id, + 'attribute_id': cls.size_attribute.id, + 'value_ids': [(6, 0, [cls.size_m.id, cls.size_l.id, cls.size_xl.id])], }) def _get_product_value_id(self, product_template_attribute_lines, product_attribute_value): diff --git a/addons/product/tests/test_product_pricelist.py b/addons/product/tests/test_product_pricelist.py index acad92c3930..814d6595447 100644 --- a/addons/product/tests/test_product_pricelist.py +++ b/addons/product/tests/test_product_pricelist.py @@ -11,15 +11,62 @@ class TestProductPricelist(TransactionCase): def setUp(self): super(TestProductPricelist, self).setUp() self.ProductPricelist = self.env['product.pricelist'] - self.res_partner_4 = self.env.ref('base.res_partner_4') - self.computer_SC234 = self.env.ref("product.product_product_3") - self.ipad_retina_display = self.env.ref('product.product_product_4') - self.custom_computer_kit = self.env.ref("product.product_product_5") - self.ipad_mini = self.env.ref("product.product_product_6") - self.apple_in_ear_headphones = self.env.ref("product.product_product_7") - self.laptop_E5023 = self.env.ref('product.product_delivery_01') - self.laptop_S3450 = self.env.ref("product.product_product_25") - self.category_5_id = self.ref('product.product_category_5') + self.res_partner_4 = self.env['res.partner'].create({'name': 'Ready Mat'}) + self.res_partner_1 = self.env['res.partner'].create({'name': 'Wood Corner'}) + self.category_5_id = self.env['product.category'].create({ + 'name': 'Office Furniture', + 'parent_id': self.env.ref('product.product_category_1').id + }).id + self.computer_SC234 = self.env['product.product'].create({ + 'name': 'Desk Combination', + 'categ_id': self.category_5_id, + }) + self.ipad_retina_display = self.env['product.product'].create({ + 'name': 'Customizable Desk', + }) + self.custom_computer_kit = self.env['product.product'].create({ + 'name': 'Corner Desk Right Sit', + 'categ_id': self.category_5_id, + }) + self.ipad_mini = self.env['product.product'].create({ + 'name': 'Large Cabinet', + 'categ_id': self.category_5_id, + 'standard_price': 800.0, + }) + self.env['product.supplierinfo'].create([ + { + 'name': self.res_partner_1.id, + 'product_tmpl_id': self.ipad_mini.product_tmpl_id.id, + 'delay': 3, + 'min_qty': 1, + 'price': 750, + }, { + 'name': self.res_partner_4.id, + 'product_tmpl_id': self.ipad_mini.product_tmpl_id.id, + 'delay': 3, + 'min_qty': 1, + 'price': 790, + }, { + 'name': self.res_partner_4.id, + 'product_tmpl_id': self.ipad_mini.product_tmpl_id.id, + 'delay': 3, + 'min_qty': 3, + 'price': 785, + } + ]) + self.apple_in_ear_headphones = self.env['product.product'].create({ + 'name': 'Storage Box', + 'categ_id': self.category_5_id, + }) + self.laptop_E5023 = self.env['product.product'].create({ + 'name': 'Office Chair', + 'categ_id': self.category_5_id, + }) + self.laptop_S3450 = self.env['product.product'].create({ + 'name': 'Acoustic Bloc Screens', + 'categ_id': self.category_5_id, + }) + self.uom_unit_id = self.ref('uom.product_uom_unit') self.list0 = self.ref('product.list0') diff --git a/addons/product/tests/test_seller.py b/addons/product/tests/test_seller.py index 637c59b78c9..e8e92afbf84 100644 --- a/addons/product/tests/test_seller.py +++ b/addons/product/tests/test_seller.py @@ -8,15 +8,17 @@ class TestSeller(TransactionCase): def setUp(self): super(TestSeller, self).setUp() - self.product_service = self.env.ref('product.product_product_2') + self.product_service = self.env['product.product'].create({ + 'name': 'Virtual Home Staging', + }) self.product_service.default_code = 'DEFCODE' self.product_consu = self.env['product.product'].create({ 'name': 'Boudin', 'type': 'consu', }) self.product_consu.default_code = 'DEFCODE' - self.asustec = self.env.ref('base.res_partner_1') - self.camptocamp = self.env.ref('base.res_partner_12') + self.asustec = self.env['res.partner'].create({'name': 'Wood Corner'}) + self.camptocamp = self.env['res.partner'].create({'name': 'Azure Interior'}) def test_10_sellers(self): self.product_service.write({'seller_ids': [ diff --git a/addons/product_margin/tests/test_product_margin.py b/addons/product_margin/tests/test_product_margin.py index 0e950a77b17..dc3f8a32bd9 100644 --- a/addons/product_margin/tests/test_product_margin.py +++ b/addons/product_margin/tests/test_product_margin.py @@ -1,11 +1,13 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. + from odoo import tools -from odoo.tests import common, Form +from odoo.addons.account.tests.account_minimal_test import AccountMinimalTest +from odoo.tests import Form from odoo.modules.module import get_resource_path -class TestProductMargin(common.TransactionCase): +class TestProductMargin(AccountMinimalTest): def create_account_invoice(self, invoice_type, partner, product, quantity=0.0, price_unit=0.0): """ Create an invoice as in a view by triggering its onchange methods""" @@ -19,19 +21,17 @@ class TestProductMargin(common.TransactionCase): invoice = invoice_form.save() invoice.post() - return invoice def test_product_margin(self): ''' In order to test the product_margin module ''' - # load account_minimal_test.xml file for chart of account in configuration - tools.convert_file(self.cr, 'product_margin', - get_resource_path('account', 'test', 'account_minimal_test.xml'), - {}, 'init', False, 'test', self.registry._assertion_report) - supplier = self.env['res.partner'].create({'name': 'Supplier'}) customer = self.env['res.partner'].create({'name': 'Customer'}) - ipad = self.env.ref("product.product_product_4") + ipad = self.env['product.product'].create({ + 'name': 'Ipad', + 'standard_price': 500.0, + 'list_price': 750.0, + }) # Create supplier invoice and customer invoice to test product margin. # Define supplier invoices diff --git a/addons/purchase/controllers/portal.py b/addons/purchase/controllers/portal.py index 171373bbec5..73e2b2bbb3a 100644 --- a/addons/purchase/controllers/portal.py +++ b/addons/purchase/controllers/portal.py @@ -18,7 +18,7 @@ class CustomerPortal(CustomerPortal): def _prepare_portal_layout_values(self): values = super(CustomerPortal, self)._prepare_portal_layout_values() - values['purchase_count'] = request.env['purchase.order'].search_count([ + values['purchase_count'] = request.env['purchase.order'].sudo().search_count([ ('state', 'in', ['purchase', 'done', 'cancel']) ]) return values diff --git a/addons/purchase/tests/test_purchase_order_report.py b/addons/purchase/tests/test_purchase_order_report.py index fe6e0b79ed4..8d157f3ace1 100644 --- a/addons/purchase/tests/test_purchase_order_report.py +++ b/addons/purchase/tests/test_purchase_order_report.py @@ -2,23 +2,20 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from datetime import datetime -from odoo.tests import common, Form, tagged - +from odoo.tests import Form, tagged +from odoo.addons.account.tests.account_minimal_test import AccountMinimalTest @tagged('post_install', '-at_install') -class TestPurchaseOrderReport(common.TransactionCase): - def setUp(self): - super(TestPurchaseOrderReport, self).setUp() +class TestPurchaseOrderReport(AccountMinimalTest): - self.partner_id = self.env.ref('base.res_partner_1') - self.product1 = self.env.ref('product.product_product_8') - self.product2 = self.env.ref('product.product_product_11') - self.PurchaseReport = self.env['purchase.report'] - - # Create a new company and set CoA - self.company_id = self.env['res.company'].create({'name': 'new_company'}) - self.env.user.company_id = self.company_id - self.env.ref('l10n_generic_coa.configurable_chart_template').try_loading() + @classmethod + def setUpClass(cls): + super(TestPurchaseOrderReport, cls).setUpClass() + cls.partner_id = cls.env['res.partner'].create({'name': 'A Partner'}) + cls.product1 = cls.env['product.product'].create({'name': 'A First Product'}) + cls.product2 = cls.env['product.product'].create({'name': 'A Second Product'}) + cls.PurchaseReport = cls.env['purchase.report'] + cls.company_id = cls.env.ref('base.main_company') def test_00_purchase_order_report(self): uom_dozen = self.env.ref('uom.product_uom_dozen') diff --git a/addons/purchase_mrp/tests/test_purchase_mrp_flow.py b/addons/purchase_mrp/tests/test_purchase_mrp_flow.py index dd0d05f4990..daf8ffc299d 100644 --- a/addons/purchase_mrp/tests/test_purchase_mrp_flow.py +++ b/addons/purchase_mrp/tests/test_purchase_mrp_flow.py @@ -223,7 +223,7 @@ class TestSaleMrpFlow(TransactionCase): # |- component_e x1 # Creation of a sale order for x7 kit_parent - partner = self.env.ref('base.res_partner_1') + partner = self.env['res.partner'].create({'name': 'My Test Partner'}) f = Form(self.env['purchase.order']) f.partner_id = partner with f.order_line.new() as line: diff --git a/addons/purchase_requisition/tests/common.py b/addons/purchase_requisition/tests/common.py index 7ae6e1781d8..235208b8a89 100644 --- a/addons/purchase_requisition/tests/common.py +++ b/addons/purchase_requisition/tests/common.py @@ -35,7 +35,7 @@ class TestPurchaseRequisitionCommon(common.SavepointCase): cls.product_09 = cls.env['product.product'].create({ 'name': 'Pedal Bin', - 'categ_id': cls.env.ref('product.product_category_5').id, + 'categ_id': cls.env.ref('product.product_category_all').id, 'standard_price': 10.0, 'list_price': 47.0, 'type': 'consu', @@ -46,7 +46,7 @@ class TestPurchaseRequisitionCommon(common.SavepointCase): cls.product_13 = cls.env['product.product'].create({ 'name': 'Corner Desk Black', - 'categ_id': cls.env.ref('product.product_category_5').id, + 'categ_id': cls.env.ref('product.product_category_all').id, 'standard_price': 78.0, 'list_price': 85.0, 'type': 'consu', @@ -64,5 +64,7 @@ class TestPurchaseRequisitionCommon(common.SavepointCase): 'product_uom_id': cls.product_uom_id.id})] }) - cls.res_partner_1 = cls.env.ref('base.res_partner_1') + cls.res_partner_1 = cls.env['res.partner'].create({ + 'name': 'Wood Corner', + }) cls.env.user.company_id.currency_id = cls.env.ref("base.USD").id diff --git a/addons/purchase_stock/tests/common.py b/addons/purchase_stock/tests/common.py index 5a5281f25e1..1b269632e44 100644 --- a/addons/purchase_stock/tests/common.py +++ b/addons/purchase_stock/tests/common.py @@ -22,11 +22,6 @@ class TestPurchase(TestStockCommon): product.name, '/', self.env.company, order_values) ]) - def _load(self, module, *args): - tools.convert_file(self.cr, 'purchase', - get_module_resource(module, *args), - {}, 'init', False, 'test', self.registry._assertion_report) - @classmethod def setUpClass(cls): super(TestPurchase, cls).setUpClass() diff --git a/addons/purchase_stock/tests/test_average_price.py b/addons/purchase_stock/tests/test_average_price.py index 2b93d8c5547..07f0a27dd6d 100644 --- a/addons/purchase_stock/tests/test_average_price.py +++ b/addons/purchase_stock/tests/test_average_price.py @@ -4,15 +4,16 @@ import time from .common import TestPurchase +from odoo.addons.stock_account.tests.stock_account_minimal_test import StockAccountMinimalTest - -class TestAveragePrice(TestPurchase): +class TestAveragePrice(TestPurchase, StockAccountMinimalTest): def test_00_average_price(self): """ Testcase for average price computation""" - self._load('account', 'test', 'account_minimal_test.xml') - self._load('stock_account', 'test', 'stock_valuation_account.xml') + res_partner_3 = self.env['res.partner'].create({ + 'name': 'Gemini Partner', + }) # Set a product as using average price. product_cable_management_box = self.env['product.product'].create({ @@ -29,12 +30,12 @@ class TestAveragePrice(TestPurchase): }) product_cable_management_box.categ_id.property_cost_method = 'average' product_cable_management_box.categ_id.property_valuation = 'real_time' - product_cable_management_box.categ_id.property_stock_account_input_categ_id = self.ref('purchase.o_expense') - product_cable_management_box.categ_id.property_stock_account_output_categ_id = self.ref('purchase.o_income') + product_cable_management_box.categ_id.property_stock_account_input_categ_id = self.o_expense + product_cable_management_box.categ_id.property_stock_account_output_categ_id = self.o_income # I create a draft Purchase Order for first incoming shipment for 10 pieces at 60€ purchase_order_1 = self.env['purchase.order'].create({ - 'partner_id': self.env.ref('base.res_partner_3').id, + 'partner_id': res_partner_3.id, 'order_line': [(0, 0, { 'name': 'Average Ice Cream', 'product_id': product_cable_management_box.id, @@ -62,7 +63,7 @@ class TestAveragePrice(TestPurchase): # I create a draft Purchase Order for second incoming shipment for 30 pieces at 80€ purchase_order_2 = self.env['purchase.order'].create({ - 'partner_id': self.env.ref('base.res_partner_3').id, + 'partner_id': res_partner_3.id, 'order_line': [(0, 0, { 'name': product_cable_management_box.name, 'product_id': product_cable_management_box.id, @@ -108,7 +109,7 @@ class TestAveragePrice(TestPurchase): # Make a new purchase order with 500 g Average Ice Cream at a price of 0.2€/g purchase_order_3 = self.env['purchase.order'].create({ - 'partner_id': self.env.ref('base.res_partner_3').id, + 'partner_id': res_partner_3.id, 'order_line': [(0, 0, { 'name': product_cable_management_box.name, 'product_id': product_cable_management_box.id, diff --git a/addons/purchase_stock/tests/test_create_picking.py b/addons/purchase_stock/tests/test_create_picking.py index 7980a251afc..8a001a41cbb 100644 --- a/addons/purchase_stock/tests/test_create_picking.py +++ b/addons/purchase_stock/tests/test_create_picking.py @@ -10,9 +10,9 @@ class TestCreatePicking(common.TestProductCommon): def setUp(self): super(TestCreatePicking, self).setUp() - self.partner_id = self.env.ref('base.res_partner_1') - self.product_id_1 = self.env.ref('product.product_product_8') - self.product_id_2 = self.env.ref('product.product_product_11') + self.partner_id = self.env['res.partner'].create({'name': 'Wood Corner Partner'}) + self.product_id_1 = self.env['product.product'].create({'name': 'Large Desk'}) + self.product_id_2 = self.env['product.product'].create({'name': 'Conference Chair'}) res_users_purchase_user = self.env.ref('purchase.group_purchase_user') Users = self.env['res.users'].with_context({'no_reset_password': True, 'mail_create_nosubscribe': True}) diff --git a/addons/purchase_stock/tests/test_fifo_price.py b/addons/purchase_stock/tests/test_fifo_price.py index 38b4365a7d6..bea7347575e 100644 --- a/addons/purchase_stock/tests/test_fifo_price.py +++ b/addons/purchase_stock/tests/test_fifo_price.py @@ -3,15 +3,16 @@ import time from .common import TestPurchase +from odoo.addons.stock_account.tests.stock_account_minimal_test import StockAccountMinimalTest - -class TestFifoPrice(TestPurchase): +class TestFifoPrice(TestPurchase, StockAccountMinimalTest): def test_00_test_fifo(self): """ Test product cost price with fifo removal strategy.""" - self._load('account', 'test', 'account_minimal_test.xml') - self._load('stock_account', 'test', 'stock_valuation_account.xml') + res_partner_3 = self.env['res.partner'].create({ + 'name': 'Gemini Partner', + }) # Set a product as using fifo price product_cable_management_box = self.env['product.product'].create({ @@ -28,12 +29,12 @@ class TestFifoPrice(TestPurchase): }) product_cable_management_box.categ_id.property_cost_method = 'fifo' product_cable_management_box.categ_id.property_valuation = 'real_time' - product_cable_management_box.categ_id.property_stock_account_input_categ_id = self.ref('purchase.o_expense') - product_cable_management_box.categ_id.property_stock_account_output_categ_id = self.ref('purchase.o_income') + product_cable_management_box.categ_id.property_stock_account_input_categ_id = self.o_expense + product_cable_management_box.categ_id.property_stock_account_output_categ_id = self.o_income # I create a draft Purchase Order for first in move for 10 kg at 50 euro purchase_order_1 = self.env['purchase.order'].create({ - 'partner_id': self.env.ref('base.res_partner_3').id, + 'partner_id': res_partner_3.id, 'order_line': [(0, 0, { 'name': 'FIFO Ice Cream', 'product_id': product_cable_management_box.id, @@ -61,7 +62,7 @@ class TestFifoPrice(TestPurchase): # I create a draft Purchase Order for second shipment for 30 kg at 80 euro purchase_order_2 = self.env['purchase.order'].create({ - 'partner_id': self.env.ref('base.res_partner_3').id, + 'partner_id': res_partner_3.id, 'order_line': [(0, 0, { 'name': 'FIFO Ice Cream', 'product_id': product_cable_management_box.id, @@ -144,7 +145,7 @@ class TestFifoPrice(TestPurchase): # Create PO for 30000 g at 0.150$/g and 10 kg at 150$/kg purchase_order_usd = self.env['purchase.order'].create({ - 'partner_id': self.env.ref('base.res_partner_3').id, + 'partner_id': res_partner_3.id, 'currency_id': NewUSD.id, 'order_line': [(0, 0, { 'name': 'FIFO Ice Cream', @@ -229,8 +230,8 @@ class TestFifoPrice(TestPurchase): }) product_fifo_negative.categ_id.property_cost_method = 'fifo' product_fifo_negative.categ_id.property_valuation = 'real_time' - product_fifo_negative.categ_id.property_stock_account_input_categ_id = self.ref('purchase.o_expense') - product_fifo_negative.categ_id.property_stock_account_output_categ_id = self.ref('purchase.o_income') + product_fifo_negative.categ_id.property_stock_account_input_categ_id = self.o_expense + product_fifo_negative.categ_id.property_stock_account_output_categ_id = self.o_income # Create outpicking.create delivery order of 100 kg. outgoing_shipment_neg = self.env['stock.picking'].create({ @@ -283,7 +284,7 @@ class TestFifoPrice(TestPurchase): # Receive purchase order with 50 kg Ice Cream at 50€/kg purchase_order_neg = self.env['purchase.order'].create({ - 'partner_id': self.env.ref('base.res_partner_3').id, + 'partner_id': res_partner_3.id, 'order_line': [(0, 0, { 'name': 'FIFO Ice Cream', 'product_id': product_fifo_negative.id, @@ -303,7 +304,7 @@ class TestFifoPrice(TestPurchase): # Receive purchase order with 600 kg FIFO Ice Cream at 80 euro/kg purchase_order_neg2 = self.env['purchase.order'].create({ - 'partner_id': self.env.ref('base.res_partner_3').id, + 'partner_id': res_partner_3.id, 'order_line': [(0, 0, { 'name': product_cable_management_box.name, 'product_id': product_fifo_negative.id, diff --git a/addons/purchase_stock/tests/test_fifo_returns.py b/addons/purchase_stock/tests/test_fifo_returns.py index 3354e4d0ac0..d20835111cb 100644 --- a/addons/purchase_stock/tests/test_fifo_returns.py +++ b/addons/purchase_stock/tests/test_fifo_returns.py @@ -4,14 +4,16 @@ import time from .common import TestPurchase from odoo.tests.common import Form +from odoo.addons.stock_account.tests.stock_account_minimal_test import StockAccountMinimalTest -class TestFifoReturns(TestPurchase): + +class TestFifoReturns(TestPurchase, StockAccountMinimalTest): def test_fifo_returns(self): """Test to create product and purchase order to test the FIFO returns of the product""" - - self._load('account', 'test', 'account_minimal_test.xml') - self._load('stock_account', 'test', 'stock_valuation_account.xml') + res_partner_3 = self.env['res.partner'].create({ + 'name': 'Gemini Partner', + }) # Set a product as using fifo price product_fiforet_icecream = self.env['product.product'].create({ @@ -26,12 +28,12 @@ class TestFifoReturns(TestPurchase): }) product_fiforet_icecream.categ_id.property_cost_method = 'fifo' product_fiforet_icecream.categ_id.property_valuation = 'real_time' - product_fiforet_icecream.categ_id.property_stock_account_input_categ_id = self.ref('purchase.o_expense') - product_fiforet_icecream.categ_id.property_stock_account_output_categ_id = self.ref('purchase.o_income') + product_fiforet_icecream.categ_id.property_stock_account_input_categ_id = self.o_expense + product_fiforet_icecream.categ_id.property_stock_account_output_categ_id = self.o_income # I create a draft Purchase Order for first in move for 10 kg at 50 euro purchase_order_1 = self.env['purchase.order'].create({ - 'partner_id': self.ref('base.res_partner_3'), + 'partner_id': res_partner_3.id, 'order_line': [(0, 0, { 'name': 'FIFO Ice Cream', 'product_id': product_fiforet_icecream.id, @@ -44,7 +46,7 @@ class TestFifoReturns(TestPurchase): # Create a draft Purchase Order for second shipment for 30kg at 80€/kg purchase_order_2 = self.env['purchase.order'].create({ - 'partner_id': self.ref('base.res_partner_3'), + 'partner_id': res_partner_3.id, 'order_line': [(0, 0, { 'name': 'FIFO Ice Cream', 'product_id': product_fiforet_icecream.id, diff --git a/addons/purchase_stock/tests/test_onchange_product.py b/addons/purchase_stock/tests/test_onchange_product.py index 3628d75affe..dc75bf8ce5c 100644 --- a/addons/purchase_stock/tests/test_onchange_product.py +++ b/addons/purchase_stock/tests/test_onchange_product.py @@ -83,7 +83,7 @@ class TestOnchangeProductId(TransactionCase): po_line._onchange_quantity() self.assertEqual(1200, po_line.price_unit, "Unit price should be 1200 for one Dozen") - product_ipad = self.env.ref('product.product_product_4') + product_ipad = self.env['product.product'].create({'name': 'Conference Chair'}) po_line2 = self.po_line_model.create({ 'name': product_ipad.name, 'product_id': product_ipad.id, diff --git a/addons/purchase_stock/tests/test_purchase_delete_order.py b/addons/purchase_stock/tests/test_purchase_delete_order.py index c45f3ed8c57..23a0279e7ba 100644 --- a/addons/purchase_stock/tests/test_purchase_delete_order.py +++ b/addons/purchase_stock/tests/test_purchase_delete_order.py @@ -11,19 +11,32 @@ class TestDeleteOrder(TestPurchase): ''' Testcase for deleting purchase order with purchase user group''' # In order to test delete process on purchase order,tried to delete a confirmed order and check Error Message. - purchase_order_1 = self.env.ref('purchase.purchase_order_1').with_user(self.res_users_purchase_user) + partner = self.env['res.partner'].create({'name': 'My Partner'}) + + purchase_order = self.env['purchase.order'].create({ + 'partner_id': partner.id, + 'state': 'purchase', + }) + purchase_order_1 = purchase_order.with_user(self.res_users_purchase_user) with self.assertRaises(UserError): purchase_order_1.unlink() # Delete 'cancelled' purchase order with user group - purchase_order_7 = self.env.ref('purchase.purchase_order_7').with_user(self.res_users_purchase_user) - purchase_order_7.button_cancel() - self.assertEqual(purchase_order_7.state, 'cancel', 'PO is cancelled!') - purchase_order_7.unlink() + purchase_order = self.env['purchase.order'].create({ + 'partner_id': partner.id, + 'state': 'purchase', + }) + purchase_order_2 = purchase_order.with_user(self.res_users_purchase_user) + purchase_order_2.button_cancel() + self.assertEqual(purchase_order_2.state, 'cancel', 'PO is cancelled!') + purchase_order_2.unlink() # Delete 'draft' purchase order with user group - purchase_order_5 = self.env.ref('purchase.purchase_order_5').with_user(self.res_users_purchase_user) - self.assertEqual(purchase_order_5.state, 'draft', 'PO in draft state!') - purchase_order_5.button_cancel() - self.assertEqual(purchase_order_5.state, 'cancel', 'PO is cancelled!') - purchase_order_5.unlink() + purchase_order = self.env['purchase.order'].create({ + 'partner_id': partner.id, + 'state': 'draft', + }) + purchase_order_3 = purchase_order.with_user(self.res_users_purchase_user) + purchase_order_3.button_cancel() + self.assertEqual(purchase_order_3.state, 'cancel', 'PO is cancelled!') + purchase_order_3.unlink() diff --git a/addons/purchase_stock/tests/test_purchase_order.py b/addons/purchase_stock/tests/test_purchase_order.py index 75eaefac587..9358da80959 100644 --- a/addons/purchase_stock/tests/test_purchase_order.py +++ b/addons/purchase_stock/tests/test_purchase_order.py @@ -16,9 +16,9 @@ class TestPurchaseOrder(AccountingTestCase): # Useful models self.PurchaseOrder = self.env['purchase.order'] self.PurchaseOrderLine = self.env['purchase.order.line'] - self.partner_id = self.env.ref('base.res_partner_1') - self.product_id_1 = self.env.ref('product.product_product_8') - self.product_id_2 = self.env.ref('product.product_product_11') + self.partner_id = self.env['res.partner'].create({'name': 'Wood Corner Partner'}) + self.product_id_1 = self.env['product.product'].create({'name': 'Large Desk'}) + self.product_id_2 = self.env['product.product'].create({'name': 'Conference Chair'}) (self.product_id_1 | self.product_id_2).write({'purchase_method': 'purchase'}) self.po_vals = { diff --git a/addons/purchase_stock/tests/test_purchase_order_process.py b/addons/purchase_stock/tests/test_purchase_order_process.py index 5ea75e32d28..4689735882b 100644 --- a/addons/purchase_stock/tests/test_purchase_order_process.py +++ b/addons/purchase_stock/tests/test_purchase_order_process.py @@ -7,7 +7,11 @@ class TestPurchaseOrderProcess(TestPurchase): """ Test cancel purchase order with group user.""" # In order to test the cancel flow,start it from canceling confirmed purchase order. - po_edit_with_user = self.env.ref('purchase.purchase_order_5').with_user(self.res_users_purchase_user) + purchase_order = self.env['purchase.order'].create({ + 'partner_id': self.env['res.partner'].create({'name': 'My Partner'}).id, + 'state': 'draft', + }) + po_edit_with_user = purchase_order.with_user(self.res_users_purchase_user) # Confirm the purchase order. po_edit_with_user.button_confirm() diff --git a/addons/purchase_stock/tests/test_stockvaluation.py b/addons/purchase_stock/tests/test_stockvaluation.py index 28a56598929..a8622746f93 100644 --- a/addons/purchase_stock/tests/test_stockvaluation.py +++ b/addons/purchase_stock/tests/test_stockvaluation.py @@ -17,8 +17,16 @@ class TestStockValuation(TransactionCase): super(TestStockValuation, self).setUp() self.supplier_location = self.env.ref('stock.stock_location_suppliers') self.stock_location = self.env.ref('stock.stock_location_stock') - self.partner_id = self.env.ref('base.res_partner_1') - self.product1 = self.env.ref('product.product_product_8') + self.partner_id = self.env['res.partner'].create({ + 'name': 'Wood Corner Partner', + 'company_id': self.env.user.company_id.id, + }) + self.product1 = self.env['product.product'].create({ + 'name': 'Large Desk', + 'standard_price': 1299.0, + 'list_price': 1799.0, + 'type': 'product', + }) Account = self.env['account.account'] self.stock_input_account = Account.create({ 'name': 'Stock Input', @@ -287,7 +295,8 @@ class TestStockValuationWithCOA(AccountingTestCase): super(TestStockValuationWithCOA, self).setUp() self.supplier_location = self.env.ref('stock.stock_location_suppliers') self.stock_location = self.env.ref('stock.stock_location_stock') - self.partner_id = self.env.ref('base.res_partner_1') + self.partner_id = self.env['res.partner'].create({'name': 'Wood Corner Partner'}) + self.product1 = self.env['product.product'].create({'name': 'Large Desk'}) self.cat = self.env['product.category'].create({ 'name': 'cat', @@ -520,6 +529,7 @@ class TestStockValuationWithCOA(AccountingTestCase): """ company = self.env.user.company_id company.anglo_saxon_accounting = True + company.currency_id = self.usd_currency date_po = '2019-01-01' @@ -587,6 +597,7 @@ class TestStockValuationWithCOA(AccountingTestCase): self.assertEqual(len(move_lines), 2) payable_line = move_lines.filtered(lambda l: l.account_id.internal_type == 'payable') + self.assertEqual(payable_line.amount_currency, -100.0) self.assertAlmostEqual(payable_line.balance, -66.67) @@ -603,6 +614,7 @@ class TestStockValuationWithCOA(AccountingTestCase): """ company = self.env.user.company_id company.anglo_saxon_accounting = True + company.currency_id = self.usd_currency self.product1.product_tmpl_id.categ_id.property_cost_method = 'average' self.product1.product_tmpl_id.categ_id.property_valuation = 'real_time' @@ -778,6 +790,7 @@ class TestStockValuationWithCOA(AccountingTestCase): """ company = self.env.user.company_id company.anglo_saxon_accounting = True + company.currency_id = self.usd_currency self.product1.product_tmpl_id.categ_id.property_cost_method = 'average' self.product1.product_tmpl_id.categ_id.property_valuation = 'real_time' @@ -938,6 +951,7 @@ class TestStockValuationWithCOA(AccountingTestCase): """ company = self.env.user.company_id company.anglo_saxon_accounting = True + company.currency_id = self.usd_currency exchange_diff_journal = company.currency_exchange_journal_id.exists() date_po = '2019-01-01' diff --git a/addons/repair/tests/test_repair.py b/addons/repair/tests/test_repair.py index 7d8578d3f3f..a144de37972 100644 --- a/addons/repair/tests/test_repair.py +++ b/addons/repair/tests/test_repair.py @@ -10,33 +10,158 @@ from odoo.tests import tagged @tagged('post_install', '-at_install') class TestRepair(AccountingTestCase): - def setUp(self): - super(TestRepair, self).setUp() + @classmethod + def setUpClass(cls): + super(TestRepair, cls).setUpClass() - self.Repair = self.env['repair.order'] - self.ResUsers = self.env['res.users'] - self.RepairMakeInvoice = self.env['repair.order.make_invoice'] - self.res_group_user = self.env.ref('stock.group_stock_user') - self.res_group_manager = self.env.ref('stock.group_stock_manager') - self.repair_r0 = self.env.ref('repair.repair_r0') - self.repair_r1 = self.env.ref('repair.repair_r1') - self.repair_r2 = self.env.ref('repair.repair_r2') + # Partners + cls.res_partner_1 = cls.env['res.partner'].create({'name': 'Wood Corner'}) + cls.res_partner_address_1 = cls.env['res.partner'].create({'name': 'Willie Burke', 'parent_id': cls.res_partner_1.id}) + cls.res_partner_12 = cls.env['res.partner'].create({'name': 'Partner 12'}) - self.res_repair_user = self.ResUsers.create({ + # Products + cls.product_product_3 = cls.env['product.product'].create({'name': 'Desk Combination'}) + cls.product_product_11 = cls.env['product.product'].create({'name': 'Conference Chair'}) + cls.product_product_5 = cls.env['product.product'].create({'name': 'Product 5'}) + cls.product_product_6 = cls.env['product.product'].create({'name': 'Large Cabinet'}) + cls.product_product_12 = cls.env['product.product'].create({'name': 'Office Chair Black'}) + cls.product_product_13 = cls.env['product.product'].create({'name': 'Corner Desk Black'}) + cls.product_product_2 = cls.env['product.product'].create({'name': 'Virtual Home Staging'}) + cls.product_service_order_repair = cls.env['product.product'].create({ + 'name': 'Repair Services', + 'type': 'service', + }) + + # Location + cls.stock_location_14 = cls.env['stock.location'].create({ + 'name': 'Shelf 2', + 'location_id': cls.env.ref('stock.warehouse0').lot_stock_id.id, + }) + + # Repair Orders + cls.repair1 = cls.env['repair.order'].create({ + 'address_id': cls.res_partner_address_1.id, + 'guarantee_limit': datetime.today().strftime('%Y-%m-%d'), + 'invoice_method': 'none', + 'user_id': False, + 'product_id': cls.product_product_3.id, + 'product_uom': cls.env.ref('uom.product_uom_unit').id, + 'partner_invoice_id': cls.res_partner_address_1.id, + 'location_id': cls.env.ref('stock.stock_location_stock').id, + 'operations': [ + (0, 0, { + 'location_dest_id': cls.product_product_11.property_stock_production.id, + 'location_id': cls.env.ref('stock.stock_location_stock').id, + 'name': cls.product_product_11.get_product_multiline_description_sale(), + 'product_id': cls.product_product_11.id, + 'product_uom': cls.env.ref('uom.product_uom_unit').id, + 'product_uom_qty': 1.0, + 'price_unit': 50.0, + 'state': 'draft', + 'type': 'add', + 'company_id': cls.env.company.id, + }) + ], + 'fees_lines': [ + (0, 0, { + 'name': cls.product_service_order_repair.get_product_multiline_description_sale(), + 'product_id': cls.product_service_order_repair.id, + 'product_uom_qty': 1.0, + 'product_uom': cls.env.ref('uom.product_uom_unit').id, + 'price_unit': 50.0, + 'company_id': cls.env.company.id, + }) + ], + 'partner_id': cls.res_partner_12.id, + }) + + cls.repair0 = cls.env['repair.order'].create({ + 'product_id': cls.product_product_5.id, + 'product_uom': cls.env.ref('uom.product_uom_unit').id, + 'address_id': cls.res_partner_address_1.id, + 'guarantee_limit': datetime.today().strftime('%Y-%m-%d'), + 'invoice_method': 'after_repair', + 'user_id': False, + 'partner_invoice_id': cls.res_partner_address_1.id, + 'location_id': cls.env.ref('stock.stock_location_stock').id, + 'operations': [ + (0, 0, { + 'location_dest_id': cls.product_product_12.property_stock_production.id, + 'location_id': cls.env.ref('stock.stock_location_stock').id, + 'name': cls.product_product_12.get_product_multiline_description_sale(), + 'price_unit': 50.0, + 'product_id': cls.product_product_12.id, + 'product_uom': cls.env.ref('uom.product_uom_unit').id, + 'product_uom_qty': 1.0, + 'state': 'draft', + 'type': 'add', + 'company_id': cls.env.company.id, + }) + ], + 'fees_lines': [ + (0, 0, { + 'name': cls.product_service_order_repair.get_product_multiline_description_sale(), + 'product_id': cls.product_service_order_repair.id, + 'product_uom_qty': 1.0, + 'product_uom': cls.env.ref('uom.product_uom_unit').id, + 'price_unit': 50.0, + 'company_id': cls.env.company.id, + }) + ], + 'partner_id': cls.res_partner_12.id, + }) + + cls.repair2 = cls.env['repair.order'].create({ + 'product_id': cls.product_product_6.id, + 'product_uom': cls.env.ref('uom.product_uom_unit').id, + 'address_id': cls.res_partner_address_1.id, + 'guarantee_limit': datetime.today().strftime('%Y-%m-%d'), + 'invoice_method': 'b4repair', + 'user_id': False, + 'partner_invoice_id': cls.res_partner_address_1.id, + 'location_id': cls.stock_location_14.id, + 'operations': [ + (0, 0, { + 'location_dest_id': cls.product_product_13.property_stock_production.id, + 'location_id': cls.env.ref('stock.stock_location_stock').id, + 'name': cls.product_product_13.get_product_multiline_description_sale(), + 'price_unit': 50.0, + 'product_id': cls.product_product_13.id, + 'product_uom': cls.env.ref('uom.product_uom_unit').id, + 'product_uom_qty': 1.0, + 'state': 'draft', + 'type': 'add', + 'company_id': cls.env.company.id, + }) + ], + 'fees_lines': [ + (0, 0, { + 'name': cls.product_service_order_repair.get_product_multiline_description_sale(), + 'product_id': cls.product_service_order_repair.id, + 'product_uom_qty': 1.0, + 'product_uom': cls.env.ref('uom.product_uom_unit').id, + 'price_unit': 50.0, + 'company_id': cls.env.company.id, + }) + ], + 'partner_id': cls.res_partner_12.id, + }) + + cls.res_repair_user = cls.env['res.users'].create({ 'name': 'Repair User', 'login': 'maru', 'email': 'repair_user@yourcompany.com', - 'groups_id': [(6, 0, [self.res_group_user.id])]}) + 'groups_id': [(6, 0, [cls.env.ref('stock.group_stock_user').id])]}) - self.res_repair_manager = self.ResUsers.create({ + cls.res_repair_manager = cls.env['res.users'].create({ 'name': 'Repair Manager', 'login': 'marm', 'email': 'repair_manager@yourcompany.com', - 'groups_id': [(6, 0, [self.res_group_manager.id])]}) + 'groups_id': [(6, 0, [cls.env.ref('stock.group_stock_manager').id])]}) def _create_simple_repair_order(self, invoice_method): - product_to_repair = self.env.ref('product.product_product_5') - partner = self.env.ref('base.res_partner_address_1') + product_to_repair = self.product_product_5 + partner = self.res_partner_address_1 return self.env['repair.order'].create({ 'product_id': product_to_repair.id, 'product_uom': product_to_repair.uom_id.id, @@ -45,11 +170,11 @@ class TestRepair(AccountingTestCase): 'invoice_method': invoice_method, 'partner_invoice_id': partner.id, 'location_id': self.env.ref('stock.stock_location_stock').id, - 'partner_id': self.env.ref('base.res_partner_12').id + 'partner_id': self.res_partner_12.id }) def _create_simple_operation(self, repair_id=False, qty=0.0, price_unit=0.0): - product_to_add = self.env.ref('product.product_product_5') + product_to_add = self.product_product_5 return self.env['repair.line'].create({ 'name': 'Add The product', 'type': 'add', @@ -64,7 +189,7 @@ class TestRepair(AccountingTestCase): }) def _create_simple_fee(self, repair_id=False, qty=0.0, price_unit=0.0): - product_service = self.env.ref('product.product_product_2') + product_service = self.product_product_2 return self.env['repair.fee'].create({ 'name': 'PC Assemble + Custom (PC on Demand)', 'product_id': product_service.id, @@ -92,7 +217,7 @@ class TestRepair(AccountingTestCase): repair.action_repair_end() # I define Invoice Method 'After Repair' option in this Repair order.so I create invoice by clicking on "Make Invoice" wizard. - make_invoice = self.RepairMakeInvoice.create({ + make_invoice = self.env['repair.order.make_invoice'].create({ 'group': True}) # I click on "Create Invoice" button of this wizard to make invoice. context = { @@ -147,7 +272,7 @@ class TestRepair(AccountingTestCase): 'Repaired product went to the wrong location') self.assertEqual(repair.operations.move_id.location_id.id, self.env.ref('stock.stock_location_stock').id, 'Consumed product was taken in the wrong location') - self.assertEqual(repair.operations.move_id.location_dest_id.id, self.env.ref('product.product_product_5').property_stock_production.id, + self.assertEqual(repair.operations.move_id.location_dest_id.id, self.product_product_5.property_stock_production.id, 'Consumed product went to the wrong location') # I define Invoice Method 'No Invoice' option in this repair order. diff --git a/addons/resource/data/resource_data.xml b/addons/resource/data/resource_data.xml index 9f269ece5d0..aa4ff25e593 100644 --- a/addons/resource/data/resource_data.xml +++ b/addons/resource/data/resource_data.xml @@ -26,7 +26,7 @@ 7.0 7.6 =', + 'max_value': 5, + 'list_base_price': 50, + }, { + 'carrier_id': cls.carrier.id, + 'operator': '>=', + 'max_value': 300, + 'variable': 'price', + 'list_base_price': 0, + }]) + # Test a free shipping reward + some expected behavior # (automatic line addition or removal) @@ -148,11 +186,6 @@ class TestSaleCouponProgramRules(TestSaleCouponCommon): def test_shipping_cost_numbers(self): # Free delivery should not be taken into account when checking for minimum required threshold - tax_15pc_excl = self.env['account.tax'].create({ - 'name': "15% Tax excl", - 'amount_type': 'percent', - 'amount': 15, - }) p_minimum_threshold_free_delivery = self.env['sale.coupon.program'].create({ 'name': 'free shipping if > 872 tax exl', 'promo_code_usage': 'code_needed', @@ -178,16 +211,11 @@ class TestSaleCouponProgramRules(TestSaleCouponCommon): 'product_uom_qty': 3.0, 'order_id': order.id, }) - # The delivery product has 15% tax on dball but not on dbbase. A module is probably adding the tax at some point. - # We want that tax to be set so we can be sure it is not added to the order total paid amount used in coupon as - # it was wrongly done before. - carrier = self.env.ref('delivery.delivery_carrier') - carrier.product_id.taxes_id = tax_15pc_excl # I add delivery cost in Sales order delivery_wizard = Form(self.env['choose.delivery.carrier'].with_context({ 'default_order_id': order.id, - 'default_carrier_id': carrier.id + 'default_carrier_id': self.carrier.id })) choose_delivery_carrier = delivery_wizard.save() choose_delivery_carrier.button_confirm() diff --git a/addons/sale_expense/tests/test_sale_expense.py b/addons/sale_expense/tests/test_sale_expense.py index 920d1ee51fd..2f61fc67f0c 100644 --- a/addons/sale_expense/tests/test_sale_expense.py +++ b/addons/sale_expense/tests/test_sale_expense.py @@ -13,7 +13,13 @@ class TestSaleExpense(TestSale): self.env.ref('product.list0').currency_id = self.env.ref('base.main_company').currency_id # create a so with a product invoiced on delivery - prod = self.env.ref('product.product_product_1') + prod = self.env['product.product'].create({ + 'name': 'A product', + 'invoice_policy': 'delivery', + 'list_price': 30.75, + 'uom_id': self.env.ref('uom.product_uom_hour').id, + 'uom_po_id': self.env.ref('uom.product_uom_hour').id, + }) so = self.env['sale.order'].create({ 'partner_id': self.partner.id, 'partner_invoice_id': self.partner.id, @@ -27,12 +33,18 @@ class TestSaleExpense(TestSale): init_price = so.amount_total # create some expense and validate it (expense at cost) - prod_exp_1 = self.env.ref('hr_expense.air_ticket') + prod_exp_1 = self.env['product.product'].create({ + 'name': 'Air Ticket', + 'list_price': 700, + 'can_be_expensed': True, + 'expense_policy': 'cost', + 'type': 'service', + 'invoice_policy': 'delivery', + }) company = self.env.ref('base.main_company') journal = self.env['account.journal'].create({'name': 'Purchase Journal - Test', 'code': 'HRTPJ', 'type': 'purchase', 'company_id': company.id}) - account_payable = self.env['account.account'].create({'code': 'X1111', 'name': 'HR Expense - Test Payable Account', 'user_type_id': self.env.ref('account.data_account_type_payable').id, 'reconcile': True}) employee = self.env['hr.employee'].create({'name': 'Test employee', 'user_id': self.user.id, 'address_home_id': self.user.partner_id.id}) - self.user.partner_id.property_account_payable_id = account_payable.id + self.user.partner_id.property_account_payable_id = self.a_pay.id # Submit to Manager sheet = self.env['hr.expense.sheet'].create({ 'name': 'Expense for John Smith', @@ -60,7 +72,16 @@ class TestSaleExpense(TestSale): # create some expense and validate it (expense at sale price) init_price = so.amount_total - prod_exp_2 = self.env.ref('hr_expense.car_travel') + prod_exp_2 = self.env['product.product'].create({ + 'name': 'Car Travel', + 'expense_policy': 'sales_price', + 'type': 'service', + 'can_be_expensed': True, + 'invoice_policy': 'delivery', + 'list_price': 0.50, + 'uom_id': self.env.ref('uom.product_uom_km').id, + 'uom_po_id': self.env.ref('uom.product_uom_km').id, + }) # Submit to Manager sheet = self.env['hr.expense.sheet'].create({ 'name': 'Expense for John Smith', diff --git a/addons/sale_management/tests/test_sale_ui.py b/addons/sale_management/tests/test_sale_ui.py index 1640e7fcace..911b2f06316 100644 --- a/addons/sale_management/tests/test_sale_ui.py +++ b/addons/sale_management/tests/test_sale_ui.py @@ -6,4 +6,4 @@ import odoo.tests class TestUi(odoo.tests.HttpCase): def test_01_sale_tour(self): - self.start_tour("/web", 'sale_tour', login="admin") + self.start_tour("/web", 'sale_tour', login="admin", step_delay=100) diff --git a/addons/sale_margin/tests/test_sale_margin.py b/addons/sale_margin/tests/test_sale_margin.py index a3aad9673f6..52a5e36baa2 100644 --- a/addons/sale_margin/tests/test_sale_margin.py +++ b/addons/sale_margin/tests/test_sale_margin.py @@ -12,9 +12,12 @@ class TestSaleMargin(common.TransactionCase): self.SaleOrder = self.env['sale.order'] self.product_uom_id = self.ref('uom.product_uom_unit') - self.product_id = self.ref('product.product_product_24') - self.partner_id = self.ref('base.res_partner_4') - self.partner_invoice_address_id = self.ref('base.res_partner_address_7') + self.product_id = self.env['product.product'].create({'name': 'Individual Workplace'}).id + self.partner_id = self.env['res.partner'].create({'name': 'A test partner'}).id + self.partner_invoice_address_id = self.env['res.partner'].create({ + 'name': 'A test partner address', + 'parent_id': self.partner_id, + }).id self.pricelist_id = self.ref('product.list0') def test_sale_margin(self): diff --git a/addons/sale_mrp/tests/test_multistep_manufacturing.py b/addons/sale_mrp/tests/test_multistep_manufacturing.py index 3a13b58de59..a33464de35f 100644 --- a/addons/sale_mrp/tests/test_multistep_manufacturing.py +++ b/addons/sale_mrp/tests/test_multistep_manufacturing.py @@ -49,7 +49,7 @@ class TestMultistepManufacturing(TestMrpCommon): # Create sale order sale_form = Form(self.env['sale.order']) - sale_form.partner_id = self.env.ref('base.res_partner_1') + sale_form.partner_id = self.env['res.partner'].create({'name': 'My Test Partner'}) sale_form.picking_policy = 'direct' sale_form.warehouse_id = self.warehouse with sale_form.order_line.new() as line: diff --git a/addons/sale_mrp/tests/test_sale_mrp_flow.py b/addons/sale_mrp/tests/test_sale_mrp_flow.py index 1e1b7101d17..18c7073dcf9 100644 --- a/addons/sale_mrp/tests/test_sale_mrp_flow.py +++ b/addons/sale_mrp/tests/test_sale_mrp_flow.py @@ -1,8 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from datetime import datetime - +from odoo.addons.account.tests.account_minimal_test import AccountMinimalTest from odoo.tests import common, Form from odoo.exceptions import UserError from odoo.tools import mute_logger, float_compare @@ -10,7 +9,7 @@ from odoo.tools import mute_logger, float_compare # these tests create accounting entries, and therefore need a chart of accounts @common.tagged('post_install', '-at_install') -class TestSaleMrpFlow(common.SavepointCase): +class TestSaleMrpFlow(AccountMinimalTest): @classmethod def setUpClass(cls): @@ -289,7 +288,7 @@ class TestSaleMrpFlow(common.SavepointCase): # ---------------------------------------- order_form = Form(self.env['sale.order']) - order_form.partner_id = self.env.ref('base.res_partner_2') + order_form.partner_id = self.env['res.partner'].create({'name': 'My Test Partner'}) with order_form.order_line.new() as line: line.product_id = product_a line.product_uom = self.uom_dozen @@ -503,13 +502,42 @@ class TestSaleMrpFlow(common.SavepointCase): def test_01_sale_mrp_delivery_kit(self): """ Test delivered quantity on SO based on delivered quantity in pickings.""" # intial so - product = self.env.ref('mrp.product_product_table_kit') - product.type = 'consu' - product.invoice_policy = 'delivery' + product = self.env['product.product'].create({ + 'name': 'Table Kit', + 'type': 'consu', + 'invoice_policy': 'delivery', + 'categ_id': self.env.ref('product.product_category_all').id, + }) # Remove the MTO route as purchase is not installed and since the procurement removal the exception is directly raised product.write({'route_ids': [(6, 0, [self.warehouse.manufacture_pull_id.route_id.id])]}) - partner = self.env.ref('base.res_partner_1') + product_wood_panel = self.env['product.product'].create({ + 'name': 'Wood Panel', + 'type': 'product', + }) + product_desk_bolt = self.env['product.product'].create({ + 'name': 'Bolt', + 'type': 'product', + }) + self.env['mrp.bom'].create({ + 'product_tmpl_id': product.product_tmpl_id.id, + 'product_uom_id': self.env.ref('uom.product_uom_unit').id, + 'sequence': 2, + 'type': 'phantom', + 'bom_line_ids': [ + (0, 0, { + 'product_id': product_wood_panel.id, + 'product_qty': 1, + 'product_uom_id': self.env.ref('uom.product_uom_unit').id, + }), (0, 0, { + 'product_id': product_desk_bolt.id, + 'product_qty': 4, + 'product_uom_id': self.env.ref('uom.product_uom_unit').id, + }) + ] + }) + + partner = self.env['res.partner'].create({'name': 'My Test Partner'}) # if `delivery` module is installed, a default property is set for the carrier to use # However this will lead to an extra line on the SO (the delivery line), which will force # the SO to have a different flow (and `invoice_state` value) @@ -544,7 +572,7 @@ class TestSaleMrpFlow(common.SavepointCase): self.assertEqual(len(so.picking_ids), 2, 'Sale MRP: number of pickings should be 2') pick_2 = so.picking_ids.filtered('backorder_id') for move in pick_2.move_lines: - if move.product_id.id == self.env.ref('mrp.product_product_computer_desk_bolt').id: + if move.product_id.id == product_desk_bolt.id: move.write({'quantity_done': 19}) else: move.write({'quantity_done': 4}) @@ -572,7 +600,7 @@ class TestSaleMrpFlow(common.SavepointCase): 'rounding': 1.0}) self.company = self.env.ref('base.main_company') self.company.anglo_saxon_accounting = True - self.partner = self.env.ref('base.res_partner_1') + self.partner = self.env['res.partner'].create({'name': 'My Test Partner'}) self.category = self.env.ref('product.product_category_1').copy({'name': 'Test category','property_valuation': 'real_time', 'property_cost_method': 'fifo'}) account_type = self.env['account.account.type'].create({'name': 'RCV type', 'type': 'other', 'internal_group': 'asset'}) self.account_receiv = self.env['account.account'].create({'name': 'Receivable', 'code': 'RCV00' , 'user_type_id': account_type.id, 'reconcile': True}) @@ -691,7 +719,7 @@ class TestSaleMrpFlow(common.SavepointCase): self.env['stock.quant']._update_available_quantity(self.component_c, stock_location, 30) # Creation of a sale order for x10 kit_1 - partner = self.env.ref('base.res_partner_1') + partner = self.env['res.partner'].create({'name': 'My Test Partner'}) f = Form(self.env['sale.order']) f.partner_id = partner with f.order_line.new() as line: @@ -815,7 +843,7 @@ class TestSaleMrpFlow(common.SavepointCase): self.env['stock.quant']._update_available_quantity(self.component_g, stock_location, 28) # Creation of a sale order for x7 kit_parent - partner = self.env.ref('base.res_partner_1') + partner = self.env['res.partner'].create({'name': 'My Test Partner'}) f = Form(self.env['sale.order']) f.partner_id = partner with f.order_line.new() as line: @@ -1037,7 +1065,7 @@ class TestSaleMrpFlow(common.SavepointCase): # Creation of a sale order for x7 kit_parent qty_ordered = 7 f = Form(self.env['sale.order']) - f.partner_id = self.env.ref('base.res_partner_1') + f.partner_id = self.env['res.partner'].create({'name': 'My Test Partner'}) f.warehouse_id = warehouse_2 with f.order_line.new() as line: line.product_id = self.kit_parent @@ -1147,7 +1175,7 @@ class TestSaleMrpFlow(common.SavepointCase): self.env['stock.quant']._update_available_quantity(component_uom_kg, stock_location, 0.03) # Creation of a sale order for x10 kit_1 - partner = self.env.ref('base.res_partner_1') + partner = self.env['res.partner'].create({'name': 'My Test Partner'}) f = Form(self.env['sale.order']) f.partner_id = partner with f.order_line.new() as line: @@ -1277,7 +1305,7 @@ class TestSaleMrpFlow(common.SavepointCase): # Creation of a sale order for x5 kit_uom_in_kit qty_ordered = 5 f = Form(self.env['sale.order']) - f.partner_id = self.env.ref('base.res_partner_1') + f.partner_id = self.env['res.partner'].create({'name': 'My Test Partner'}) f.warehouse_id = warehouse_1 with f.order_line.new() as line: line.product_id = kit_uom_in_kit @@ -1326,6 +1354,15 @@ class TestSaleMrpFlow(common.SavepointCase): # kit_1 --|- component_shelf1 x3 # |- component_shelf2 x2 + stock_location_components = self.env['stock.location'].create({ + 'name': 'Shelf 1', + 'location_id': self.env.ref('stock.warehouse0').lot_stock_id.id, + }) + stock_location_14 = self.env['stock.location'].create({ + 'name': 'Shelf 2', + 'location_id': self.env.ref('stock.warehouse0').lot_stock_id.id, + }) + kit_1 = self._create_product('Kit1', self.uom_unit) component_shelf1 = self._create_product('Comp Shelf1', self.uom_unit) component_shelf2 = self._create_product('Comp Shelf2', self.uom_unit) @@ -1352,7 +1389,7 @@ class TestSaleMrpFlow(common.SavepointCase): 'name': 'Shelf1 -> Customer', 'action': 'pull', 'picking_type_id': self.ref('stock.picking_type_in'), - 'location_src_id': self.ref('stock.stock_location_components'), + 'location_src_id': stock_location_components.id, 'location_id': self.ref('stock.stock_location_customers'), })], }) @@ -1364,7 +1401,7 @@ class TestSaleMrpFlow(common.SavepointCase): 'name': 'Shelf2 -> Customer', 'action': 'pull', 'picking_type_id': self.ref('stock.picking_type_in'), - 'location_src_id': self.ref('stock.stock_location_14'), + 'location_src_id': stock_location_14.id, 'location_id': self.ref('stock.stock_location_customers'), })], }) @@ -1380,7 +1417,7 @@ class TestSaleMrpFlow(common.SavepointCase): # Creating a sale order for 5 kits and confirming it order_form = Form(self.env['sale.order']) - order_form.partner_id = self.env.ref('base.res_partner_2') + order_form.partner_id = self.env['res.partner'].create({'name': 'My Test Partner'}) with order_form.order_line.new() as line: line.product_id = kit_1 line.product_uom = self.uom_unit @@ -1396,9 +1433,9 @@ class TestSaleMrpFlow(common.SavepointCase): moves = order.picking_ids.mapped('move_lines') move_shelf1 = moves.filtered(lambda m: m.product_id == component_shelf1) move_shelf2 = moves.filtered(lambda m: m.product_id == component_shelf2) - self.assertEqual(move_shelf1.location_id.id, self.ref('stock.stock_location_components')) + self.assertEqual(move_shelf1.location_id.id, stock_location_components.id) self.assertEqual(move_shelf1.location_dest_id.id, self.ref('stock.stock_location_customers')) - self.assertEqual(move_shelf2.location_id.id, self.ref('stock.stock_location_14')) + self.assertEqual(move_shelf2.location_id.id, stock_location_14.id) self.assertEqual(move_shelf2.location_dest_id.id, self.ref('stock.stock_location_customers')) def test_11_sale_mrp_explode_kits_uom_quantities(self): @@ -1438,7 +1475,7 @@ class TestSaleMrpFlow(common.SavepointCase): # Creating a sale order for 3 Units of kit_1 and confirming it order_form = Form(self.env['sale.order']) - order_form.partner_id = self.env.ref('base.res_partner_2') + order_form.partner_id = self.env['res.partner'].create({'name': 'My Test Partner'}) order_form.warehouse_id = warehouse_1 with order_form.order_line.new() as line: line.product_id = kit_1 @@ -1488,7 +1525,7 @@ class TestSaleMrpFlow(common.SavepointCase): # Create sale order sale_form = Form(self.env['sale.order']) - sale_form.partner_id = self.env.ref('base.res_partner_1') + sale_form.partner_id = self.env['res.partner'].create({'name': 'My Test Partner'}) with sale_form.order_line.new() as line: line.name = finished_product.name line.product_id = finished_product diff --git a/addons/sale_mrp/tests/test_sale_mrp_procurement.py b/addons/sale_mrp/tests/test_sale_mrp_procurement.py index e9c7a52ae62..8c411bfb55f 100644 --- a/addons/sale_mrp/tests/test_sale_mrp_procurement.py +++ b/addons/sale_mrp/tests/test_sale_mrp_procurement.py @@ -55,7 +55,7 @@ class TestSaleMrpProcurement(TransactionCase): # I create a sale order for product Slider mobile so_form = Form(self.env['sale.order']) - so_form.partner_id = self.env.ref('base.res_partner_4') + so_form.partner_id = self.env['res.partner'].create({'name': 'Another Test Partner'}) with so_form.order_line.new() as line: line.product_id = product_template_slidermobile0.product_variant_ids line.price_unit = 200 @@ -150,7 +150,7 @@ class TestSaleMrpProcurement(TransactionCase): warehouse.manufacture_steps = 'pbm_sam' so_form = Form(self.env['sale.order']) - so_form.partner_id = self.env.ref('base.res_partner_4') + so_form.partner_id = self.env['res.partner'].create({'name': 'Another Test Partner'}) with so_form.order_line.new() as line: line.product_id = self.complex_product line.price_unit = 1 diff --git a/addons/sale_product_configurator/static/tests/tours/product_configurator_advanced_ui.js b/addons/sale_product_configurator/static/tests/tours/product_configurator_advanced_ui.js index 891a1742d90..0f351b8be5e 100644 --- a/addons/sale_product_configurator/static/tests/tours/product_configurator_advanced_ui.js +++ b/addons/sale_product_configurator/static/tests/tours/product_configurator_advanced_ui.js @@ -9,7 +9,7 @@ tour.register('sale_product_configurator_advanced_tour', { url: "/web", test: true, }, [tour.STEPS.SHOW_APPS_MENU_ITEM, { - trigger: '.o_app[data-menu-xmlid="sale.sale_menu_root"]', + trigger: '.o_app[data-menu-xmlid="sale.sale_menu_root"]', // Note: The module sale_management is mandatory edition: 'community' }, { trigger: '.o_app[data-menu-xmlid="sale.sale_menu_root"]', @@ -37,7 +37,7 @@ tour.register('sale_product_configurator_advanced_tour', { $input.trigger(keyDownEvent); } }, { - trigger: 'ul.ui-autocomplete a:contains("Customizable Desk")', + trigger: 'ul.ui-autocomplete a:contains("Customizable Desk (TEST)")', run: 'click' }, { trigger: 'span:contains("Custom")', @@ -103,14 +103,14 @@ tour.register('sale_product_configurator_advanced_tour', { extra_trigger: '.oe_optional_products_modal', run: function () {} //check }, { - trigger: '.oe_optional_products_modal .js_product:eq(1) div:contains("Conference Chair (CONFIG) (Steel)")', + trigger: '.oe_optional_products_modal .js_product:eq(1) div:contains("Conference Chair (TEST) (Steel)")', run: function () { optionVariantImage = $('.oe_optional_products_modal .js_product:eq(1) img.variant_image').attr('src'); } }, { trigger: '.oe_optional_products_modal .js_product:eq(1) input[data-value_name="Aluminium"]', }, { - trigger: '.oe_optional_products_modal .js_product:eq(1) div:contains("Conference Chair (CONFIG) (Aluminium)")', + trigger: '.oe_optional_products_modal .js_product:eq(1) div:contains("Conference Chair (TEST) (Aluminium)")', run: function () { var newVariantImage = $('.oe_optional_products_modal .js_product:eq(1) img.variant_image').attr('src'); if (newVariantImage !== optionVariantImage) { @@ -126,7 +126,7 @@ tour.register('sale_product_configurator_advanced_tour', { extra_trigger: '.oe_optional_products_modal', run: 'click' }, { - trigger: 'td.o_data_cell:contains("Customizable Desk (CONFIG) (Custom, White, PAV9, PAV5, PAV1)")', + trigger: 'td.o_data_cell:contains("Customizable Desk (TEST) (Custom, White, PAV9, PAV5, PAV1)")', extra_trigger: 'div[name="order_line"]', in_modal: false, run: function (){} //check diff --git a/addons/sale_product_configurator/static/tests/tours/product_configurator_edition_ui.js b/addons/sale_product_configurator/static/tests/tours/product_configurator_edition_ui.js index d5de6358294..907cc86382a 100644 --- a/addons/sale_product_configurator/static/tests/tours/product_configurator_edition_ui.js +++ b/addons/sale_product_configurator/static/tests/tours/product_configurator_edition_ui.js @@ -28,7 +28,7 @@ tour.register('sale_product_configurator_edition_tour', { $input.trigger(keyDownEvent); } }, { - trigger: 'ul.ui-autocomplete a:contains("Customizable Desk")', + trigger: 'ul.ui-autocomplete a:contains("Customizable Desk (TEST)")', run: 'click' }, { trigger: '.configurator_container span:contains("Steel")', @@ -49,7 +49,7 @@ tour.register('sale_product_configurator_edition_tour', { extra_trigger: '.oe_optional_products_modal', run: 'click' }, { - trigger: 'td.o_data_cell:contains("Customizable Desk (CONFIG) (Aluminium, White)")', + trigger: 'td.o_data_cell:contains("Customizable Desk (TEST) (Aluminium, White)")', extra_trigger: 'div[name="order_line"]', run: function (){} // check added product }, { @@ -94,7 +94,7 @@ tour.register('sale_product_configurator_edition_tour', { }, { trigger: '.o_sale_product_configurator_edit', }, { - trigger: 'td.o_data_cell:contains("Customizable Desk (CONFIG) (Custom, Black)")', + trigger: 'td.o_data_cell:contains("Customizable Desk (TEST) (Custom, Black)")', extra_trigger: 'div[name="order_line"]', run: function (){} // check updated product }, { @@ -148,7 +148,7 @@ tour.register('sale_product_configurator_edition_tour', { run: function () { // used to check that the description does not contain a custom value anymore if ($('td.o_data_cell:contains("Custom: another nice custom value")').length === 0){ - $('td.o_data_cell:contains("Customizable Desk (CONFIG) (Steel, Black)")').html('tour success'); + $('td.o_data_cell:contains("Customizable Desk (TEST) (Steel, Black)")').html('tour success'); } } }, { diff --git a/addons/sale_product_configurator/static/tests/tours/product_configurator_optional_products_ui.js b/addons/sale_product_configurator/static/tests/tours/product_configurator_optional_products_ui.js index c3ccafaf427..c68fc9debec 100644 --- a/addons/sale_product_configurator/static/tests/tours/product_configurator_optional_products_ui.js +++ b/addons/sale_product_configurator/static/tests/tours/product_configurator_optional_products_ui.js @@ -28,7 +28,7 @@ tour.register('sale_product_configurator_optional_products_tour', { $input.trigger(keyDownEvent); } }, { - trigger: 'ul.ui-autocomplete a:contains("Customizable Desk")', + trigger: 'ul.ui-autocomplete a:contains("Customizable Desk (TEST)")', run: 'click' }, { trigger: '.o_sale_product_configurator_add' diff --git a/addons/sale_product_configurator/static/tests/tours/product_configurator_pricelist_ui.js b/addons/sale_product_configurator/static/tests/tours/product_configurator_pricelist_ui.js index 4e38e5ce5fa..ff761c0b540 100644 --- a/addons/sale_product_configurator/static/tests/tours/product_configurator_pricelist_ui.js +++ b/addons/sale_product_configurator/static/tests/tours/product_configurator_pricelist_ui.js @@ -48,7 +48,7 @@ tour.STEPS.SHOW_APPS_MENU_ITEM, $input.trigger(keyDownEvent); } }, { - trigger: 'ul.ui-autocomplete a:contains("Customizable Desk")', + trigger: 'ul.ui-autocomplete a:contains("Customizable Desk (TEST)")', run: 'click' }, { content: "check price is correct (USD)", @@ -66,7 +66,7 @@ tour.STEPS.SHOW_APPS_MENU_ITEM, trigger: '.o_sale_product_configurator_add:not(.disabled)' }, { content: "check we are on the add modal", - trigger: '.td-product_name:contains("Customizable Desk (CONFIG) (Steel, White)")', + trigger: '.td-product_name:contains("Customizable Desk (TEST) (Steel, White)")', extra_trigger: '.oe_optional_products_modal', run: 'click' }, { diff --git a/addons/sale_product_configurator/static/tests/tours/product_configurator_single_custom_attribute_ui.js b/addons/sale_product_configurator/static/tests/tours/product_configurator_single_custom_attribute_ui.js index 9c145ce0c71..4c1b68da988 100644 --- a/addons/sale_product_configurator/static/tests/tours/product_configurator_single_custom_attribute_ui.js +++ b/addons/sale_product_configurator/static/tests/tours/product_configurator_single_custom_attribute_ui.js @@ -29,7 +29,7 @@ tour.register('sale_product_configurator_single_custom_attribute_tour', { $input.trigger(keyDownEvent); } }, { - trigger: 'ul.ui-autocomplete a:contains("Customizable Desk")', + trigger: 'ul.ui-autocomplete a:contains("Customizable Desk (TEST)")', run: 'click' }, { trigger: '.configurator_container span:contains("Aluminium")', diff --git a/addons/sale_product_configurator/static/tests/tours/product_configurator_ui.js b/addons/sale_product_configurator/static/tests/tours/product_configurator_ui.js index 6de323a10f3..d1857944ae7 100644 --- a/addons/sale_product_configurator/static/tests/tours/product_configurator_ui.js +++ b/addons/sale_product_configurator/static/tests/tours/product_configurator_ui.js @@ -32,7 +32,7 @@ tour.register('sale_product_configurator_tour', { $input.trigger(keyDownEvent); } }, { - trigger: 'ul.ui-autocomplete a:contains("Customizable Desk")', + trigger: 'ul.ui-autocomplete a:contains("Customizable Desk (TEST)")', run: 'click' }, { trigger: '.configurator_container span:contains("Steel")', @@ -71,12 +71,12 @@ tour.register('sale_product_configurator_tour', { }, // check that 3 products were added to the SO { - trigger: 'td.o_data_cell:contains("Customizable Desk (CONFIG) (Aluminium, White)")', + trigger: 'td.o_data_cell:contains("Customizable Desk (TEST) (Aluminium, White)")', extra_trigger: 'div[name="order_line"]', in_modal: false, run: function (){} }, { - trigger: 'td.o_data_cell:contains("Conference Chair (CONFIG) (Aluminium)")', + trigger: 'td.o_data_cell:contains("Conference Chair (TEST) (Aluminium)")', extra_trigger: 'div[name="order_line"]', in_modal: false, run: function (){} diff --git a/addons/sale_product_configurator/tests/test_sale_product_configurator_ui.py b/addons/sale_product_configurator/tests/test_sale_product_configurator_ui.py index 6e63bcebbb1..3b962f52d87 100644 --- a/addons/sale_product_configurator/tests/test_sale_product_configurator_ui.py +++ b/addons/sale_product_configurator/tests/test_sale_product_configurator_ui.py @@ -1,11 +1,107 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +import base64 + import odoo.tests +from odoo.modules.module import get_module_resource @odoo.tests.tagged('post_install', '-at_install') class TestUi(odoo.tests.HttpCase): + + def setUp(self): + super(TestUi, self).setUp() + + # Setup attributes and attributes values + self.product_attribute_1 = self.env['product.attribute'].create({ + 'name': 'Legs', + 'sequence': 10, + }) + product_attribute_value_1 = self.env['product.attribute.value'].create({ + 'name': 'Steel', + 'attribute_id': self.product_attribute_1.id, + 'sequence': 1, + }) + product_attribute_value_2 = self.env['product.attribute.value'].create({ + 'name': 'Aluminium', + 'attribute_id': self.product_attribute_1.id, + 'sequence': 2, + }) + product_attribute_2 = self.env['product.attribute'].create({ + 'name': 'Color', + 'sequence': 20, + }) + product_attribute_value_3 = self.env['product.attribute.value'].create({ + 'name': 'White', + 'attribute_id': product_attribute_2.id, + 'sequence': 1, + }) + product_attribute_value_4 = self.env['product.attribute.value'].create({ + 'name': 'Black', + 'attribute_id': product_attribute_2.id, + 'sequence': 2, + }) + + # Create product template + self.product_product_4_product_template = self.env['product.template'].create({ + 'name': 'Customizable Desk (TEST)', + 'standard_price': 500.0, + 'list_price': 750.0, + }) + + # Generate variants + self.env['product.template.attribute.line'].create([{ + 'product_tmpl_id': self.product_product_4_product_template.id, + 'attribute_id': self.product_attribute_1.id, + 'value_ids': [(4, product_attribute_value_1.id), (4, product_attribute_value_2.id)], + }, { + 'product_tmpl_id': self.product_product_4_product_template.id, + 'attribute_id': product_attribute_2.id, + 'value_ids': [(4, product_attribute_value_3.id), (4, product_attribute_value_4.id)], + + }]) + + # Apply a price_extra for the attribute Aluminium + self.product_product_4_product_template.attribute_line_ids[0].product_template_value_ids[1].price_extra = 50.40 + + + # Add a Custom attribute + product_attribute_value_7 = self.env['product.attribute.value'].create({ + 'name': 'Custom', + 'attribute_id': self.product_attribute_1.id, + 'sequence': 3, + 'is_custom': True + }) + self.product_product_4_product_template.attribute_line_ids[0].write({'value_ids': [(4, product_attribute_value_7.id)]}) + + # Disable the aluminium + black product + self.product_product_4_product_template.product_variant_ids[3].active = False + + # Setup a first optional product + img_path = get_module_resource('product', 'static', 'img', 'product_product_11-image.png') + img_content = base64.b64encode(open(img_path, "rb").read()) + self.product_product_11_product_template = self.env['product.template'].create({ + 'name': 'Conference Chair (TEST)', + 'image_1920': img_content, + 'list_price': 16.50, + }) + + self.env['product.template.attribute.line'].create({ + 'product_tmpl_id': self.product_product_11_product_template.id, + 'attribute_id': self.product_attribute_1.id, + 'value_ids': [(4, product_attribute_value_1.id), (4, product_attribute_value_2.id)], + }) + self.product_product_4_product_template.optional_product_ids = [(4, self.product_product_11_product_template.id)] + + # Setup a second optional product + self.product_product_1_product_template = self.env['product.template'].create({ + 'name': 'Chair floor protection', + 'list_price': 12.0, + }) + self.product_product_11_product_template.optional_product_ids = [(4, self.product_product_1_product_template.id)] + + def test_01_product_configurator(self): # To be able to test the product configurator, admin user must have access to "variants" feature, so we give him the right group for that self.env.ref('base.user_admin').write({'groups_id': [(4, self.env.ref('product.group_product_variant').id)]}) @@ -63,7 +159,7 @@ class TestUi(odoo.tests.HttpCase): 'attribute_id': product_attribute.id } for i in range(1, 11) for product_attribute in product_attributes]) - product_template = self.env.ref("product.product_product_4_product_template") + product_template = self.product_product_4_product_template self.env['product.template.attribute.line'].create([{ 'attribute_id': product_attribute.id, @@ -104,7 +200,7 @@ class TestUi(odoo.tests.HttpCase): 'attribute_id': product_attributes[0].id }]) - product_template = self.env.ref("product.product_product_4_product_template") + product_template = self.product_product_4_product_template self.env['product.template.attribute.line'].create([{ 'attribute_id': product_attributes[0].id, @@ -131,14 +227,14 @@ class TestUi(odoo.tests.HttpCase): # Add a 15% tax on desk tax = self.env['account.tax'].create({'name': "Test tax", 'amount': 15}) - self.env.ref('product.product_product_4_product_template').taxes_id = tax + self.product_product_4_product_template.taxes_id = tax # Remove tax from Conference Chair and Chair floor protection - self.env.ref('sale_product_configurator.product_product_1_product_template').taxes_id = None - self.env.ref('product.product_product_11_product_template').taxes_id = None + self.product_product_1_product_template.taxes_id = None + self.product_product_11_product_template.taxes_id = None # Make sure pricelist rule exist - product_template = self.env.ref('product.product_product_4_product_template') + product_template = self.product_product_4_product_template pricelist = self.env.ref('product.list0') if not pricelist.item_ids.filtered(lambda i: i.product_tmpl_id == product_template and i.applied_on == '1_product' and i.price_discount == 20): @@ -161,12 +257,15 @@ class TestUi(odoo.tests.HttpCase): """ # add an optional product to the office chair and the custo desk for testing purposes - office_chair = self.env.ref('product.product_product_12') - custo_desk = self.env.ref('product.product_product_4') + office_chair = self.env['product.product'].create({ + 'name': 'Office Chair Black', + }) + + custo_desk = self.product_product_4_product_template.product_variant_ids[0] office_chair.update({ - 'optional_product_ids': [(6, 0, [self.env.ref('sale_product_configurator.product_product_1_product_template').id])] + 'optional_product_ids': [(6, 0, [self.product_product_1_product_template.id])] }) custo_desk.update({ - 'optional_product_ids': [(6, 0, [self.env.ref('product.product_product_12_product_template').id, self.env.ref('product.product_product_11_product_template').id])] + 'optional_product_ids': [(6, 0, [office_chair.product_tmpl_id.id, self.product_product_11_product_template.id])] }) self.start_tour("/web", 'sale_product_configurator_optional_products_tour', login="admin") diff --git a/addons/sale_stock/tests/__init__.py b/addons/sale_stock/tests/__init__.py index 017499f740f..43ad813d2c3 100644 --- a/addons/sale_stock/tests/__init__.py +++ b/addons/sale_stock/tests/__init__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. + from . import test_anglo_saxon_valuation from . import test_anglo_saxon_valuation_reconciliation from . import test_sale_stock diff --git a/addons/sale_stock/tests/test_anglo_saxon_valuation_reconciliation.py b/addons/sale_stock/tests/test_anglo_saxon_valuation_reconciliation.py index 381d0bde32b..372cb0c72b1 100644 --- a/addons/sale_stock/tests/test_anglo_saxon_valuation_reconciliation.py +++ b/addons/sale_stock/tests/test_anglo_saxon_valuation_reconciliation.py @@ -13,14 +13,14 @@ class TestValuationReconciliation(ValuationReconciliationTestCase): def setUp(self): super(TestValuationReconciliation, self).setUp() self.account_receivable = self.env['account.account'].create({ - 'code': 'X1111', + 'code': 'X1111 - Test Sale Stock', 'name': 'Sale - Test Receivable Account', 'user_type_id': self.env.ref('account.data_account_type_receivable').id, 'reconcile': True }) self.account_income = self.env['account.account'].create({ - 'code': 'X1112', + 'code': 'X1112 - Test Sale Stock', 'name': 'Sale - Test Account', 'user_type_id': self.env.ref('account.data_account_type_direct_costs').id }) diff --git a/addons/sale_stock/tests/test_sale_order_dates.py b/addons/sale_stock/tests/test_sale_order_dates.py index fd826fc877e..55d4f991a20 100644 --- a/addons/sale_stock/tests/test_sale_order_dates.py +++ b/addons/sale_stock/tests/test_sale_order_dates.py @@ -36,7 +36,7 @@ class TestSaleExpectedDate(common.TransactionCase): self.env['stock.quant']._update_available_quantity(product_B, self.env.ref('stock.stock_location_stock'), 10) self.env['stock.quant']._update_available_quantity(product_C, self.env.ref('stock.stock_location_stock'), 10) sale_order = self.env['sale.order'].create({ - 'partner_id': self.ref('base.res_partner_3'), + 'partner_id': self.env['res.partner'].create({'name': 'A Customer'}).id, 'picking_policy': 'direct', 'order_line': [ (0, 0, {'name': product_A.name, 'product_id': product_A.id, 'customer_lead': product_A.sale_delay, 'product_uom_qty': 5}), @@ -90,7 +90,19 @@ class TestSaleExpectedDate(common.TransactionCase): # In order to test the Commitment Date feature in Sales Orders in Odoo, # I copy a demo Sales Order with committed Date on 2010-07-12 - new_order = self.env.ref('sale.sale_order_6').copy({'commitment_date': '2010-07-12'}) + new_order = self.env['sale.order'].create({ + 'partner_id': self.env['res.partner'].create({'name': 'A Partner'}).id, + 'order_line': [(0, 0, { + 'name': "A product", + 'product_id': self.env['product.product'].create({ + 'name': 'A product', + 'type': 'product', + }).id, + 'product_uom_qty': 1, + 'price_unit': 750, + })], + 'commitment_date': '2010-07-12', + }) # I confirm the Sales Order. new_order.action_confirm() # I verify that the Procurements and Stock Moves have been generated with the correct date diff --git a/addons/sale_stock/tests/test_sale_stock.py b/addons/sale_stock/tests/test_sale_stock.py index a21b60951a9..6d5eaf6c753 100644 --- a/addons/sale_stock/tests/test_sale_stock.py +++ b/addons/sale_stock/tests/test_sale_stock.py @@ -9,13 +9,14 @@ from odoo.tests import Form, tagged @tagged('post_install', '-at_install') class TestSaleStock(TestSale): + def _get_new_sale_order(self, amount=10.0): """ Creates and returns a sale order with one default order line. :param float amount: quantity of product for the order line (10 by default) """ - partner = self.env.ref('base.res_partner_1') - product = self.env.ref('product.product_delivery_01') + partner = self.partner + product = self.products['prod_del'] sale_order_vals = { 'partner_id': partner.id, 'partner_invoice_id': partner.id, @@ -121,10 +122,15 @@ class TestSaleStock(TestSale): self.assertFalse(self.so.order_line.sorted()[0].product_updatable) self.assertTrue(self.so.picking_ids, 'Sale Stock: no picking created for "invoice on order" storable products') # let's do an invoice for a deposit of 5% + + advance_product = self.env['product.product'].create({ + 'name': 'Deposit', + 'type': 'service', + }) adv_wiz = self.env['sale.advance.payment.inv'].with_context(active_ids=[self.so.id]).create({ 'advance_payment_method': 'percentage', 'amount': 5.0, - 'product_id': self.env.ref('sale.advance_product_0').id, + 'product_id': advance_product.id, }) act = adv_wiz.with_context(open_invoices=True).create_invoices() inv = self.env['account.move'].browse(act['res_id']) @@ -151,8 +157,7 @@ class TestSaleStock(TestSale): of the picking. Check that a refund invoice is well generated. """ # intial so - self.partner = self.env.ref('base.res_partner_1') - self.product = self.env.ref('product.product_delivery_01') + self.product = self.products['prod_del'] so_vals = { 'partner_id': self.partner.id, 'partner_invoice_id': self.partner.id, @@ -223,8 +228,7 @@ class TestSaleStock(TestSale): the SO is set on 'done', the SO should be fully invoiced. """ # intial so - self.partner = self.env.ref('base.res_partner_1') - self.product = self.env.ref('product.product_delivery_01') + self.product = self.products['prod_del'] so_vals = { 'partner_id': self.partner.id, 'partner_invoice_id': self.partner.id, @@ -276,6 +280,7 @@ class TestSaleStock(TestSale): item1 = self.products['prod_order'] # consumable item1.type = 'consu' item2 = self.products['prod_del'] # storable + item2.type = 'product' # storable self.so = self.env['sale.order'].create({ 'partner_id': self.partner.id, @@ -342,7 +347,9 @@ class TestSaleStock(TestSale): """ # sell two products item1 = self.products['prod_order'] # consumable + item1.type = 'consu' # consumable item2 = self.products['prod_del'] # storable + item2.type = 'product' # storable self.env['stock.quant']._update_available_quantity(item2, self.env.ref('stock.stock_location_stock'), 2) self.so = self.env['sale.order'].create({ @@ -378,7 +385,7 @@ class TestSaleStock(TestSale): """ item1 = self.products['prod_order'] partner1 = self.partner.id - partner2 = self.env.ref('base.res_partner_2').id + partner2 = self.env['res.partner'].create({'name': 'Another Test Partner'}) so1 = self.env['sale.order'].create({ 'partner_id': partner1, 'order_line': [(0, 0, { @@ -399,7 +406,7 @@ class TestSaleStock(TestSale): so1.action_confirm() self.assertEqual(len(so1.picking_ids), 2) picking2 = so1.picking_ids.filtered(lambda p: p.state != 'cancel') - self.assertEqual(picking2.partner_id.id, partner2) + self.assertEqual(picking2.partner_id.id, partner2.id) def test_06_uom(self): """ Sell a dozen of products stocked in units. Check that the quantities on the sale order @@ -628,6 +635,7 @@ class TestSaleStock(TestSale): self.env['stock.quant']._update_reserved_quantity(item1, warehouse1.lot_stock_id, 3) warehouse2 = self.env['stock.warehouse'].create({ 'partner_id': self.env.ref('base.main_partner').id, + 'name': 'Zizizatestwarehouse', 'code': 'Test', }) self.env['stock.quant']._update_available_quantity(item1, warehouse2.lot_stock_id, 5) diff --git a/addons/sale_stock/tests/test_sale_stock_lead_time.py b/addons/sale_stock/tests/test_sale_stock_lead_time.py index fbf6080059d..253e2309d3b 100644 --- a/addons/sale_stock/tests/test_sale_stock_lead_time.py +++ b/addons/sale_stock/tests/test_sale_stock_lead_time.py @@ -9,12 +9,12 @@ from odoo.addons.stock.tests.common2 import TestStockCommon class TestSaleStockLeadTime(TestStockCommon): - def setUp(self): - super(TestSaleStockLeadTime, self).setUp() + @classmethod + def setUpClass(cls): + super(TestSaleStockLeadTime, cls).setUpClass() # Update the product_1 with type and Customer Lead Time - self.product_1.write({'type': 'product', - 'sale_delay': 5.0}) + cls.product_1.write({'type': 'product', 'sale_delay': 5.0}) def test_00_product_company_level_delays(self): """ In order to check schedule date, set product's Customer Lead Time diff --git a/addons/stock/tests/test_warehouse.py b/addons/stock/tests/test_warehouse.py index 859fe6de94d..f5ffd7b1907 100644 --- a/addons/stock/tests/test_warehouse.py +++ b/addons/stock/tests/test_warehouse.py @@ -452,6 +452,17 @@ class TestWarehouse(TestStockCommon): def test_noleak(self): # non-regression test to avoid company_id leaking to other warehouses (see blame) + partner = self.env['res.partner'].create({'name': 'Chicago partner'}) + company = self.env['res.company'].create({ + 'name': 'My Company (Chicago)1', + 'currency_id': self.ref('base.USD') + }) + self.env['stock.warehouse'].create({ + 'name': 'Chicago Warehouse2', + 'company_id': company.id, + 'code': 'Chic2', + 'partner_id': partner.id + }) wh = self.env["stock.warehouse"].search([]) assert len(set(wh.mapped("company_id.id"))) > 1 diff --git a/addons/stock_account/test/stock_valuation_account.xml b/addons/stock_account/test/stock_valuation_account.xml deleted file mode 100644 index 40e61a96be1..00000000000 --- a/addons/stock_account/test/stock_valuation_account.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - property_stock_valuation_account_id - - - - - - property_stock_valuation_journal - - - - - - - diff --git a/addons/stock_account/tests/stock_account_minimal_test.py b/addons/stock_account/tests/stock_account_minimal_test.py new file mode 100644 index 00000000000..a93d6f14c14 --- /dev/null +++ b/addons/stock_account/tests/stock_account_minimal_test.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.addons.account.tests.account_test_classes import AccountingTestCase + + +class StockAccountMinimalTest(AccountingTestCase): + + @classmethod + def setUpClass(cls): + super(StockAccountMinimalTest, cls).setUpClass() + + # Properties: Stock valuation account and journal + cls.env['ir.property'].create([{ + 'name': 'property_stock_valuation_account_id', + 'fields_id': cls.env['ir.model.fields'].search([('model', '=', 'product.category'), ('name', '=', 'property_stock_valuation_account_id')], limit=1).id, + 'value': 'account.account,%s' % (cls.stk.id), + 'company_id': cls.env.company.id, + }, { + 'name': 'property_stock_valuation_journal', + 'fields_id': cls.env['ir.model.fields'].search([('model', '=', 'product.category'), ('name', '=', 'property_stock_journal')], limit=1).id, + 'value': 'account.journal,%s' % (cls.miscellaneous_journal.id), + 'company_id': cls.env.company.id, + }]) diff --git a/addons/stock_account/tests/test_anglo_saxon_valuation_reconciliation_common.py b/addons/stock_account/tests/test_anglo_saxon_valuation_reconciliation_common.py index 568b8299599..3fbe09aa9d6 100644 --- a/addons/stock_account/tests/test_anglo_saxon_valuation_reconciliation_common.py +++ b/addons/stock_account/tests/test_anglo_saxon_valuation_reconciliation_common.py @@ -2,10 +2,10 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.addons.account.tests.account_test_classes import AccountingTestCase +from odoo.addons.stock_account.tests.stock_account_minimal_test import StockAccountMinimalTest from odoo import fields -class ValuationReconciliationTestCase(AccountingTestCase): +class ValuationReconciliationTestCase(StockAccountMinimalTest): """ Base class for tests checking interim accounts reconciliation works in anglosaxon accounting. It sets up everything we need in the tests, and is extended in both sale_stock and purchase modules to run the 'true' tests. @@ -139,4 +139,6 @@ class ValuationReconciliationTestCase(AccountingTestCase): # entries get automatically reconciled (and you cannot modify a reconciled entry). # So, we have to make sure that "today"'s rate will always be the last rate we # created in order to ensure complete control of the test. - self.env.ref('base.rateUSDbis').unlink() + rateUSDbis = self.env.ref('base.rateUSDbis', raise_if_not_found=False) + if rateUSDbis: + rateUSDbis.unlink() diff --git a/addons/stock_dropshipping/tests/test_crossdock.py b/addons/stock_dropshipping/tests/test_crossdock.py index dad75786bca..671d3098c6a 100644 --- a/addons/stock_dropshipping/tests/test_crossdock.py +++ b/addons/stock_dropshipping/tests/test_crossdock.py @@ -40,7 +40,7 @@ class TestCrossdock(common.TransactionCase): # Create a sales order with a line of 100 PCE incoming shipment with route_id crossdock shipping so_form = Form(self.env['sale.order']) - so_form.partner_id = self.env.ref('base.res_partner_4') + so_form.partner_id = self.env['res.partner'].create({'name': 'My Test Partner'}) so_form.warehouse_id = wh_pps with mute_logger('odoo.tests.common.onchange'): diff --git a/addons/stock_dropshipping/tests/test_dropship.py b/addons/stock_dropshipping/tests/test_dropship.py index 93c56163af2..a3c49b1c07f 100644 --- a/addons/stock_dropshipping/tests/test_dropship.py +++ b/addons/stock_dropshipping/tests/test_dropship.py @@ -8,7 +8,7 @@ from odoo.tools import mute_logger class TestDropship(common.TransactionCase): def test_change_qty(self): # enable the dropship and MTO route on the product - prod = self.env.ref('product.product_product_8') + prod = self.env['product.product'].create({'name': 'Large Desk'}) dropshipping_route = self.env.ref('stock_dropshipping.route_drop_shipping') mto_route = self.env.ref('stock.route_warehouse0_mto') prod.write({'route_ids': [(6, 0, [dropshipping_route.id, mto_route.id])]}) @@ -87,7 +87,7 @@ class TestDropship(common.TransactionCase): # Create a sales order with a line of 200 PCE incoming shipment, with route_id drop shipping so_form = Form(self.env['sale.order']) - so_form.partner_id = self.env.ref('base.res_partner_2') + so_form.partner_id = self.env['res.partner'].create({'name': 'My Test Partner'}) so_form.payment_term_id = self.env.ref('account.account_payment_term_end_following_month') with mute_logger('odoo.tests.common.onchange'): # otherwise complains that there's not enough inventory and diff --git a/addons/stock_dropshipping/tests/test_lifo_price.py b/addons/stock_dropshipping/tests/test_lifo_price.py index 8459cc4ea1b..5edf4059bb8 100644 --- a/addons/stock_dropshipping/tests/test_lifo_price.py +++ b/addons/stock_dropshipping/tests/test_lifo_price.py @@ -2,21 +2,15 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import fields, tools +from odoo.addons.stock_account.tests.stock_account_minimal_test import StockAccountMinimalTest from odoo.modules.module import get_module_resource from odoo.tests import common, Form -class TestLifoPrice(common.TransactionCase): - - def _load(self, module, *args): - tools.convert_file( - self.cr, 'stock_dropshipping', get_module_resource(module, *args), {}, 'init', False, 'test', self.registry._assertion_report) +class TestLifoPrice(StockAccountMinimalTest): def test_lifoprice(self): - self._load('account', 'test', 'account_minimal_test.xml') - self._load('stock_account', 'test', 'stock_valuation_account.xml') - # Set product category removal strategy as LIFO product_category_001 = self.env['product.category'].create({ 'name': 'Lifo Category', @@ -24,6 +18,7 @@ class TestLifoPrice(common.TransactionCase): 'property_valuation': 'real_time', 'property_cost_method': 'fifo', }) + res_partner_3 = self.env['res.partner'].create({'name': 'My Test Partner'}) # Set a product as using lifo price product_form = Form(self.env['product.product']) @@ -39,8 +34,8 @@ class TestLifoPrice(common.TransactionCase): # category (or hand-assign the property_* version which seems...) # product_form.categ_id.valuation = 'real_time' # product_form.categ_id.property_cost_method = 'fifo' - product_form.categ_id.property_stock_account_input_categ_id = self.env.ref('stock_dropshipping.o_expense') - product_form.categ_id.property_stock_account_output_categ_id = self.env.ref('stock_dropshipping.o_income') + product_form.categ_id.property_stock_account_input_categ_id = self.o_expense + product_form.categ_id.property_stock_account_output_categ_id = self.o_income product_lifo_icecream = product_form.save() std_price_wiz = Form(self.env['stock.change.standard.price'].with_context(active_id=product_lifo_icecream.id, active_model='product.product')) @@ -49,7 +44,7 @@ class TestLifoPrice(common.TransactionCase): # I create a draft Purchase Order for first in move for 10 pieces at 60 euro order_form = Form(self.env['purchase.order']) - order_form.partner_id = self.env.ref('base.res_partner_3') + order_form.partner_id = res_partner_3 with order_form.order_line.new() as line: line.product_id = product_lifo_icecream line.product_qty = 10.0 @@ -58,7 +53,7 @@ class TestLifoPrice(common.TransactionCase): # I create a draft Purchase Order for second shipment for 30 pieces at 80 euro order2_form = Form(self.env['purchase.order']) - order2_form.partner_id = self.env.ref('base.res_partner_3') + order2_form.partner_id = res_partner_3 with order2_form.order_line.new() as line: line.product_id = product_lifo_icecream line.product_qty = 30.0 diff --git a/addons/stock_dropshipping/tests/test_procurement_exception.py b/addons/stock_dropshipping/tests/test_procurement_exception.py index b7e2c01b580..8d1a234d4c2 100644 --- a/addons/stock_dropshipping/tests/test_procurement_exception.py +++ b/addons/stock_dropshipping/tests/test_procurement_exception.py @@ -8,6 +8,12 @@ class TestProcurementException(common.TransactionCase): def test_00_procurement_exception(self): + res_partner_2 = self.env['res.partner'].create({'name': 'My Test Partner'}) + res_partner_address = self.env['res.partner'].create({ + 'name': 'My Test Partner Address', + 'parent_id': res_partner_2.id, + }) + # I create a product with no supplier define for it. product_form = Form(self.env['product.product']) product_form.name = 'product with no seller' @@ -18,12 +24,11 @@ class TestProcurementException(common.TransactionCase): std_price_wiz = Form(self.env['stock.change.standard.price'].with_context(active_id=product_with_no_seller.id, active_model='product.product')) std_price_wiz.new_price = 70.0 std_price_wiz.save() - # I create a sales order with this product with route dropship. so_form = Form(self.env['sale.order']) - so_form.partner_id = self.env.ref('base.res_partner_2') - so_form.partner_invoice_id = self.env.ref('base.res_partner_address_3') - so_form.partner_shipping_id = self.env.ref('base.res_partner_address_3') + so_form.partner_id = res_partner_2 + so_form.partner_invoice_id = res_partner_address + so_form.partner_shipping_id = res_partner_address so_form.payment_term_id = self.env.ref('account.account_payment_term_end_following_month') with so_form.order_line.new() as line: line.product_id = product_with_no_seller @@ -39,7 +44,7 @@ class TestProcurementException(common.TransactionCase): with Form(product_with_no_seller) as f: with f.seller_ids.new() as seller: seller.delay = 1 - seller.name = self.env.ref('base.res_partner_2') + seller.name = res_partner_2 seller.min_qty = 2.0 # I confirm the sales order, no error this time diff --git a/addons/stock_dropshipping/tests/test_stockvaluation.py b/addons/stock_dropshipping/tests/test_stockvaluation.py index 2f8f9bc65aa..d4805cca50b 100644 --- a/addons/stock_dropshipping/tests/test_stockvaluation.py +++ b/addons/stock_dropshipping/tests/test_stockvaluation.py @@ -1,25 +1,67 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.addons.account.tests.account_test_classes import AccountingTestCase +from odoo.addons.stock_account.tests.stock_account_minimal_test import StockAccountMinimalTest from odoo.tests import Form, tagged @tagged('post_install', '-at_install') -class TestStockValuation(AccountingTestCase): - def setUp(self): - super(TestStockValuation, self).setUp() - self.supplier_location = self.env.ref('stock.stock_location_suppliers') - self.stock_location = self.env.ref('stock.stock_location_stock') - self.partner_id = self.env.ref('base.res_partner_1') - self.product1 = self.env.ref('product.product_product_8') - self.categ_id = self.product1.categ_id +class TestStockValuation(StockAccountMinimalTest): - self.acc_payable = self.partner_id.property_account_payable_id.id - self.acc_expense = self.categ_id.property_account_expense_categ_id.id - self.acc_receivable = self.partner_id.property_account_receivable_id.id - self.acc_sale = self.categ_id.property_account_income_categ_id.id - self.acc_stock_in = self.categ_id.property_stock_account_input_categ_id.id - self.acc_stock_out = self.categ_id.property_stock_account_output_categ_id.id + @classmethod + def setUpClass(cls): + super(TestStockValuation, cls).setUpClass() + # Setup a new company to avoid any external influence + cls.company = cls.env['res.company'].create({ + 'name': 'My Test Company', + 'currency_id': cls.env.ref('base.USD').id, + }) + cls.env.user.company_id = cls.company + cls.create_accounting_minimal_data() + + cls.supplier_location = cls.env.ref('stock.stock_location_suppliers') + cls.stock_location = cls.env.ref('stock.stock_location_stock') + cls.partner_id = cls.env['res.partner'].create({'name': 'My Test Partner'}) + cls.product1 = cls.env['product.product'].create({ + 'name': 'Large Desk', + 'type': 'product', + 'categ_id': cls.env.ref('product.product_category_all').id, + 'taxes_id': [(6, 0, [])], + }) + cls.categ_id = cls.product1.categ_id + cls.stock_input_account = cls.env['account.account'].create({ + 'name': 'Stock Input', + 'code': 'StockIn', + 'user_type_id': cls.env.ref('account.data_account_type_current_assets').id, + 'reconcile': True, + }) + cls.stock_output_account = cls.env['account.account'].create({ + 'name': 'Stock Output', + 'code': 'StockOut', + 'user_type_id': cls.env.ref('account.data_account_type_current_assets').id, + 'reconcile': True, + }) + cls.stock_valuation_account = cls.env['account.account'].create({ + 'name': 'Stock Valuation', + 'code': 'Stock Valuation', + 'user_type_id': cls.env.ref('account.data_account_type_current_assets').id, + }) + cls.stock_journal = cls.env['account.journal'].create({ + 'name': 'Stock Journal', + 'code': 'STJTEST', + 'type': 'general', + }) + cls.product1.categ_id.write({ + 'property_stock_account_input_categ_id': cls.stock_input_account.id, + 'property_stock_account_output_categ_id': cls.stock_output_account.id, + 'property_stock_valuation_account_id': cls.stock_valuation_account.id, + 'property_stock_journal': cls.stock_journal.id, + }) + cls.acc_payable = cls.partner_id.property_account_payable_id.id + cls.acc_expense = cls.categ_id.property_account_expense_categ_id.id + cls.acc_receivable = cls.partner_id.property_account_receivable_id.id + cls.acc_sale = cls.categ_id.property_account_income_categ_id.id + cls.acc_stock_in = cls.categ_id.property_stock_account_input_categ_id.id + cls.acc_stock_out = cls.categ_id.property_stock_account_output_categ_id.id def _dropship_product1(self): # enable the dropship and MTO route on the product @@ -47,6 +89,7 @@ class TestStockValuation(AccountingTestCase): 'product_uom_qty': 1, 'product_uom': self.product1.uom_id.id, 'price_unit': 12, + 'tax_id': [(6, 0, [])], })], 'pricelist_id': self.env.ref('product.list0').id, 'picking_policy': 'direct', @@ -69,6 +112,7 @@ class TestStockValuation(AccountingTestCase): move_form = Form(self.env['account.move'].with_context(default_type='in_invoice')) move_form.partner_id = vendor1 move_form.purchase_id = self.purchase_order1 + move_form.line_ids.tax_ids = False self.vendor_bill1 = move_form.save() self.vendor_bill1.post() @@ -261,7 +305,6 @@ class TestStockValuation(AccountingTestCase): self.acc_stock_in: (8.0, 8.0), self.acc_stock_out: (8.0, 8.0), } - self._check_results(expected_aml, 10, all_amls) def test_dropship_standard_perpetual_anglosaxon_ordered_return(self): diff --git a/addons/stock_landed_costs/tests/common.py b/addons/stock_landed_costs/tests/common.py index ac14bb6745e..273d1a246fd 100644 --- a/addons/stock_landed_costs/tests/common.py +++ b/addons/stock_landed_costs/tests/common.py @@ -7,11 +7,6 @@ from odoo.modules.module import get_module_resource class TestStockLandedCostsCommon(AccountingTestCase): - def _load(self, module, *args): - tools.convert_file(self.cr, 'stock_landed_costs', - get_module_resource(module, *args), - {}, 'init', False, 'test', self.registry._assertion_report) - def setUp(self): super(TestStockLandedCostsCommon, self).setUp() # Objects @@ -21,8 +16,8 @@ class TestStockLandedCostsCommon(AccountingTestCase): self.LandedCost = self.env['stock.landed.cost'] self.CostLine = self.env['stock.landed.cost.lines'] # References - self.supplier_id = self.ref('base.res_partner_2') - self.customer_id = self.ref('base.res_partner_4') + self.supplier_id = self.env['res.partner'].create({'name': 'My Test Supplier'}).id + self.customer_id = self.env['res.partner'].create({'name': 'My Test Customer'}).id self.picking_type_in_id = self.ref('stock.picking_type_in') self.picking_type_out_id = self.ref('stock.picking_type_out') self.supplier_location_id = self.ref('stock.stock_location_suppliers') diff --git a/addons/stock_landed_costs/tests/test_stock_landed_costs.py b/addons/stock_landed_costs/tests/test_stock_landed_costs.py index c2ceedf8109..fd366173e4b 100644 --- a/addons/stock_landed_costs/tests/test_stock_landed_costs.py +++ b/addons/stock_landed_costs/tests/test_stock_landed_costs.py @@ -2,20 +2,18 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo.addons.stock_landed_costs.tests.common import TestStockLandedCostsCommon +from odoo.addons.stock_account.tests.stock_account_minimal_test import StockAccountMinimalTest from odoo.exceptions import ValidationError from odoo.tests import tagged @tagged('post_install', '-at_install') -class TestStockLandedCosts(TestStockLandedCostsCommon): +class TestStockLandedCosts(TestStockLandedCostsCommon, StockAccountMinimalTest): def test_stock_landed_costs(self): # In order to test the landed costs feature of stock, # I create a landed cost, confirm it and check its account move created - self._load('account', 'test', 'account_minimal_test.xml') - self._load('stock_account', 'test', 'stock_valuation_account.xml') - # I create 2 products with different volume and gross weight and configure # them for real_time valuation and fifo costing method product_landed_cost_1 = self.env['product.product'].create({ @@ -24,8 +22,8 @@ class TestStockLandedCosts(TestStockLandedCostsCommon): 'volume': 1, }) product_landed_cost_1.product_tmpl_id.categ_id.property_cost_method = 'fifo' - product_landed_cost_1.product_tmpl_id.categ_id.property_stock_account_input_categ_id = self.ref('stock_landed_costs.o_expense') - product_landed_cost_1.product_tmpl_id.categ_id.property_stock_account_output_categ_id = self.ref('stock_landed_costs.o_income') + product_landed_cost_1.product_tmpl_id.categ_id.property_stock_account_input_categ_id = self.o_expense + product_landed_cost_1.product_tmpl_id.categ_id.property_stock_account_output_categ_id = self.o_income product_landed_cost_2 = self.env['product.product'].create({ 'name': "LC product 2", @@ -33,8 +31,8 @@ class TestStockLandedCosts(TestStockLandedCostsCommon): 'volume': 1.5, }) product_landed_cost_2.product_tmpl_id.categ_id.property_cost_method = 'fifo' - product_landed_cost_2.product_tmpl_id.categ_id.property_stock_account_input_categ_id = self.ref('stock_landed_costs.o_expense') - product_landed_cost_2.product_tmpl_id.categ_id.property_stock_account_output_categ_id = self.ref('stock_landed_costs.o_income') + product_landed_cost_2.product_tmpl_id.categ_id.property_stock_account_input_categ_id = self.o_expense + product_landed_cost_2.product_tmpl_id.categ_id.property_stock_account_output_categ_id = self.o_income picking_default_vals = self.env['stock.picking'].default_get(list(self.env['stock.picking'].fields_get())) @@ -90,14 +88,15 @@ class TestStockLandedCosts(TestStockLandedCostsCommon): # I create a landed cost for those 2 pickings default_vals = self.env['stock.landed.cost'].default_get(list(self.env['stock.landed.cost'].fields_get())) + virtual_home_staging = self.env['product.product'].create({'name': 'Virtual Home Staging'}) default_vals.update({ 'picking_ids': [picking_landed_cost_1.id, picking_landed_cost_2.id], - 'account_journal_id': self.ref('stock_landed_costs.expenses_journal'), + 'account_journal_id': self.expenses_journal, 'cost_lines': [ - (0, 0, {'product_id': self.ref('product.product_product_2')}), - (0, 0, {'product_id': self.ref('product.product_product_2')}), - (0, 0, {'product_id': self.ref('product.product_product_2')}), - (0, 0, {'product_id': self.ref('product.product_product_2')})], + (0, 0, {'product_id': virtual_home_staging.id}), + (0, 0, {'product_id': virtual_home_staging.id}), + (0, 0, {'product_id': virtual_home_staging.id}), + (0, 0, {'product_id': virtual_home_staging.id})], 'valuation_adjustment_lines': [], }) cost_lines_values = { diff --git a/addons/stock_landed_costs/tests/test_stock_landed_costs_purchase.py b/addons/stock_landed_costs/tests/test_stock_landed_costs_purchase.py index 357c56fb7f0..1b5fcd6e27a 100644 --- a/addons/stock_landed_costs/tests/test_stock_landed_costs_purchase.py +++ b/addons/stock_landed_costs/tests/test_stock_landed_costs_purchase.py @@ -2,6 +2,8 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import unittest from odoo.addons.stock_landed_costs.tests.common import TestStockLandedCostsCommon +from odoo.addons.stock_account.tests.test_stockvaluation import _create_accounting_data + from odoo.tests import tagged @@ -46,12 +48,15 @@ class TestLandedCosts(TestStockLandedCostsCommon): 'picking_id': self.picking_out.id, 'location_id': self.stock_location_id, 'location_dest_id': self.customer_location_id}) + self.stock_input_account, self.stock_output_account, self.stock_valuation_account, self.expense_account, self.stock_journal = _create_accounting_data(self.env) + self.categ_all.write({ + 'property_stock_account_input_categ_id': self.stock_input_account.id, + 'property_stock_account_output_categ_id': self.stock_output_account.id, + 'property_stock_valuation_account_id': self.stock_valuation_account.id, + 'property_stock_journal': self.stock_journal.id, + }) def test_00_landed_costs_on_incoming_shipment(self): - chart_of_accounts = self.env.company.chart_template_id - generic_coa = self.env.ref('l10n_generic_coa.configurable_chart_template') - if chart_of_accounts != generic_coa: - raise unittest.SkipTest('Skip this test as it works only with %s (%s loaded)' % (generic_coa.name, chart_of_accounts.name)) """ Test landed cost on incoming shipment """ # # (A) Purchase product @@ -101,11 +106,6 @@ class TestLandedCosts(TestStockLandedCostsCommon): self.assertEqual(account_entry['debit'], 430.0, 'Wrong Account Entry') def test_01_negative_landed_costs_on_incoming_shipment(self): - chart_of_accounts = self.env.company.chart_template_id - generic_coa = self.env.ref('l10n_generic_coa.configurable_chart_template') - if chart_of_accounts != generic_coa: - raise unittest.SkipTest('Skip this test as it works only with %s (%s loaded)' % (generic_coa.name, chart_of_accounts.name)) - """ Test negative landed cost on incoming shipment """ # # (A) Purchase Product diff --git a/addons/stock_landed_costs/tests/test_stock_landed_costs_rounding.py b/addons/stock_landed_costs/tests/test_stock_landed_costs_rounding.py index 064b3093de4..458a9791e68 100644 --- a/addons/stock_landed_costs/tests/test_stock_landed_costs_rounding.py +++ b/addons/stock_landed_costs/tests/test_stock_landed_costs_rounding.py @@ -2,18 +2,16 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo.addons.stock_landed_costs.tests.common import TestStockLandedCostsCommon +from odoo.addons.stock_account.tests.stock_account_minimal_test import StockAccountMinimalTest from odoo.tests import tagged @tagged('post_install', '-at_install') -class TestStockLandedCostsRounding(TestStockLandedCostsCommon): +class TestStockLandedCostsRounding(TestStockLandedCostsCommon, StockAccountMinimalTest): def test_stock_landed_costs_rounding(self): # In order to test the rounding in landed costs feature of stock, I create 2 landed cost - self._load('account', 'test', 'account_minimal_test.xml') - self._load('stock_account', 'test', 'stock_valuation_account.xml') - # Define undivisible units product_uom_unit_round_1 = self.env.ref('uom.product_uom_unit') product_uom_unit_round_1.write({ @@ -28,8 +26,8 @@ class TestStockLandedCostsRounding(TestStockLandedCostsCommon): 'uom_id': product_uom_unit_round_1.id, }) product_landed_cost_3.product_tmpl_id.categ_id.property_cost_method = 'fifo' - product_landed_cost_3.product_tmpl_id.categ_id.property_stock_account_input_categ_id = self.ref('stock_landed_costs.o_expense') - product_landed_cost_3.product_tmpl_id.categ_id.property_stock_account_output_categ_id = self.ref('stock_landed_costs.o_income') + product_landed_cost_3.product_tmpl_id.categ_id.property_stock_account_input_categ_id = self.o_expense + product_landed_cost_3.product_tmpl_id.categ_id.property_stock_account_output_categ_id = self.o_income product_landed_cost_4 = self.env['product.product'].create({ 'name': "LC product 4", @@ -37,8 +35,8 @@ class TestStockLandedCostsRounding(TestStockLandedCostsCommon): }) product_landed_cost_4.product_tmpl_id.categ_id.property_cost_method = 'fifo' product_landed_cost_4.product_tmpl_id.categ_id.property_valuation = 'real_time' - product_landed_cost_4.product_tmpl_id.categ_id.property_stock_account_input_categ_id = self.ref('stock_landed_costs.o_expense') - product_landed_cost_4.product_tmpl_id.categ_id.property_stock_account_output_categ_id = self.ref('stock_landed_costs.o_income') + product_landed_cost_4.product_tmpl_id.categ_id.property_stock_account_input_categ_id = self.o_expense + product_landed_cost_4.product_tmpl_id.categ_id.property_stock_account_output_categ_id = self.o_income picking_default_vals = self.env['stock.picking'].default_get(list(self.env['stock.picking'].fields_get())) @@ -87,12 +85,14 @@ class TestStockLandedCostsRounding(TestStockLandedCostsCommon): picking_landed_cost_3.action_assign() picking_landed_cost_3._action_done() + virtual_interior_design = self.env['product.product'].create({'name': 'Virtual Interior Design'}) + # I create a landed cost for picking 3 default_vals = self.env['stock.landed.cost'].default_get(list(self.env['stock.landed.cost'].fields_get())) default_vals.update({ 'picking_ids': [picking_landed_cost_3.id], - 'account_journal_id': self.ref('stock_landed_costs.expenses_journal'), - 'cost_lines': [(0, 0, {'product_id': self.ref('product.product_product_1')})], + 'account_journal_id': self.expenses_journal, + 'cost_lines': [(0, 0, {'product_id': virtual_interior_design.id})], 'valuation_adjustment_lines': [], }) stock_landed_cost_2 = self.env['stock.landed.cost'].new(default_vals) @@ -128,8 +128,8 @@ class TestStockLandedCostsRounding(TestStockLandedCostsCommon): default_vals = self.env['stock.landed.cost'].default_get(list(self.env['stock.landed.cost'].fields_get())) default_vals.update({ 'picking_ids': [picking_landed_cost_4.id], - 'account_journal_id': self.ref('stock_landed_costs.expenses_journal'), - 'cost_lines': [(0, 0, {'product_id': self.ref('product.product_product_1')})], + 'account_journal_id': self.expenses_journal, + 'cost_lines': [(0, 0, {'product_id': virtual_interior_design.id})], 'valuation_adjustment_lines': [], }) stock_landed_cost_3 = self.env['stock.landed.cost'].new(default_vals) diff --git a/addons/stock_landed_costs/tests/test_stockvaluationlayer.py b/addons/stock_landed_costs/tests/test_stockvaluationlayer.py index e4cab04936e..66c075858d7 100644 --- a/addons/stock_landed_costs/tests/test_stockvaluationlayer.py +++ b/addons/stock_landed_costs/tests/test_stockvaluationlayer.py @@ -6,9 +6,10 @@ from odoo.tests import Form, tagged from odoo.addons.stock_account.tests.test_stockvaluationlayer import TestStockValuationCommon from odoo.addons.stock_account.tests.test_stockvaluation import _create_accounting_data +from odoo.addons.stock_account.tests.stock_account_minimal_test import StockAccountMinimalTest -class TestStockValuationLC(TestStockValuationCommon): +class TestStockValuationLC(TestStockValuationCommon, StockAccountMinimalTest): @classmethod def setUpClass(cls): super(TestStockValuationLC, cls).setUpClass() diff --git a/addons/survey/static/tests/tours/certification_failure.js b/addons/survey/static/tests/tours/certification_failure.js index baebb64864d..e26ac61b17c 100644 --- a/addons/survey/static/tests/tours/certification_failure.js +++ b/addons/survey/static/tests/tours/certification_failure.js @@ -82,7 +82,7 @@ var lastSteps = [{ tour.register('test_certification_failure', { test: true, - url: '/survey/start/4ead4bc8-b8f2-4760-a682-1fde8ddb95ac' + url: '/survey/start/4ead4bc8-b8f2-4760-a682-1fde8daaaaac' }, [].concat(failSteps, retrySteps, failSteps, lastSteps)); }); diff --git a/addons/survey/static/tests/tours/certification_success.js b/addons/survey/static/tests/tours/certification_success.js index 39108e1b7a4..afefe3648eb 100644 --- a/addons/survey/static/tests/tours/certification_success.js +++ b/addons/survey/static/tests/tours/certification_success.js @@ -5,7 +5,7 @@ var tour = require('web_tour.tour'); tour.register('test_certification_success', { test: true, - url: '/survey/start/4ead4bc8-b8f2-4760-a682-1fde8ddb95ac' + url: '/survey/start/4ead4bc8-b8f2-4760-a682-1fde8daaaaac' }, [{ // Page-1 content: "Clicking on Start Certification", diff --git a/addons/survey/static/tests/tours/survey.js b/addons/survey/static/tests/tours/survey.js index 2ce01b8dc41..422ee75a68e 100644 --- a/addons/survey/static/tests/tours/survey.js +++ b/addons/survey/static/tests/tours/survey.js @@ -5,7 +5,7 @@ var tour = require('web_tour.tour'); tour.register('test_survey', { test: true, - url: '/survey/start/b137640d-14d4-4748-9ef6-344ca256531e', + url: '/survey/start/b137640d-14d4-4748-9ef6-344caaaaaae', }, [ // Page-1 { diff --git a/addons/survey/static/tests/tours/survey_prefill.js b/addons/survey/static/tests/tours/survey_prefill.js index 01fb3bec41b..845a3bdf53a 100644 --- a/addons/survey/static/tests/tours/survey_prefill.js +++ b/addons/survey/static/tests/tours/survey_prefill.js @@ -5,7 +5,7 @@ var tour = require('web_tour.tour'); tour.register('test_survey_prefill', { test: true, - url: '/survey/start/b137640d-14d4-4748-9ef6-344ca256531e' + url: '/survey/start/b137640d-14d4-4748-9ef6-344caaaaaae' }, [{ // Page-1 trigger: 'a.btn.btn-primary.btn-lg:contains("Start Survey")', @@ -17,7 +17,10 @@ tour.register('test_survey_prefill', { run: 'text 05/05/1980', }, { // Question: How frequently do you buy products online ? trigger: 'div.js_question-wrapper:contains("How frequently do you buy products online ?") select', - run: 'text 2', // value 2 = 'Once a week' + run: function() { + var optionID = $('option:contains("Once a week")').val(); + $('div.js_question-wrapper:contains("How frequently do you buy products online ?") select').val(optionID); + }, }, { // Question: How many times did you order products on our website ? trigger: 'div.js_question-wrapper:contains("How many times did you order products on our website ?") input', run: 'text 42', diff --git a/addons/survey/tests/__init__.py b/addons/survey/tests/__init__.py index feae4e21546..76df1c8efa8 100644 --- a/addons/survey/tests/__init__.py +++ b/addons/survey/tests/__init__.py @@ -8,6 +8,7 @@ from . import test_certification_flow from . import test_survey_invite from . import test_survey_security from . import test_survey_randomize -from . import test_survey_ui +from . import test_survey_ui_certification +from . import test_survey_ui_feedback from . import test_survey_compute_pages_questions from . import test_certification_badge diff --git a/addons/survey/tests/test_survey_ui.py b/addons/survey/tests/test_survey_ui.py deleted file mode 100644 index e9abcd08b90..00000000000 --- a/addons/survey/tests/test_survey_ui.py +++ /dev/null @@ -1,30 +0,0 @@ -# Part of Odoo. See LICENSE file for full copyright and licensing details. -import odoo.tests - - -@odoo.tests.common.tagged('post_install','-at_install') -class TestUi(odoo.tests.HttpCase): - - def test_01_admin_survey_tour(self): - access_token = self.env.ref('survey.survey_feedback').access_token - self.start_tour("/survey/start/%s" % access_token, 'test_survey', login="admin") - - def test_02_demo_survey_tour(self): - access_token = self.env.ref('survey.survey_feedback').access_token - self.start_tour("/survey/start/%s" % access_token, 'test_survey', login="demo") - - def test_03_public_survey_tour(self): - access_token = self.env.ref('survey.survey_feedback').access_token - self.start_tour("/survey/start/%s" % access_token, 'test_survey') - - def test_04_certification_success_tour(self): - access_token = self.env.ref('survey.vendor_certification').access_token - self.start_tour("/survey/start/%s" % access_token, 'test_certification_success', login="demo") - - def test_05_certification_failure_tour(self): - access_token = self.env.ref('survey.vendor_certification').access_token - self.start_tour("/survey/start/%s" % access_token, 'test_certification_failure', login="demo") - - def test_06_survey_prefill(self): - access_token = self.env.ref('survey.survey_feedback').access_token - self.start_tour("/survey/start/%s" % access_token, 'test_survey_prefill') diff --git a/addons/survey/tests/test_survey_ui_certification.py b/addons/survey/tests/test_survey_ui_certification.py new file mode 100644 index 00000000000..f5a6e5645c4 --- /dev/null +++ b/addons/survey/tests/test_survey_ui_certification.py @@ -0,0 +1,245 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import odoo.tests +from odoo.addons.base.tests.common import HttpCaseWithUserDemo + +@odoo.tests.common.tagged('post_install', '-at_install') +class TestUiCertification(HttpCaseWithUserDemo): + + def setUp(self): + super(TestUiCertification, self).setUp() + + self.survey_certification = self.env['survey.survey'].create({ + 'title': 'MyCompany Vendor Certification', + 'access_token': '4ead4bc8-b8f2-4760-a682-1fde8daaaaac', + 'state': 'open', + 'access_mode': 'public', + 'users_can_go_back': True, + 'users_login_required': True, + 'scoring_type': 'scoring_with_answers', + 'certificate': True, + 'certification_mail_template_id': self.env.ref('survey.mail_template_certification').id, + 'is_time_limited': 'limited', + 'time_limit': 10.0, + 'is_attempts_limited': True, + 'attempts_limit': 2, + 'description': """<p>Test your vendor skills!.</p>""", + 'thank_you_message': """<p></p>""", + 'question_and_page_ids': [ + (0, 0, { + 'title': 'Products', + 'sequence': 1, + 'is_page': True, + 'question_type': False, + 'description': '<p>Test your knowledge of your products!</p>', + }), (0, 0, { + 'title': 'Do we sell Acoustic Bloc Screens?', + 'sequence': 2, + 'question_type': 'simple_choice', + 'display_mode': 'dropdown', + 'constr_mandatory': True, + 'labels_ids': [ + (0, 0, { + 'value': 'No', + 'sequence': 1, + }), (0, 0, { + 'value': 'Yes', + 'sequence': 2, + 'is_correct': True, + 'answer_score': 2, + }) + ], + }), (0, 0, { + 'title': 'Select all the existing products', + 'sequence': 3, + 'question_type': 'multiple_choice', + 'column_nb': '4', + 'labels_ids': [ + (0, 0, { + 'value': 'Chair floor protection', + 'sequence': 1, + 'is_correct': True, + 'answer_score': 1, + }), (0, 0, { + 'value': 'Fanta', + 'sequence': 2, + 'answer_score': -1, + }), (0, 0, { + 'value': 'Conference chair', + 'sequence': 3, + 'is_correct': True, + 'answer_score': 1, + }), (0, 0, { + 'value': 'Drawer', + 'sequence': 4, + 'is_correct': True, + 'answer_score': 1, + }), (0, 0, { + 'value': 'Customizable Lamp', + 'sequence': 5, + 'answer_score': -1, + }) + ] + }), (0, 0, { + 'title': 'Select all the available customizations for our Customizable Desk', + 'sequence': 4, + 'question_type': 'multiple_choice', + 'column_nb': '4', + 'labels_ids': [ + (0, 0, { + 'value': 'Color', + 'sequence': 1, + 'is_correct': True, + 'answer_score': 1, + }), (0, 0, { + 'value': 'Height', + 'sequence': 2, + 'answer_score': -1, + }), (0, 0, { + 'value': 'Width', + 'sequence': 3, + 'is_correct': True, + 'answer_score': 1, + }), (0, 0, { + 'value': 'Legs', + 'sequence': 4, + 'is_correct': True, + 'answer_score': 1, + }), (0, 0, { + 'value': 'Number of drawers', + 'sequence': 5, + 'answer_score': -1, + }) + ] + }), (0, 0, { + 'title': 'How many versions of the Corner Desk do we have?', + 'sequence': 5, + 'question_type': 'simple_choice', + 'display_mode': 'dropdown', + 'constr_mandatory': True, + 'labels_ids': [ + (0, 0, { + 'value': 1, + 'sequence': 1, + }), (0, 0, { + 'value': 2, + 'sequence': 2, + 'is_correct': True, + 'answer_score': 2, + }), (0, 0, { + 'value': 3, + 'sequence': 3, + }), (0, 0, { + 'value': 4, + 'sequence': 4, + }) + ] + }), (0, 0, { + 'title': 'Do you think we have missing products in our catalog? (not rated)', + 'sequence': 6, + 'question_type': 'free_text', + }), (0, 0, { + 'title': 'Prices', + 'sequence': 7, + 'is_page': True, + 'question_type': False, + 'description': """<p>Test your knowledge of our prices.</p>""", + }), (0, 0, { + 'title': 'How much do we sell our Cable Management Box?', + 'sequence': 8, + 'question_type': 'simple_choice', + 'display_mode': 'dropdown', + 'constr_mandatory': True, + 'labels_ids': [ + (0, 0, { + 'value': '20$', + 'sequence': 1, + }), (0, 0, { + 'value': '50$', + 'sequence': 2, + }), (0, 0, { + 'value': '80$', + 'sequence': 3, + }), (0, 0, { + 'value': '100$', + 'sequence': 4, + 'is_correct': True, + 'answer_score': 2, + }), (0, 0, { + 'value': '200$', + 'sequence': 5, + }), (0, 0, { + 'value': '300$', + 'sequence': 6, + }) + ] + }), (0, 0, { + 'title': 'Select all the the products that sell for 100$ or more', + 'sequence': 9, + 'question_type': 'multiple_choice', + 'column_nb': '2', + 'labels_ids': [ + (0, 0, { + 'value': 'Corner Desk Right Sit', + 'sequence': 1, + 'answer_score': 1, + 'is_correct': True, + }), (0, 0, { + 'value': 'Desk Combination', + 'sequence': 2, + 'answer_score': 1, + 'is_correct': True, + }), (0, 0, { + 'value': 'Cabinet with Doors', + 'sequence': 3, + 'answer_score': -1, + }), (0, 0, { + 'value': 'Large Desk', + 'sequence': 4, + 'answer_score': 1, + 'is_correct': True, + }), (0, 0, { + 'value': 'Letter Tray', + 'sequence': 5, + 'answer_score': -1, + }), (0, 0, { + 'value': 'Office Chair Black', + 'sequence': 6, + 'answer_score': -1, + }), + ] + }), (0, 0, { + 'title': 'What do you think about our prices (not rated)?', + 'sequence': 10, + 'question_type': 'simple_choice', + 'display_mode': 'dropdown', + 'constr_mandatory': True, + 'labels_ids': [ + (0, 0, { + 'value': 'Very underpriced', + 'sequence': 1, + }), (0, 0, { + 'value': 'Underpriced', + 'sequence': 2, + }), (0, 0, { + 'value': 'Correctly priced', + 'sequence': 3, + }), (0, 0, { + 'value': 'A little bit overpriced', + 'sequence': 4, + }), (0, 0, { + 'value': 'A lot overpriced', + 'sequence': 5, + }) + ] + }) + ] + }) + + def test_04_certification_success_tour(self): + access_token = self.survey_certification.access_token + self.start_tour("/survey/start/%s" % access_token, 'test_certification_success', login="demo") + + def test_05_certification_failure_tour(self): + access_token = self.survey_certification.access_token + self.start_tour("/survey/start/%s" % access_token, 'test_certification_failure', login="demo") diff --git a/addons/survey/tests/test_survey_ui_feedback.py b/addons/survey/tests/test_survey_ui_feedback.py new file mode 100644 index 00000000000..2e10d757f8e --- /dev/null +++ b/addons/survey/tests/test_survey_ui_feedback.py @@ -0,0 +1,169 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import odoo.tests +from odoo.addons.base.tests.common import HttpCaseWithUserDemo + +@odoo.tests.common.tagged('post_install', '-at_install') +class TestUiFeedback(HttpCaseWithUserDemo): + + def setUp(self): + super(TestUiFeedback, self).setUp() + self.survey_feedback = self.env['survey.survey'].create({ + 'title': 'User Feedback Form', + 'access_token': 'b137640d-14d4-4748-9ef6-344caaaaaae', + 'state': 'open', + 'access_mode': 'public', + 'users_can_go_back': True, + 'questions_layout': 'page_per_section', + 'description': """

This survey allows you to give a feedback about your experience with our eCommerce solution. + Filling it helps us improving your experience.

""", + 'thank_you_message': """<p></p>""", + 'question_and_page_ids': [ + (0, 0, { + 'title': 'General information', + 'sequence': 1, + 'question_type': False, + 'is_page': True, + 'description': """

This section is about general informations about you. Answering them helps qualifying your answers.

""", + }), (0, 0, { + 'title': 'Where do you live ?', + 'sequence': 2, + 'question_type': 'textbox', + 'constr_mandatory': False, + }), (0, 0, { + 'title': 'When is your date of birth ?', + 'sequence': 3, + 'question_type': 'date', + 'description': False, + }), (0, 0, { + 'title': 'How frequently do you buy products online ?', + 'sequence': 4, + 'question_type': 'simple_choice', + 'display_mode': 'dropdown', + 'comments_allowed': True, + 'comment_count_as_answer': True, + 'constr_mandatory': True, + 'labels_ids': [ + (0, 0, { + 'value': 'Once a day', + 'sequence': 1, + }), (0, 0, { + 'value': 'Once a week', + 'sequence': 2, + }), (0, 0, { + 'value': 'Once a month', + 'sequence': 3, + }), (0, 0, { + 'value': 'Once a year', + 'sequence': 4, + }), (0, 0, { + 'value': 'Other (answer in comment)', + 'sequence': 5, + })], + }), (0, 0, { + 'title': 'How many times did you order products on our website ?', + 'sequence': 5, + 'question_type': 'numerical_box', + 'constr_mandatory': True, + }), (0, 0, { + 'title': 'About our ecommerce', + 'sequence': 6, + 'is_page': True, + 'question_type': False, + 'description': """

This section is about our eCommerce experience itself.

""", + }), (0, 0, { + 'title': 'Which of the following words would you use to describe our products ?', + 'sequence': 7, + 'question_type': 'multiple_choice', + 'constr_mandatory': True, + 'comments_allowed': True, + 'comment_count_as_answer': False, + 'labels_ids': [ + (0, 0, { + 'value': 'High quality', + 'sequence': 1, + }), (0, 0, { + 'value': 'Useful', + 'sequence': 2, + }), (0, 0, { + 'value': 'Unique', + 'sequence': 3, + }), (0, 0, { + 'value': 'Good value for money', + 'sequence': 4, + }), (0, 0, { + 'value': 'Overpriced', + 'sequence': 5, + }), (0, 0, { + 'value': 'Impractical', + 'sequence': 6, + }), (0, 0, { + 'value': 'Ineffective', + 'sequence': 7, + }), (0, 0, { + 'value': 'Poor quality', + 'sequence': 8, + }), (0, 0, { + 'value': 'Other', + 'sequence': 9, + })], + }), (0, 0, { + 'title': 'What do your think about our new eCommerce ?', + 'sequence': 8, + 'question_type': 'matrix', + 'matrix_subtype': 'multiple', + 'constr_mandatory': True, + 'labels_ids': [(0, 0, { + 'value': 'Totally disagree', + 'sequence': 1 + }), (0, 0, { + 'value': 'Disagree', + 'sequence': 2, + }), (0, 0, { + 'value': 'Agree', + 'sequence': 3, + }), (0, 0, { + 'value': 'Totally agree', + 'sequence': 4, + })], + 'labels_ids_2': [(0, 0, { + 'value': 'The new layout and design is fresh and up-to-date', + 'sequence': 1, + }), (0, 0, { + 'value': 'It is easy to find the product that I want', + 'sequence': 2, + }), (0, 0, { + 'value': 'The tool to compare the products is useful to make a choice', + 'sequence': 3, + }), (0, 0, { + 'value': 'The checkout process is clear and secure', + 'sequence': 4, + }), (0, 0, { + 'value': 'I have added products to my wishlist', + 'sequence': 5, + })], + }), (0, 0, { + 'title': 'Do you have any other comments, questions, or concerns ?', + 'sequence': 9, + 'question_type': 'free_text', + 'constr_mandatory': False, + }) + ], + }) + + + def test_01_admin_survey_tour(self): + access_token = self.survey_feedback.access_token + self.start_tour("/survey/start/%s" % access_token, 'test_survey', login="admin") + + def test_02_demo_survey_tour(self): + access_token = self.survey_feedback.access_token + self.start_tour("/survey/start/%s" % access_token, 'test_survey', login="demo") + + def test_03_public_survey_tour(self): + access_token = self.survey_feedback.access_token + self.start_tour("/survey/start/%s" % access_token, 'test_survey') + + def test_06_survey_prefill(self): + access_token = self.survey_feedback.access_token + self.start_tour("/survey/start/%s" % access_token, 'test_survey_prefill') diff --git a/addons/test_mail/__manifest__.py b/addons/test_mail/__manifest__.py index 9f716d8786f..18516b56e90 100644 --- a/addons/test_mail/__manifest__.py +++ b/addons/test_mail/__manifest__.py @@ -14,11 +14,10 @@ tests independently to functional aspects of other models. """, 'security/ir.model.access.csv', 'security/test_mail_security.xml', 'data/data.xml', + 'data/subtype_data.xml', + 'data/template_data.xml', ], 'demo': [ - 'data/demo.xml', - 'data/subtype_demo.xml', - 'data/template_demo.xml', ], 'installable': True, 'application': False, diff --git a/addons/test_mail/data/demo.xml b/addons/test_mail/data/demo.xml deleted file mode 100644 index 552d20d439d..00000000000 --- a/addons/test_mail/data/demo.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - Object 0 - 0 - - - - Object 1 - 10 - - - - Object 2 - 20 - - - - Object 3 - 30 - - - - Object 4 - 40 - - - - diff --git a/addons/test_mail/data/subtype_demo.xml b/addons/test_mail/data/subtype_data.xml similarity index 100% rename from addons/test_mail/data/subtype_demo.xml rename to addons/test_mail/data/subtype_data.xml diff --git a/addons/test_mail/data/template_demo.xml b/addons/test_mail/data/template_data.xml similarity index 100% rename from addons/test_mail/data/template_demo.xml rename to addons/test_mail/data/template_data.xml diff --git a/addons/test_mail/tests/test_ir_actions.py b/addons/test_mail/tests/test_ir_actions.py index 9a20ee94db3..52a65232985 100644 --- a/addons/test_mail/tests/test_ir_actions.py +++ b/addons/test_mail/tests/test_ir_actions.py @@ -19,13 +19,14 @@ class TestServerActionsEmail(BaseFunctionalTest, TestServerActionsBase): def test_action_followers(self): self.test_partner.message_unsubscribe(self.test_partner.message_partner_ids.ids) + random_partner = self.env['res.partner'].create({'name': 'Thierry Wololo'}) self.action.write({ 'state': 'followers', - 'partner_ids': [(4, self.env.ref('base.partner_admin').id), (4, self.env.ref('base.partner_demo').id)], + 'partner_ids': [(4, self.env.ref('base.partner_admin').id), (4, random_partner.id)], 'channel_ids': [(4, self.env.ref('mail.channel_all_employees').id)] }) self.action.with_context(self.context).run() - self.assertEqual(self.test_partner.message_partner_ids, self.env.ref('base.partner_admin') | self.env.ref('base.partner_demo')) + self.assertEqual(self.test_partner.message_partner_ids, self.env.ref('base.partner_admin') | random_partner) self.assertEqual(self.test_partner.message_channel_ids, self.env.ref('mail.channel_all_employees')) def test_action_next_activity(self): diff --git a/addons/test_mail/tests/test_performance.py b/addons/test_mail/tests/test_performance.py index 33a3bccb149..c26fe1a81f4 100644 --- a/addons/test_mail/tests/test_performance.py +++ b/addons/test_mail/tests/test_performance.py @@ -2,13 +2,14 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import base64 +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo from odoo.tests.common import TransactionCase, users, warmup from odoo.tests import tagged from odoo.tools import mute_logger, formataddr @tagged('mail_performance') -class BaseMailPerformance(TransactionCase): +class BaseMailPerformance(TransactionCaseWithUserDemo): def setUp(self): super(BaseMailPerformance, self).setUp() @@ -34,6 +35,49 @@ class BaseMailPerformance(TransactionCase): @tagged('mail_performance') class TestMailPerformance(BaseMailPerformance): + def setUp(self): + super(TestMailPerformance, self).setUp() + + self.res_partner_3 = self.env['res.partner'].create({ + 'name': 'Gemini Furniture', + 'email': 'gemini.furniture39@example.com', + }) + self.res_partner_4 = self.env['res.partner'].create({ + 'name': 'Ready Mat', + 'email': 'ready.mat28@example.com', + }) + self.res_partner_10 = self.env['res.partner'].create({ + 'name': 'The Jackson Group', + 'email': 'jackson.group82@example.com', + }) + self.res_partner_12 = self.env['res.partner'].create({ + 'name': 'Azure Interior', + 'email': 'azure.Interior24@example.com', + }) + self.env['test_performance.mail'].create([ + { + 'name': 'Object 0', + 'value': 0, + 'partner_id': self.res_partner_3.id, + }, { + 'name': 'Object 1', + 'value': 10, + 'partner_id': self.res_partner_3.id, + }, { + 'name': 'Object 2', + 'value': 20, + 'partner_id': self.res_partner_4.id, + }, { + 'name': 'Object 3', + 'value': 30, + 'partner_id': self.res_partner_10.id, + }, { + 'name': 'Object 4', + 'value': 40, + 'partner_id': self.res_partner_12.id, + } + ]) + @users('__system__', 'demo') @warmup def test_read_mail(self): @@ -84,7 +128,7 @@ class TestMailPerformance(BaseMailPerformance): 'name': 'Test', 'track': 'Y', 'value': 40, - 'partner_id': self.env.ref('base.res_partner_12').id, + 'partner_id': self.res_partner_12.id, }) with self.assertQueryCount(__system__=3, demo=3): diff --git a/addons/test_website/static/tests/tours/json_auth.js b/addons/test_website/static/tests/tours/json_auth.js index 6c4df8e26de..ba89bed4f3c 100644 --- a/addons/test_website/static/tests/tours/json_auth.js +++ b/addons/test_website/static/tests/tours/json_auth.js @@ -19,7 +19,7 @@ tour.register('test_json_auth', { window.location.href = window.location.origin; }, }, { - trigger: 'span:contains(Mitchell Admin)', + trigger: 'span:contains(Mitchell Admin), span:contains(Administrator)', run: function () {}, } ]); diff --git a/addons/test_website/tests/test_multi_company.py b/addons/test_website/tests/test_multi_company.py index 8c9c6859959..1395466ab47 100644 --- a/addons/test_website/tests/test_multi_company.py +++ b/addons/test_website/tests/test_multi_company.py @@ -9,7 +9,7 @@ class TestMultiCompany(HttpCase): def test_company_in_context(self): """ Test website company is set in context """ - website = self.env['website'].browse(1) + website = self.env.ref('website.default_website') company = self.env['res.company'].create({'name': "Adaa"}) website.company_id = company response = self.url_open('/multi_company_website') diff --git a/addons/test_website_slides_full/tests/test_ui_wslides.py b/addons/test_website_slides_full/tests/test_ui_wslides.py index 5d8592b9eb2..39ff909e2b5 100644 --- a/addons/test_website_slides_full/tests/test_ui_wslides.py +++ b/addons/test_website_slides_full/tests/test_ui_wslides.py @@ -1,20 +1,169 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from dateutil.relativedelta import relativedelta +from odoo.fields import Datetime from odoo import tests - +from odoo.addons.website_slides.tests.test_ui_wslides import TestUICommon @tests.common.tagged('post_install', '-at_install') -class TestUi(tests.HttpCase): +class TestUi(TestUICommon): def test_course_certification_employee(self): - # remove membership because we need to be able to join the course during the tour - user_demo = self.env.ref('base.user_demo') + user_demo = self.user_demo user_demo.flush() + # Avoid Billing/Shipping address page user_demo.write({ - 'groups_id': [(5, 0), (4, self.env.ref('base.group_user').id)] + 'groups_id': [(5, 0), (4, self.env.ref('base.group_user').id)], + 'street': '215 Vine St', + 'city': 'Scranton', + 'zip': '18503', + 'country_id': self.env.ref('base.us').id, + 'state_id': self.env.ref('base.state_us_39').id, + 'phone': '+1 555-555-5555', + 'email': 'admin@yourcompany.example.com', + }) + + # Specify Accounting Data + cash_journal = self.env['account.journal'].create({'name': 'Cash - Test', 'type': 'cash', 'code': 'CASH - Test'}) + self.env['payment.acquirer'].search([('journal_id', '=', False)]).journal_id = cash_journal + a_recv = self.env['account.account'].create({ + 'code': 'X1012', + 'name': 'Debtors - (test)', + 'reconcile': True, + 'user_type_id': self.env.ref('account.data_account_type_receivable').id, + }) + a_pay = self.env['account.account'].create({ + 'code': 'X1111', + 'name': 'Creditors - (test)', + 'user_type_id': self.env.ref('account.data_account_type_payable').id, + 'reconcile': True, + }) + self.env['ir.property'].create([{ + 'name': 'property_account_receivable_id', + 'fields_id': self.env['ir.model.fields'].search([('model', '=', 'res.partner'), ('name', '=', 'property_account_receivable_id')], limit=1).id, + 'value': 'account.account,%s' % (a_recv.id), + 'company_id': self.env.company.id, + }, { + 'name': 'property_account_payable_id', + 'fields_id': self.env['ir.model.fields'].search([('model', '=', 'res.partner'), ('name', '=', 'property_account_payable_id')], limit=1).id, + 'value': 'account.account,%s' % (a_pay.id), + 'company_id': self.env.company.id, + }]) + + product_course_channel_6 = self.env['product.product'].create({ + 'name': 'DIY Furniture Course', + 'list_price': 100.0, + 'type': 'service', + 'is_published': True, + }) + + furniture_survey = self.env['survey.survey'].create({ + 'title': 'Furniture Creation Certification', + 'access_token': '5632a4d7-48cf-aaaa-8c52-2174d58cf50b', + 'state': 'open', + 'access_mode': 'public', + 'users_can_go_back': True, + 'users_login_required': True, + 'scoring_type': 'scoring_with_answers', + 'certificate': True, + 'certification_mail_template_id': self.env.ref('survey.mail_template_certification').id, + 'is_attempts_limited': True, + 'attempts_limit': 3, + 'description': "

Test your furniture knowledge!

", + 'thank_you_message': "

", + 'question_and_page_ids': [ + (0, 0, { + 'title': 'Furniture', + 'sequence': 1, + 'is_page': True, + 'description': "<p>Test your furniture knowledge!</p>", + }), (0, 0, { + 'title': 'What type of wood is the best for furniture?', + 'sequence': 2, + 'question_type': 'simple_choice', + 'display_mode': 'dropdown', + 'constr_mandatory': True, + 'labels_ids': [ + (0, 0, { + 'value': 'Fir', + 'sequence': 1, + }), (0, 0, { + 'value': 'Oak', + 'sequence': 2, + 'is_correct': True, + 'answer_score': 2.0, + }), (0, 0, { + 'value': 'Ash', + 'sequence': 3, + }), (0, 0, { + 'value': 'Beech', + 'sequence': 4, + }) + ] + }), (0, 0, { + 'title': 'Select all the furniture shown in the video', + 'sequence': 3, + 'question_type': 'multiple_choice', + 'column_nb': '4', + 'labels_ids': [ + (0, 0, { + 'value': 'Chair', + 'sequence': 1, + 'is_correct': True, + 'answer_score': 1.0, + }), (0, 0, { + 'value': 'Table', + 'sequence': 2, + 'answer_score': -1.0, + }), (0, 0, { + 'value': 'Desk', + 'sequence': 3, + 'is_correct': True, + 'answer_score': 1.0, + }), (0, 0, { + 'value': 'Shelve', + 'sequence': 4, + 'is_correct': True, + 'answer_score': 1.0, + }), (0, 0, { + 'value': 'Bed', + 'sequence': 5, + 'answer_score': -1.0, + }) + ] + }), (0, 0, { + 'title': 'What do you think about the content of the course? (not rated)', + 'sequence': 4, + 'question_type': 'free_text', + }) + ] + }) + + slide_channel_demo_6_furn3 = self.env['slide.channel'].create({ + 'name': 'DIY Furniture - TEST', + 'user_id': self.env.ref('base.user_admin').id, + 'enroll': 'payment', + 'product_id': product_course_channel_6.id, + 'channel_type': 'training', + 'allow_comment': True, + 'promote_strategy': 'most_voted', + 'is_published': True, + 'description': 'So much amazing certification.', + 'create_date': Datetime.now() - relativedelta(days=2), + 'slide_ids': [ + (0, 0, { + 'name': 'DIY Furniture Certification', + 'sequence': 1, + 'slide_type': 'certification', + 'category_id': False, + 'is_published': True, + 'is_preview': False, + 'description': "It's time to test your knowledge!", + 'survey_id': furniture_survey.id, + }) + ] }) - self.env.ref('website_slides.slide_channel_demo_6_furn3')._remove_membership(self.env.ref('base.partner_demo').ids) self.browser_js( '/slides', diff --git a/addons/test_website_slides_full/tests/tours/slides_certification_member.js b/addons/test_website_slides_full/tests/tours/slides_certification_member.js index c6f0e699cfd..53681eae54c 100644 --- a/addons/test_website_slides_full/tests/tours/slides_certification_member.js +++ b/addons/test_website_slides_full/tests/tours/slides_certification_member.js @@ -21,7 +21,7 @@ var tour = require('web_tour.tour'); var initTourSteps = [{ content: 'eLearning: go to certification course', - trigger: 'a:contains("DIY Furniture")' + trigger: 'a:contains("DIY Furniture - TEST")' }, { content: 'eLearning: does not have access to certification', trigger: '.o_wslides_course_main', diff --git a/addons/website/static/src/js/tours/banner.js b/addons/website/static/src/js/tours/banner.js index f4ddc040c69..04311eeecaf 100644 --- a/addons/website/static/src/js/tours/banner.js +++ b/addons/website/static/src/js/tours/banner.js @@ -15,6 +15,7 @@ tour.register("banner", { position: "bottom", }, { trigger: "#snippet_structure .oe_snippet:eq(1) .oe_snippet_thumbnail", + extra_trigger: "body.editor_enable.editor_has_snippets", content: _t("Drag the Cover block and drop it in your page."), position: "bottom", run: "drag_and_drop #wrap", diff --git a/addons/website/static/tests/tours/reset_password.js b/addons/website/static/tests/tours/reset_password.js index 9484a4c039f..98ce641373f 100644 --- a/addons/website/static/tests/tours/reset_password.js +++ b/addons/website/static/tests/tours/reset_password.js @@ -44,14 +44,14 @@ tour.register('website_reset_password', { }); // Set a website on "Admin" partner to test the URL of the website. var def3 = rpc.query({ - model: 'res.partner', - method: 'name_search', - kwargs: {'name': 'Mitchell Admin', 'args': [['company_id', '=', 1]]}, - }).then(function (res) { + model: 'ir.model.data', + method: 'xmlid_to_res_id', + args: ['base.partner_admin'], + }).then(function (res_id) { return rpc.query({ 'model': 'res.partner', 'method': 'write', - 'args': [[res[0][0]], { + 'args': [[res_id], { 'website_id': 1, }], }); diff --git a/addons/website/tests/test_crawl.py b/addons/website/tests/test_crawl.py index 81907aa3a16..62df28c0f38 100644 --- a/addons/website/tests/test_crawl.py +++ b/addons/website/tests/test_crawl.py @@ -10,12 +10,13 @@ from werkzeug import urls import odoo import re +from odoo.addons.base.tests.common import HttpCaseWithUserDemo _logger = logging.getLogger(__name__) -@odoo.tests.common.tagged('post_install', '-at_install') -class Crawler(odoo.tests.HttpCase): +@odoo.tests.common.tagged('post_install', '-at_install', 'crawl') +class Crawler(HttpCaseWithUserDemo): """ Test suite crawling an Odoo CMS instance and checking that all internal links lead to a 200 response. @@ -23,6 +24,23 @@ class Crawler(odoo.tests.HttpCase): starting the crawl """ + def setUp(self): + super(Crawler, self).setUp() + + if hasattr(self.env['res.partner'], 'grade_id'): + # Create at least one published parter, so that /partners doesn't + # return a 404 + grade = self.env['res.partner.grade'].create({ + 'name': 'A test grade', + 'website_published': True, + }) + self.env['res.partner'].create({ + 'name': 'A Company for /partners', + 'is_company': True, + 'grade_id': grade.id, + 'website_published': True, + }) + def crawl(self, url, seen=None, msg=''): if seen is None: seen = set() diff --git a/addons/website/tests/test_get_current_website.py b/addons/website/tests/test_get_current_website.py index ee02a4d5ff8..da36762acee 100644 --- a/addons/website/tests/test_get_current_website.py +++ b/addons/website/tests/test_get_current_website.py @@ -14,13 +14,15 @@ class TestGetCurrentWebsite(TransactionCase): Website = self.env['website'] # clean initial state - website1 = Website.browse(1) + website1 = self.env.ref('website.default_website') website1.domain = '' website1.country_group_ids = False - website2 = Website.browse(2) - website2.domain = '' - website2.country_group_ids = False + website2 = Website.create({ + 'name': 'My Website 2', + 'domain': '', + 'country_group_ids': False, + }) country1 = self.env['res.country'].create({'name': "My Country 1"}) country2 = self.env['res.country'].create({'name': "My Country 2"}) @@ -114,7 +116,7 @@ class TestGetCurrentWebsite(TransactionCase): self.assertEqual(Website._get_current_website_id('site-1.com', False), website1.id) def test_02_signup_user_website_id(self): - website = self.env['website'].browse(1) + website = self.env.ref('website.default_website') website.specific_user_account = True user = self.env['res.users'].create({'website_id': website.id, 'login': 'sad@mail.com', 'name': 'Hope Fully'}) diff --git a/addons/website/tests/test_lang_url.py b/addons/website/tests/test_lang_url.py index 871248c2778..1c08b866fa4 100644 --- a/addons/website/tests/test_lang_url.py +++ b/addons/website/tests/test_lang_url.py @@ -12,7 +12,7 @@ class TestLangUrl(HttpCase): super(TestLangUrl, self).setUp() # Simulate multi lang without loading translations - self.website = self.env['website'].browse(1) + self.website = self.env.ref('website.default_website') lang_fr = self.env.ref('base.lang_fr') lang_fr.write({'active': True, 'url_code': 'fr'}) self.website.language_ids = self.env.ref('base.lang_en') + lang_fr diff --git a/addons/website/tests/test_page.py b/addons/website/tests/test_page.py index 3c0b294b606..09f39074c89 100644 --- a/addons/website/tests/test_page.py +++ b/addons/website/tests/test_page.py @@ -167,6 +167,11 @@ class TestPage(common.TransactionCase): View = self.env['ir.ui.view'] Website = self.env['website'] + website2 = self.env['website'].create({ + 'name': 'My Second Website', + 'domain': '', + }) + # currently the view unlink of website.page can't handle views with inherited views self.extension_view.unlink() diff --git a/addons/website/tests/test_qweb.py b/addons/website/tests/test_qweb.py index 9cc199291a9..1c2c1dbe573 100644 --- a/addons/website/tests/test_qweb.py +++ b/addons/website/tests/test_qweb.py @@ -4,12 +4,13 @@ import re from odoo import tools +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo from odoo.addons.website.tools import MockRequest from odoo.modules.module import get_module_resource from odoo.tests.common import TransactionCase -class TestQweb(TransactionCase): +class TestQweb(TransactionCaseWithUserDemo): def _load(self, module, *args): tools.convert_file(self.cr, 'website', get_module_resource(module, *args), @@ -18,7 +19,7 @@ class TestQweb(TransactionCase): def test_qweb_cdn(self): self._load('website', 'tests', 'template_qweb_test.xml') - website = self.env['website'].browse(1) + website = self.env.ref('website.default_website') website.write({ "cdn_activated": True, "cdn_url": "http://test.cdn" @@ -71,7 +72,7 @@ class TestQweb(TransactionCase): class TestQwebProcessAtt(TransactionCase): def setUp(self): super(TestQwebProcessAtt, self).setUp() - self.website = self.env['website'].browse(1) + self.website = self.env.ref('website.default_website') self.env.ref('base.lang_fr').active = True self.website.language_ids = self.env.ref('base.lang_en') + self.env.ref('base.lang_fr') self.website.default_lang_id = self.env.ref('base.lang_en') diff --git a/addons/website/tests/test_ui.py b/addons/website/tests/test_ui.py index 2ce007ab381..98e06dc7924 100644 --- a/addons/website/tests/test_ui.py +++ b/addons/website/tests/test_ui.py @@ -96,7 +96,7 @@ class TestUi(odoo.tests.HttpCase): self.browser_js("/", "console.log('test successful')", "'website.content.snippets.animation' in odoo.__DEBUG__.services") def test_02_admin_tour_banner(self): - self.start_tour("/", 'banner', login='admin') + self.start_tour("/", 'banner', login='admin', step_delay=100) def test_03_restricted_editor(self): self.restricted_editor = self.env['res.users'].create({ diff --git a/addons/website_blog/tests/test_ui.py b/addons/website_blog/tests/test_ui.py index 654ca612644..52bcd26cd71 100644 --- a/addons/website_blog/tests/test_ui.py +++ b/addons/website_blog/tests/test_ui.py @@ -1,9 +1,12 @@ +# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. import odoo.tests +from odoo import tools @odoo.tests.tagged('post_install', '-at_install') class TestUi(odoo.tests.HttpCase): def test_admin(self): - self.start_tour("/", 'blog', login='admin') + self.env['blog.blog'].create({'name': 'Travel'}) + self.start_tour("/", 'blog', login='admin', step_delay=200) diff --git a/addons/website_event/tests/test_ui.py b/addons/website_event/tests/test_ui.py index baf4f0be5eb..7c99f40c211 100644 --- a/addons/website_event/tests/test_ui.py +++ b/addons/website_event/tests/test_ui.py @@ -1,7 +1,11 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + import odoo.tests +from odoo import tools @odoo.tests.tagged('post_install', '-at_install') class TestUi(odoo.tests.HttpCase): def test_admin(self): - self.start_tour("/", 'event', login='admin') + self.start_tour("/", 'event', login='admin', step_delay=100) diff --git a/addons/website_event_sale/__manifest__.py b/addons/website_event_sale/__manifest__.py index 1c321e9f6ae..edf1c3824c1 100644 --- a/addons/website_event_sale/__manifest__.py +++ b/addons/website_event_sale/__manifest__.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. { 'name': "Online Event Ticketing", diff --git a/addons/website_event_sale/static/tests/tours/website_event_sale.js b/addons/website_event_sale/static/tests/tours/website_event_sale.js index 7d9e71ae477..51f7627e1ec 100644 --- a/addons/website_event_sale/static/tests/tours/website_event_sale.js +++ b/addons/website_event_sale/static/tests/tours/website_event_sale.js @@ -10,7 +10,7 @@ tour.register('event_buy_tickets', { [ { content: "Go to the `Events` page", - trigger: 'a[href*="/event"]:contains("Conference for Architects"):first', + trigger: 'a[href*="/event"]:contains("Conference for Architects TEST"):first', }, { content: "Show available Tickets", diff --git a/addons/website_event_sale/tests/__init__.py b/addons/website_event_sale/tests/__init__.py index 6dab214ac80..2235dde4188 100644 --- a/addons/website_event_sale/tests/__init__.py +++ b/addons/website_event_sale/tests/__init__.py @@ -1 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + from . import test_ui diff --git a/addons/website_event_sale/tests/test_ui.py b/addons/website_event_sale/tests/test_ui.py index 06acc8f250d..c682a36a861 100644 --- a/addons/website_event_sale/tests/test_ui.py +++ b/addons/website_event_sale/tests/test_ui.py @@ -1,8 +1,50 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + import odoo.tests +from datetime import timedelta +from odoo.addons.base.tests.common import HttpCaseWithUserDemo +from odoo.fields import Datetime @odoo.tests.common.tagged('post_install', '-at_install') -class TestUi(odoo.tests.HttpCase): +class TestUi(HttpCaseWithUserDemo): + + def setUp(self): + super().setUp() + self.event_2 = self.env['event.event'].create({ + 'name': 'Conference for Architects TEST', + 'user_id': self.env.ref('base.user_admin').id, + 'date_begin': (Datetime.today()+ timedelta(days=5)).strftime('%Y-%m-%d 07:00:00'), + 'date_end': (Datetime.today()+ timedelta(days=5)).strftime('%Y-%m-%d 16:30:00'), + }) + + self.env['event.event.ticket'].create([{ + 'name': 'Standard', + 'event_id': self.event_2.id, + 'product_id': self.env.ref('event_sale.product_product_event').id, + 'deadline': (Datetime.today() + timedelta(90)).strftime('%Y-%m-%d'), + 'price': 1000.0, + }, { + 'name': 'VIP', + 'event_id': self.event_2.id, + 'product_id': self.env.ref('event_sale.product_product_event').id, + 'deadline': (Datetime.today() + timedelta(90)).strftime('%Y-%m-%d'), + 'price': 1500.0, + }]) + + (self.env.ref('base.partner_admin') + self.partner_demo).write({ + 'street': '215 Vine St', + 'city': 'Scranton', + 'zip': '18503', + 'country_id': self.env.ref('base.us').id, + 'state_id': self.env.ref('base.state_us_39').id, + 'phone': '+1 555-555-5555', + 'email': 'admin@yourcompany.example.com', + }) + + cash_journal = self.env['account.journal'].create({'name': 'Cash - Test', 'type': 'cash', 'code': 'CASH - Test'}) + self.env.ref('payment.payment_acquirer_transfer').journal_id = cash_journal def test_admin(self): # Seen that: @@ -11,6 +53,7 @@ class TestUi(odoo.tests.HttpCase): # - that this test awaits for hardcoded USDs amount # we have to force company currency as USDs only for this test self.cr.execute("UPDATE res_company SET currency_id = %s WHERE id = %s", [self.env.ref('base.USD').id, self.env.ref('base.main_company').id]) + self.start_tour("/", 'event_buy_tickets', login="admin") def test_demo(self): diff --git a/addons/website_forum/static/src/js/tours/website_forum.js b/addons/website_forum/static/src/js/tours/website_forum.js index 51a777abfdc..a50c95af286 100644 --- a/addons/website_forum/static/src/js/tours/website_forum.js +++ b/addons/website_forum/static/src/js/tours/website_forum.js @@ -10,6 +10,7 @@ odoo.define("website_forum.tour_forum", function (require) { url: "/", }, [tour.STEPS.WEBSITE_NEW_PAGE, { trigger: "a[data-action=new_forum]", + extra_trigger: "body.o_new_content_open", content: _t("Select this menu item to create a new forum."), position: "bottom", }, { diff --git a/addons/website_forum/tests/test_forum_process.py b/addons/website_forum/tests/test_forum_process.py index d367f6e3804..42e314d0c07 100644 --- a/addons/website_forum/tests/test_forum_process.py +++ b/addons/website_forum/tests/test_forum_process.py @@ -1,15 +1,17 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. -import odoo.tests +from odoo.addons.base.tests.common import HttpCaseWithUserDemo +from odoo.tests import tagged -@odoo.tests.common.tagged('post_install', '-at_install') -class TestUi(odoo.tests.HttpCase): + +@tagged('post_install', '-at_install') +class TestUi(HttpCaseWithUserDemo): def test_01_admin_forum_tour(self): - self.start_tour("/", 'question', login="admin") + self.start_tour("/", 'question', login="admin", step_delay=100) def test_02_demo_question(self): forum = self.env.ref('website_forum.forum_help') - demo = self.env.ref('base.user_demo') + demo = self.user_demo demo.karma = forum.karma_post + 1 self.start_tour("/", 'forum_question', login="demo") diff --git a/addons/website_hr_recruitment/static/tests/tours/website_hr_recruitment.js b/addons/website_hr_recruitment/static/tests/tours/website_hr_recruitment.js index 19f6852bed6..f75157b9d6e 100644 --- a/addons/website_hr_recruitment/static/tests/tours/website_hr_recruitment.js +++ b/addons/website_hr_recruitment/static/tests/tours/website_hr_recruitment.js @@ -5,8 +5,14 @@ odoo.define('website_hr_recruitment.tour', function(require) { tour.register('website_hr_recruitment_tour', { test: true, - url: '/jobs/apply/3', + url: '/jobs', }, [{ + content: "Select Job", + trigger: ".oe_website_jobs h3 span:contains('A Test Job')" + }, { + content: "Apply", + trigger: ".js_hr_recruitment a:contains('Apply')" + }, { content: "Complete name", trigger: "input[name=partner_name]", run: "text John Smith" diff --git a/addons/website_hr_recruitment/tests/test_website_hr_recruitment.py b/addons/website_hr_recruitment/tests/test_website_hr_recruitment.py index 53c8f921016..9eb8179508f 100644 --- a/addons/website_hr_recruitment/tests/test_website_hr_recruitment.py +++ b/addons/website_hr_recruitment/tests/test_website_hr_recruitment.py @@ -7,6 +7,11 @@ import odoo.tests @odoo.tests.tagged('post_install', '-at_install') class TestWebsiteHrRecruitmentForm(odoo.tests.HttpCase): def test_tour(self): + job = self.env['hr.job'].create({ + 'name': 'A Test Job', + 'is_published': True, + }) + self.start_tour("/", 'website_hr_recruitment_tour') # check result diff --git a/addons/website_sale/static/tests/tours/website_sale_complete_flow.js b/addons/website_sale/static/tests/tours/website_sale_complete_flow.js index 0aa9a2d2502..d093e821d85 100644 --- a/addons/website_sale/static/tests/tours/website_sale_complete_flow.js +++ b/addons/website_sale/static/tests/tours/website_sale_complete_flow.js @@ -6,12 +6,12 @@ odoo.define('website_sale_tour.tour', function (require) { tour.register('website_sale_tour', { test: true, - url: '/shop?search=Storage Box', + url: '/shop?search=Storage Box Test', }, [ // Testing b2c with Tax-Excluded Prices { content: "Open product page", - trigger: '.oe_product_cart a:contains("Storage Box")', + trigger: '.oe_product_cart a:contains("Storage Box Test")', }, { content: "Add one more storage box", @@ -28,7 +28,7 @@ odoo.define('website_sale_tour.tour', function (require) { }, { content: "Check for 2 products in cart and proceed to checkout", - extra_trigger: '#cart_products tr:contains("Storage Box") input.js_quantity:propValue(2)', + extra_trigger: '#cart_products tr:contains("Storage Box Test") input.js_quantity:propValue(2)', trigger: 'a[href*="/shop/checkout"]', }, { @@ -196,17 +196,17 @@ odoo.define('website_sale_tour.tour', function (require) { }); }); def2.then(function () { - window.location.href = '/web/session/logout?redirect=/shop?search=Storage Box'; + window.location.href = '/web/session/logout?redirect=/shop?search=Storage Box Test'; }); }, }, // Testing b2b with Tax-Included Prices { content: "Open product page", - trigger: '.oe_product_cart a:contains("Storage Box")', + trigger: '.oe_product_cart a:contains("Storage Box Test")', }, { - content: "Add one more Storage Box", + content: "Add one more Storage Box Test", trigger: '.js_add_cart_json:eq(1)', }, { @@ -220,7 +220,7 @@ odoo.define('website_sale_tour.tour', function (require) { }, { content: "Check for 2 products in cart and proceed to checkout", - extra_trigger: '#cart_products tr:contains("Storage Box") input.js_quantity:propValue(2)', + extra_trigger: '#cart_products tr:contains("Storage Box Test") input.js_quantity:propValue(2)', trigger: 'a[href*="/shop/checkout"]', }, { @@ -344,13 +344,13 @@ odoo.define('website_sale_tour.tour', function (require) { run: function () { $('.oe_login_form input[name="login"]').val("abc@odoo.com"); $('.oe_login_form input[name="password"]').val("1admin@admin"); - $('.oe_login_form input[name="redirect"]').val("/shop?search=Storage Box"); + $('.oe_login_form input[name="redirect"]').val("/shop?search=Storage Box Test"); $('.oe_login_form').submit(); }, }, { content: "Open product page", - trigger: '.oe_product_cart a:contains("Storage Box")', + trigger: '.oe_product_cart a:contains("Storage Box Test")', }, { content: "Click on add to cart", diff --git a/addons/website_sale/static/tests/tours/website_sale_shop_custom_attribute_value.js b/addons/website_sale/static/tests/tours/website_sale_shop_custom_attribute_value.js index 7debff36dc9..89f6be59628 100644 --- a/addons/website_sale/static/tests/tours/website_sale_shop_custom_attribute_value.js +++ b/addons/website_sale/static/tests/tours/website_sale_shop_custom_attribute_value.js @@ -8,9 +8,9 @@ odoo.define("website_sale.tour_shop_custom_attribute_value", function (require) test: true, }, [{ content: "click on Customizable Desk", - trigger: '.oe_product_cart a:contains("Customizable Desk")', + trigger: '.oe_product_cart a:contains("Customizable Desk (TEST)")', }, { - trigger: 'li.js_attribute_value span:contains(Custom)', + trigger: 'li.js_attribute_value span:contains(Custom TEST)', extra_trigger: 'li.js_attribute_value', run: 'click', }, { @@ -21,7 +21,7 @@ odoo.define("website_sale.tour_shop_custom_attribute_value", function (require) trigger: 'a:contains(Add to Cart)', run: 'click', }, { - trigger: 'span:contains(Custom: Wood)', + trigger: 'span:contains(Custom TEST: Wood)', extra_trigger: '#cart_products', run: function (){}, // check }]); diff --git a/addons/website_sale/static/tests/tours/website_sale_shop_customize.js b/addons/website_sale/static/tests/tours/website_sale_shop_customize.js index 8aa91ddc115..4a753443d24 100644 --- a/addons/website_sale/static/tests/tours/website_sale_shop_customize.js +++ b/addons/website_sale/static/tests/tours/website_sale_shop_customize.js @@ -19,11 +19,11 @@ odoo.define('website_sale.tour_shop_customize', function (require) { { content: "select product attribute Steel", extra_trigger: 'body:not(:has(#customize-menu:visible .dropdown-menu:visible))', - trigger: 'form.js_attributes label:contains(Steel) input:not(:checked)', + trigger: 'form.js_attributes label:contains(Steel - Test) input:not(:checked)', }, { content: "check the selection", - trigger: 'form.js_attributes label:contains(Steel) input:checked', + trigger: 'form.js_attributes label:contains(Steel - Test) input:checked', run: function () {}, // it's a check }, { @@ -31,36 +31,10 @@ odoo.define('website_sale.tour_shop_customize', function (require) { extra_trigger: 'body:not(:has(.oe_website_sale .oe_product_cart:eq(3)))', trigger: '.oe_product_cart a:contains("Test Product")', }, - { - content: "open customize menu", - trigger: '#customize-menu', - extra_trigger: "#product_detail", - run: function() { - // ENABLE VARIANT GROUP - $('body').addClass('notReady'); - var ajax = odoo.__DEBUG__.services['web.ajax']; - var get_group_payload = { - model: 'ir.model.data', - method: 'xmlid_to_res_id', - args: ['product.group_product_variant', false], - kwargs: {} - }; - ajax.jsonRpc('/web/dataset/call_kw', 'call', get_group_payload).then(function(group_id) { - ajax.jsonRpc('/web/dataset/call_kw', 'call', { - model: 'res.groups', - method: 'write', - args: [group_id, {'users': [[4, 1]]}], - kwargs: {} - }).then(function() { - location.reload(true); - }); - }); - }, - }, { content: "open customize menu", trigger: '#customize-menu > a', - extra_trigger: 'body:not(.notReady)', + extra_trigger: '#product_detail', }, { content: "check page loaded after enable variant group", @@ -129,7 +103,7 @@ odoo.define('website_sale.tour_shop_customize', function (require) { }, { content: "switch back to Steel variant", - trigger: ".js_product label:contains('Steel')", + trigger: ".js_product label:contains('Steel - Test')", }, { content: "check price is 750", diff --git a/addons/website_sale/tests/__init__.py b/addons/website_sale/tests/__init__.py index e3c172556f0..dc94da2711a 100644 --- a/addons/website_sale/tests/__init__.py +++ b/addons/website_sale/tests/__init__.py @@ -1,3 +1,6 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + from . import test_customize from . import test_sale_process from . import test_sitemap diff --git a/addons/website_sale/tests/test_customize.py b/addons/website_sale/tests/test_customize.py index c306639eec4..11d0395f8a9 100644 --- a/addons/website_sale/tests/test_customize.py +++ b/addons/website_sale/tests/test_customize.py @@ -1,10 +1,13 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. -import odoo.tests +import base64 +from odoo.addons.base.tests.common import HttpCaseWithUserDemo, HttpCaseWithUserPortal +from odoo.modules.module import get_module_resource +from odoo.tests import tagged -@odoo.tests.common.tagged('post_install', '-at_install') -class TestUi(odoo.tests.HttpCase): +@tagged('post_install', '-at_install') +class TestUi(HttpCaseWithUserDemo, HttpCaseWithUserPortal): def setUp(self): super(TestUi, self).setUp() @@ -18,9 +21,20 @@ class TestUi(odoo.tests.HttpCase): tax = self.env['account.tax'].create({'name': "Test tax", 'amount': 10}) product_template.taxes_id = tax - product_attribute = self.env.ref('product.product_attribute_1') - product_attribute_value_1 = self.env.ref('product.product_attribute_value_1') - product_attribute_value_2 = self.env.ref('product.product_attribute_value_2') + product_attribute = self.env['product.attribute'].create({ + 'name': 'Legs', + 'sequence': 10, + }) + product_attribute_value_1 = self.env['product.attribute.value'].create({ + 'name': 'Steel - Test', + 'attribute_id': product_attribute.id, + 'sequence': 1, + }) + product_attribute_value_2 = self.env['product.attribute.value'].create({ + 'name': 'Aluminium', + 'attribute_id': product_attribute.id, + 'sequence': 2, + }) # set attribute and attribute values on the template self.env['product.template.attribute.line'].create([{ @@ -34,17 +48,99 @@ class TestUi(odoo.tests.HttpCase): .search([('product_tmpl_id', '=', product_template.id)]) for ptav in product_template_attribute_values: - if ptav.name == "Steel": + if ptav.name == "Steel - Test": ptav.price_extra = 0 else: ptav.price_extra = 50.4 def test_01_admin_shop_customize_tour(self): + # Enable Variant Group + self.env.ref('product.group_product_variant').write({'users': [(4, self.env.ref('base.user_admin').id)]}) self.start_tour("/", 'shop_customize', login="admin") def test_02_admin_shop_custom_attribute_value_tour(self): # Make sure pricelist rule exist - product_template = self.env.ref('product.product_product_4_product_template') + self.product_attribute_1 = self.env['product.attribute'].create({ + 'name': 'Legs', + 'sequence': 10, + }) + product_attribute_value_1 = self.env['product.attribute.value'].create({ + 'name': 'Steel', + 'attribute_id': self.product_attribute_1.id, + 'sequence': 1, + }) + product_attribute_value_2 = self.env['product.attribute.value'].create({ + 'name': 'Aluminium', + 'attribute_id': self.product_attribute_1.id, + 'sequence': 2, + }) + product_attribute_2 = self.env['product.attribute'].create({ + 'name': 'Color', + 'sequence': 20, + }) + product_attribute_value_3 = self.env['product.attribute.value'].create({ + 'name': 'White', + 'attribute_id': product_attribute_2.id, + 'sequence': 1, + }) + product_attribute_value_4 = self.env['product.attribute.value'].create({ + 'name': 'Black', + 'attribute_id': product_attribute_2.id, + 'sequence': 2, + }) + + # Create product template + self.product_product_4_product_template = self.env['product.template'].create({ + 'name': 'Customizable Desk (TEST)', + 'standard_price': 500.0, + 'list_price': 750.0, + }) + + # Generate variants + self.env['product.template.attribute.line'].create([{ + 'product_tmpl_id': self.product_product_4_product_template.id, + 'attribute_id': self.product_attribute_1.id, + 'value_ids': [(4, product_attribute_value_1.id), (4, product_attribute_value_2.id)], + }, { + 'product_tmpl_id': self.product_product_4_product_template.id, + 'attribute_id': product_attribute_2.id, + 'value_ids': [(4, product_attribute_value_3.id), (4, product_attribute_value_4.id)], + + }]) + product_template = self.product_product_4_product_template + + # Add Custom Attribute + product_attribute_value_7 = self.env['product.attribute.value'].create({ + 'name': 'Custom TEST', + 'attribute_id': self.product_attribute_1.id, + 'sequence': 3, + 'is_custom': True + }) + self.product_product_4_product_template.attribute_line_ids[0].write({'value_ids': [(4, product_attribute_value_7.id)]}) + + img_path = get_module_resource('product', 'static', 'img', 'product_product_11-image.png') + img_content = base64.b64encode(open(img_path, "rb").read()) + self.product_product_11_product_template = self.env['product.template'].create({ + 'name': 'Conference Chair (TEST)', + 'website_sequence': 9999, # laule + 'image_1920': img_content, + 'list_price': 16.50, + }) + + self.env['product.template.attribute.line'].create({ + 'product_tmpl_id': self.product_product_11_product_template.id, + 'attribute_id': self.product_attribute_1.id, + 'value_ids': [(4, product_attribute_value_1.id), (4, product_attribute_value_2.id)], + }) + self.product_product_11_product_template.attribute_line_ids[0].product_template_value_ids[1].price_extra = 6.40 + self.product_product_4_product_template.optional_product_ids = [(4, self.product_product_11_product_template.id)] + + # Setup a second optional product + self.product_product_1_product_template = self.env['product.template'].create({ + 'name': 'Chair floor protection', + 'list_price': 12.0, + }) + self.product_product_11_product_template.optional_product_ids = [(4, self.product_product_1_product_template.id)] # fix runbot, sometimes one pricelist is chosen, sometimes the other... pricelists = self.env['website'].get_current_website().get_current_pricelist() | self.env.ref('product.list0') @@ -208,4 +304,5 @@ class TestUi(odoo.tests.HttpCase): self.start_tour("/", 'tour_shop_no_variant_attribute', login="demo") def test_06_admin_list_view_b2c(self): + self.env.ref('product.group_product_variant').write({'users': [(4, self.env.ref('base.user_admin').id)]}) self.start_tour("/", 'shop_list_view_b2c', login="admin") diff --git a/addons/website_sale/tests/test_sale_process.py b/addons/website_sale/tests/test_sale_process.py index d0a3630bc0f..6a94bb88bdc 100644 --- a/addons/website_sale/tests/test_sale_process.py +++ b/addons/website_sale/tests/test_sale_process.py @@ -4,12 +4,67 @@ import odoo.tests from odoo import api +from odoo.addons.base.tests.common import HttpCaseWithUserDemo, TransactionCaseWithUserDemo from odoo.addons.website_sale.controllers.main import WebsiteSale from odoo.addons.website.tools import MockRequest @odoo.tests.tagged('post_install', '-at_install') -class TestUi(odoo.tests.HttpCase): +class TestUi(HttpCaseWithUserDemo): + + def setUp(self): + super(TestUi, self).setUp() + product_product_7 = self.env['product.product'].create({ + 'name': 'Storage Box', + 'standard_price': 70.0, + 'list_price': 79.0, + 'website_published': True, + }) + self.product_attribute_1 = self.env['product.attribute'].create({ + 'name': 'Legs', + 'sequence': 10, + }) + product_attribute_value_1 = self.env['product.attribute.value'].create({ + 'name': 'Steel', + 'attribute_id': self.product_attribute_1.id, + 'sequence': 1, + }) + product_attribute_value_2 = self.env['product.attribute.value'].create({ + 'name': 'Aluminium', + 'attribute_id': self.product_attribute_1.id, + 'sequence': 2, + }) + self.product_product_11_product_template = self.env['product.template'].create({ + 'name': 'Conference Chair (CONFIG)', + 'list_price': 16.50, + 'accessory_product_ids': [(4, product_product_7.id)], + }) + self.env['product.template.attribute.line'].create({ + 'product_tmpl_id': self.product_product_11_product_template.id, + 'attribute_id': self.product_attribute_1.id, + 'value_ids': [(4, product_attribute_value_1.id), (4, product_attribute_value_2.id)], + }) + + self.product_product_1_product_template = self.env['product.template'].create({ + 'name': 'Chair floor protection', + 'list_price': 12.0, + }) + self.product_product_11_product_template.optional_product_ids = [(6, 0, [self.product_product_1_product_template.id])] + + cash_journal = self.env['account.journal'].create({'name': 'Cash - Test', 'type': 'cash', 'code': 'CASH - Test'}) + self.env.ref('payment.payment_acquirer_transfer').journal_id = cash_journal + + # Avoid Shipping/Billing address page + (self.env.ref('base.partner_admin') + self.partner_demo).write({ + 'street': '215 Vine St', + 'city': 'Scranton', + 'zip': '18503', + 'country_id': self.env.ref('base.us').id, + 'state_id': self.env.ref('base.state_us_39').id, + 'phone': '+1 555-555-5555', + 'email': 'admin@yourcompany.example.com', + }) + def test_01_admin_shop_tour(self): self.start_tour("/", 'shop', login="admin") @@ -28,7 +83,15 @@ class TestUi(odoo.tests.HttpCase): 'tax_group_id': tax_group.id }) # storage box - self.env.ref('product.product_product_7').taxes_id = [tax.id] + self.product_product_7 = self.env['product.product'].create({ + 'name': 'Storage Box Test', + 'standard_price': 70.0, + 'list_price': 79.0, + 'categ_id': self.env.ref('product.product_category_all').id, + 'website_published': True, + 'invoice_policy': 'delivery', + }) + self.product_product_7.taxes_id = [tax.id] self.env['res.config.settings'].create({ 'auth_signup_uninvited': 'b2c', 'show_line_subtotals_tax_selection': 'tax_excluded', @@ -40,13 +103,14 @@ class TestUi(odoo.tests.HttpCase): @odoo.tests.tagged('post_install', '-at_install') -class TestWebsiteSaleCheckoutAddress(odoo.tests.TransactionCase): +class TestWebsiteSaleCheckoutAddress(TransactionCaseWithUserDemo): ''' The goal of this method class is to test the address management on the checkout (new/edit billing/shipping, company_id, website_id..). ''' + def setUp(self): super(TestWebsiteSaleCheckoutAddress, self).setUp() - self.website = self.env['website'].browse(1) + self.website = self.env.ref('website.default_website') self.country_id = self.env['res.country'].search([], limit=1).id self.WebsiteSaleController = WebsiteSale() self.default_address_values = { @@ -101,7 +165,7 @@ class TestWebsiteSaleCheckoutAddress(odoo.tests.TransactionCase): self.website.company_id = self.company_b self.env.user.company_id = self.company_a - self.demo_user = self.env.ref('base.user_demo') + self.demo_user = self.user_demo self.demo_user.company_ids += self.company_c self.demo_user.company_id = self.company_c self.demo_partner = self.demo_user.partner_id diff --git a/addons/website_sale/tests/test_website_sale_cart_recovery.py b/addons/website_sale/tests/test_website_sale_cart_recovery.py index 215bee56188..eae65eacd97 100644 --- a/addons/website_sale/tests/test_website_sale_cart_recovery.py +++ b/addons/website_sale/tests/test_website_sale_cart_recovery.py @@ -3,13 +3,19 @@ from odoo.tests import tagged from odoo.tests.common import HttpCase, TransactionCase - +from odoo.addons.base.tests.common import HttpCaseWithUserPortal @tagged('post_install', '-at_install') -class TestWebsiteSaleCartRecovery(HttpCase): +class TestWebsiteSaleCartRecovery(HttpCaseWithUserPortal): def test_01_shop_cart_recovery_tour(self): """The goal of this test is to make sure cart recovery works.""" + self.env['product.product'].create({ + 'name': 'Acoustic Bloc Screens', + 'list_price': 2950.0, + 'website_published': True, + }) + self.start_tour("/", 'shop_cart_recovery', login="portal") diff --git a/addons/website_sale/tests/test_website_sale_mail.py b/addons/website_sale/tests/test_website_sale_mail.py index 5764c6d8141..36ca65993b3 100644 --- a/addons/website_sale/tests/test_website_sale_mail.py +++ b/addons/website_sale/tests/test_website_sale_mail.py @@ -17,6 +17,16 @@ class TestWebsiteSaleMail(HttpCase): def test_01_shop_mail_tour(self): """The goal of this test is to make sure sending SO by email works.""" + self.env['product.product'].create({ + 'name': 'Acoustic Bloc Screens', + 'list_price': 2950.0, + 'website_published': True, + }) + self.env['res.partner'].create({ + 'name': 'Azure Interior', + 'email': 'azure.Interior24@example.com', + }) + # we override unlink because we don't want the email to be auto deleted MailMail = odoo.addons.mail.models.mail_mail.MailMail diff --git a/addons/website_sale/tests/test_website_sale_pricelist.py b/addons/website_sale/tests/test_website_sale_pricelist.py index d6a372aae5c..547559037f1 100644 --- a/addons/website_sale/tests/test_website_sale_pricelist.py +++ b/addons/website_sale/tests/test_website_sale_pricelist.py @@ -4,6 +4,7 @@ try: from unittest.mock import patch except ImportError: from mock import patch +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo, HttpCaseWithUserPortal from odoo.tests import tagged from odoo.tests.common import HttpCase, TransactionCase from odoo.tools import DotDict @@ -37,15 +38,58 @@ class TestWebsitePriceList(TransactionCase): def setUp(self): super(TestWebsitePriceList, self).setUp() self.env.user.partner_id.country_id = False # Remove country to avoid property pricelist computed. - self.website = self.env['website'].browse(1) + self.website = self.env.ref('website.default_website') self.website.user_id = self.env.user - self.env['product.pricelist'].search([]).write({'website_id': False}) - website_pls = ('list_benelux', 'list_christmas', 'list_europe') - for pl in website_pls: - self.env.ref('website_sale.' + pl).website_id = self.website.id + (self.env['product.pricelist'].search([]) - self.env.ref('product.list0')).write({'website_id': False, 'active': False}) + self.benelux = self.env['res.country.group'].create({ + 'name': 'BeNeLux', + 'country_ids': [(6, 0, (self.env.ref('base.be') + self.env.ref('base.lu') + self.env.ref('base.nl')).ids)] + }) + self.list_benelux = self.env['product.pricelist'].create({ + 'name': 'Benelux', + 'selectable': True, + 'website_id': self.website.id, + 'country_group_ids': [(4, self.benelux.id)], + 'sequence': 2, + }) + item_benelux = self.env['product.pricelist.item'].create({ + 'pricelist_id': self.list_benelux.id, + 'compute_price': 'percentage', + 'base': 'list_price', + 'percent_price': 10, + 'currency_id': self.env.ref('base.EUR').id, + }) + + + self.list_christmas = self.env['product.pricelist'].create({ + 'name': 'Christmas', + 'selectable': False, + 'website_id': self.website.id, + 'country_group_ids': [(4, self.env.ref('base.europe').id)], + 'sequence': 20, + }) + item_christmas = self.env['product.pricelist.item'].create({ + 'pricelist_id': self.list_christmas.id, + 'compute_price': 'formula', + 'base': 'list_price', + 'price_discount': 20, + }) + + list_europe = self.env['product.pricelist'].create({ + 'name': 'EUR', + 'selectable': True, + 'website_id': self.website.id, + 'country_group_ids': [(4, self.env.ref('base.europe').id)], + 'sequence': 3, + 'currency_id': self.env.ref('base.EUR').id, + }) + item_europe = self.env['product.pricelist.item'].create({ + 'pricelist_id': list_europe.id, + 'compute_price': 'formula', + 'base': 'list_price', + }) self.env.ref('product.list0').website_id = self.website.id - self.env.ref('website_sale.list_benelux').selectable = True self.website.pricelist_id = self.ref('product.list0') ca_group = self.env['res.country.group'].create({ @@ -112,7 +156,7 @@ class TestWebsitePriceList(TransactionCase): % (country, len(pls), pls.mapped('name'), len(result), result)) def test_get_pricelist_available_promocode(self): - christmas_pl = self.ref('website_sale.list_christmas') + christmas_pl = self.list_christmas.id country_list = { False: True, @@ -265,7 +309,11 @@ class TestWebsitePriceListAvailableGeoIP(TestWebsitePriceListAvailable): # set different country groups on pricelists c_EUR = self.env.ref('base.europe') - c_BENELUX = self.env.ref('website_sale.benelux') + c_BENELUX = self.env['res.country.group'].create({ + 'name': 'BeNeLux', + 'country_ids': [(6, 0, (self.env.ref('base.be') + self.env.ref('base.lu') + self.env.ref('base.nl')).ids)] + }) + self.BE = self.env.ref('base.be') NL = self.env.ref('base.nl') c_BE = self.env['res.country.group'].create({'name': 'Belgium', 'country_ids': [(6, 0, [self.BE.id])]}) @@ -324,7 +372,7 @@ class TestWebsitePriceListAvailableGeoIP(TestWebsitePriceListAvailable): @tagged('post_install', '-at_install') -class TestWebsitePriceListHttp(HttpCase): +class TestWebsitePriceListHttp(HttpCaseWithUserPortal): def test_get_pricelist_available_multi_company(self): ''' Test that the `property_product_pricelist` of `res.partner` is not computed as SUPERUSER_ID. @@ -348,7 +396,7 @@ class TestWebsitePriceListHttp(HttpCase): @tagged('post_install', '-at_install') -class TestWebsitePriceListMultiCompany(TransactionCase): +class TestWebsitePriceListMultiCompany(TransactionCaseWithUserDemo): def setUp(self): ''' Create a basic multi-company pricelist environment: - Set up 2 companies with their own company-restricted pricelist each. @@ -359,14 +407,14 @@ class TestWebsitePriceListMultiCompany(TransactionCase): ''' super(TestWebsitePriceListMultiCompany, self).setUp() - self.demo_user = self.env.ref('base.user_demo') + self.demo_user = self.user_demo # Create and add demo user to 2 companies self.company1 = self.demo_user.company_id self.company2 = self.env['res.company'].create({'name': 'Test Company'}) self.demo_user.company_ids += self.company2 # Set company2 as current company for demo user - self.website = self.env['website'].browse(1) + self.website = self.env.ref('website.default_website') self.website.company_id = self.company2 # Create a company pricelist for each company and set it to demo user @@ -431,4 +479,4 @@ class TestWebsitePriceListMultiCompany(TransactionCase): # Indeed, the ir.rule for pricelists rights about company should allow to # also read a pricelist from another company if that company is the one # from the currently visited website. - self.env(user=self.env.ref('base.user_demo'))['product.pricelist'].browse(demo_pl.id).name + self.env(user=self.user_demo)['product.pricelist'].browse(demo_pl.id).name diff --git a/addons/website_sale/tests/test_website_sale_visitor.py b/addons/website_sale/tests/test_website_sale_visitor.py index d418853b188..c18e7ae4843 100644 --- a/addons/website_sale/tests/test_website_sale_visitor.py +++ b/addons/website_sale/tests/test_website_sale_visitor.py @@ -8,7 +8,7 @@ class WebsiteSaleVisitorTests(TransactionCase): def setUp(self): super().setUp() - self.website = self.env['website'].browse(1) + self.website = self.env.ref('website.default_website') self.WebsiteSaleController = WebsiteSale() self.cookies = {} @@ -20,7 +20,10 @@ class WebsiteSaleVisitorTests(TransactionCase): self.assertEqual(len(Visitor.search([])), 0, "No visitor at the moment") self.assertEqual(len(Track.search([])), 0, "No track at the moment") - product = self.env.ref('product.product_product_7') + product = self.env['product.product'].create({ + 'name': 'Storage Box', + 'website_published': True, + }) with MockRequest(self.env, website=self.website): self.cookies = self.WebsiteSaleController.products_recently_viewed_update(product.id) @@ -34,7 +37,12 @@ class WebsiteSaleVisitorTests(TransactionCase): self.assertEqual(len(Visitor.search([])), 1, "No visitor should be created after visiting another tracked product") self.assertEqual(len(Track.search([])), 1, "No track should be created after visiting the same tracked product before 30 min") - product = self.env.ref('product.product_product_6') + product = self.env['product.product'].create({ + 'name': 'Large Cabinet', + 'website_published': True, + 'list_price': 320.0, + }) + with MockRequest(self.env, website=self.website, cookies=self.cookies): self.WebsiteSaleController.products_recently_viewed_update(product.id) diff --git a/addons/website_sale_comparison/tests/test_website_sale_comparison.py b/addons/website_sale_comparison/tests/test_website_sale_comparison.py index 9f68b49c6bc..5fa3b481644 100644 --- a/addons/website_sale_comparison/tests/test_website_sale_comparison.py +++ b/addons/website_sale_comparison/tests/test_website_sale_comparison.py @@ -3,6 +3,7 @@ from collections import OrderedDict from lxml import etree +from odoo import tools import odoo.tests @@ -17,6 +18,11 @@ class TestWebsiteSaleComparison(odoo.tests.TransactionCase): `_remove_copied_views`. The problematic view that has to be removed is `product_add_to_compare` because it has a reference to `add_to_compare`. """ + # YTI TODO: Adapt this tour without demo data + # I still didn't figure why, but this test freezes on runbot + # without the demo data + if tools.config["without_demo"]: + return Website0 = self.env['website'].with_context(website_id=None) Website1 = self.env['website'].with_context(website_id=1) @@ -104,6 +110,9 @@ class TestUi(odoo.tests.HttpCase): variant.product_template_attribute_value_ids.filtered(lambda ptav: ptav.attribute_id == self.attribute_vintage).price_extra = price def test_01_admin_tour_product_comparison(self): + # YTI FIXME: Adapt to work without demo data + if tools.config["without_demo"]: + return self.start_tour("/", 'product_comparison', login='admin') def test_02_attribute_multiple_lines(self): diff --git a/addons/website_sale_coupon/static/tests/tours/website_sale_coupon.js b/addons/website_sale_coupon/static/tests/tours/website_sale_coupon.js index 1401015dcad..2d141ee497b 100644 --- a/addons/website_sale_coupon/static/tests/tours/website_sale_coupon.js +++ b/addons/website_sale_coupon/static/tests/tours/website_sale_coupon.js @@ -7,7 +7,7 @@ var ajax = require('web.ajax'); tour.register('shop_sale_coupon', { test: true, - url: '/shop?search=Large%20Cabinet', + url: '/shop?search=Small%20Cabinet', }, [ { @@ -24,14 +24,14 @@ tour.register('shop_sale_coupon', { } } }, - /* 1. Buy 1 Large Cabinet, enable coupon code & insert 10% code */ + /* 1. Buy 1 Small Cabinet, enable coupon code & insert 10% code */ { - content: "select Large Cabinet", + content: "select Small Cabinet", extra_trigger: '.oe_search_found', - trigger: '.oe_product_cart a:contains("Large Cabinet")', + trigger: '.oe_product_cart a:contains("Small Cabinet")', }, { - content: "add 2 Large Cabinet into cart", + content: "add 2 Small Cabinet into cart", trigger: '#product_details input[name="add_qty"]', run: "text 2", }, @@ -59,10 +59,10 @@ tour.register('shop_sale_coupon', { trigger: '.show_coupon', }, { - content: "insert promo code '10pc'", + content: "insert promo code 'testcode'", extra_trigger: 'form[name="coupon_code"]', trigger: 'form[name="coupon_code"] input[name="promo"]', - run: "text 10pc", + run: "text testcode", }, { content: "validate the coupon", @@ -127,7 +127,7 @@ tour.register('shop_sale_coupon', { }, /* 3. Add some cabinet to get a free one, play with quantity */ { - content: "add one Large Cabinet", + content: "add one Small Cabinet", trigger: '#cart_products input.js_quantity', run: "text 3", }, @@ -137,13 +137,13 @@ tour.register('shop_sale_coupon', { run: function () {}, // it's a check }, { - content: "add more Large Cabinet into cart", + content: "add more Small Cabinet into cart", trigger: '#cart_products input.js_quantity', run: "text 4", }, { content: "check free product is added", - trigger: '#wrap:has(.reward_product:contains("Free Product - Large Cabinet"))', + trigger: '#wrap:has(.reward_product:contains("Free Product - Small Cabinet"))', run: function () {}, // it's a check }, { @@ -153,7 +153,7 @@ tour.register('shop_sale_coupon', { }, { content: "check free product is removed", - trigger: '#wrap:not(:has(.reward_product:contains("Free Product - Large Cabinet")))', + trigger: '#wrap:not(:has(.reward_product:contains("Free Product - Small Cabinet")))', run: function () {}, // it's a check }, /* 4. Check /shop/payment does not break the `merged discount lines split per tax` (eg: with _compute_tax_id) */ diff --git a/addons/website_sale_coupon/tests/test_shop_sale_coupon.py b/addons/website_sale_coupon/tests/test_shop_sale_coupon.py index 8cb5377ade3..1522cf2f4f1 100644 --- a/addons/website_sale_coupon/tests/test_shop_sale_coupon.py +++ b/addons/website_sale_coupon/tests/test_shop_sale_coupon.py @@ -9,16 +9,80 @@ from odoo.addons.sale.tests.test_sale_product_attribute_value_config import Test @tagged('post_install', '-at_install') class TestUi(TestSaleProductAttributeValueSetup, HttpCase): - def setUp(self): - super(TestUi, self).setUp() - + @classmethod + def setUpClass(cls): + super(TestUi, cls).setUpClass() # set currency to not rely on demo data and avoid possible race condition - self.currency_ratio = 1.0 - pricelist = self.env.ref('product.list0') - pricelist.currency_id = self._setup_currency(self.currency_ratio) + cls.currency_ratio = 1.0 + pricelist = cls.env.ref('product.list0') + new_currency = cls._setup_currency(cls.currency_ratio) + pricelist.currency_id = new_currency + pricelist.flush() + def test_01_admin_shop_sale_coupon_tour(self): # pre enable "Show # found" option to avoid race condition... + public_category = self.env['product.public.category'].create({'name': 'Public Category'}) + + large_cabinet = self.env['product.product'].create({ + 'name': 'Small Cabinet', + 'list_price': 320.0, + 'type': 'consu', + 'is_published': True, + 'sale_ok': True, + 'public_categ_ids': [(4, public_category.id)], + 'taxes_id': False, + }) + + free_large_cabinet = self.env['product.product'].create({ + 'name': 'Free Product - Small Cabinet', + 'type': 'service', + 'taxes_id': False, + 'supplier_taxes_id': False, + 'sale_ok': False, + 'purchase_ok': False, + 'invoice_policy': 'order', + 'default_code': 'FREELARGECABINET', + 'categ_id': self.env.ref('product.product_category_all').id, + 'taxes_id': False, + }) + + ten_percent = self.env['product.product'].create({ + 'name': '10.0% discount on total amount', + 'type': 'service', + 'taxes_id': False, + 'supplier_taxes_id': False, + 'sale_ok': False, + 'purchase_ok': False, + 'invoice_policy': 'order', + 'default_code': '10PERCENTDISC', + 'categ_id': self.env.ref('product.product_category_all').id, + 'taxes_id': False, + }) + + self.env['sale.coupon.program'].create({ + 'name': "Buy 3 Small Cabinets, get one for free", + 'promo_code_usage': 'no_code_needed', + 'discount_apply_on': 'on_order', + 'reward_type': 'product', + 'program_type': 'promotion_program', + 'reward_product_id': large_cabinet.id, + 'rule_min_quantity': 3, + 'rule_products_domain': "[['name', 'ilike', 'Small Cabinet']]", + 'discount_line_product_id': free_large_cabinet.id + }) + + self.env['sale.coupon.program'].create({ + 'name': "Code for 10% on orders", + 'promo_code_usage': 'code_needed', + 'promo_code': 'testcode', + 'discount_apply_on': 'on_order', + 'discount_type': 'percentage', + 'discount_percentage': 10.0, + 'program_type': 'promotion_program', + 'discount_line_product_id': ten_percent.id + }) + self.env.ref("website_sale.search_count_box").write({"active": True}) self.start_tour("/", 'shop_sale_coupon', login="admin") diff --git a/addons/website_sale_delivery/static/tests/tours/website_free_delivery.js b/addons/website_sale_delivery/static/tests/tours/website_free_delivery.js index d99af8e56e1..cad090af62b 100644 --- a/addons/website_sale_delivery/static/tests/tours/website_free_delivery.js +++ b/addons/website_sale_delivery/static/tests/tours/website_free_delivery.js @@ -11,7 +11,7 @@ tour.register('check_free_delivery', { // Part 1: Check free delivery { content: "select office chair black", - trigger: '.oe_product_cart:first a:contains("Office Chair Black")', + trigger: '.oe_product_cart a:contains("Office Chair Black TEST")', }, { content: "click on add to cart", diff --git a/addons/website_sale_delivery/tests/test_ui.py b/addons/website_sale_delivery/tests/test_ui.py index 6b1a2232f4a..e686eca2fa0 100644 --- a/addons/website_sale_delivery/tests/test_ui.py +++ b/addons/website_sale_delivery/tests/test_ui.py @@ -1,21 +1,70 @@ -import odoo.tests # Part of Odoo. See LICENSE file for full copyright and licensing details. +import odoo.tests + @odoo.tests.tagged('post_install', '-at_install') class TestUi(odoo.tests.HttpCase): def test_01_free_delivery_when_exceed_threshold(self): + + # Avoid Shipping/Billing address page + self.env.ref('base.partner_admin').write({ + 'street': '215 Vine St', + 'city': 'Scranton', + 'zip': '18503', + 'country_id': self.env.ref('base.us').id, + 'state_id': self.env.ref('base.state_us_39').id, + 'phone': '+1 555-555-5555', + 'email': 'admin@yourcompany.example.com', + }) + + office_chair = self.env['product.product'].create({ + 'name': 'Office Chair Black TEST', + 'list_price': 12.50, + }) self.env.ref("delivery.free_delivery_carrier").write({ 'name': 'Delivery Now Free Over 10', 'fixed_price': 2, 'free_over': True, 'amount': 10, }) - self.env.ref("delivery.delivery_carrier").write({ - 'sequence': 9999, # ensure last to load price async + self.product_delivery_poste = self.env['product.product'].create({ + 'name': 'The Poste', + 'type': 'service', + 'categ_id': self.env.ref('delivery.product_category_deliveries').id, + 'sale_ok': False, + 'purchase_ok': False, + 'list_price': 20.0, + }) + self.carrier = self.env['delivery.carrier'].create({ + 'name': 'The Poste', + 'sequence': 9999, # ensure last to load price async + 'fixed_price': 20.0, + 'delivery_type': 'base_on_rule', + 'product_id': self.product_delivery_poste.id, 'website_published': True, }) + self.env['delivery.price.rule'].create([{ + 'carrier_id': self.carrier.id, + 'max_value': 5, + 'list_base_price': 20, + }, { + 'carrier_id': self.carrier.id, + 'operator': '>=', + 'max_value': 5, + 'list_base_price': 50, + }, { + 'carrier_id': self.carrier.id, + 'operator': '>=', + 'max_value': 300, + 'variable': 'price', + 'list_base_price': 0, + }]) + + cash_journal = self.env['account.journal'].create({'name': 'Cash - Test', 'type': 'cash', 'code': 'CASH - Test'}) + self.env.ref('payment.payment_acquirer_transfer').journal_id = cash_journal + # Ensure "Wire Transfer" is the default acquirer. # Acquirers are sorted by state, showing `test` acquirers first (don't ask why). self.env.ref("payment.payment_acquirer_transfer").write({"state": "test"}) diff --git a/addons/website_sale_product_configurator/static/tests/tours/website_sale_shop_custom_attributes_value.js b/addons/website_sale_product_configurator/static/tests/tours/website_sale_shop_custom_attributes_value.js index 1cb93c5bea9..aa3f2122ec2 100644 --- a/addons/website_sale_product_configurator/static/tests/tours/website_sale_shop_custom_attributes_value.js +++ b/addons/website_sale_product_configurator/static/tests/tours/website_sale_shop_custom_attributes_value.js @@ -1,8 +1,8 @@ -odoo.define("website_sale_product_configurator.tour_shop_custom_attribute_value", function (require) { +odoo.define("website_sale_product_TESTurator.tour_shop_custom_attribute_value", function (require) { "use strict"; /** * Add custom steps to handle the optional products modal introduced - * by the product configurator module. + * by the product TESTurator module. */ var tour = require('web_tour.tour'); require('website_sale.tour_shop_custom_attribute_value'); @@ -13,7 +13,7 @@ var addCartStepIndex = _.findIndex(tour.tours.shop_custom_attribute_value.steps, }); tour.tours.shop_custom_attribute_value.steps.splice(addCartStepIndex + 1, 0, { - trigger: 'div:contains(Custom: Wood)', + trigger: 'div:contains(Custom TEST: Wood)', extra_trigger: '.js_product.in_cart.main_product', run: function (){} // checks that Yep, it's wood! }, { @@ -26,14 +26,14 @@ tour.tours.shop_custom_attribute_value.steps.splice(addCartStepIndex + 1, 0, { trigger: 'span.oe_price span:contains(600)', run: function (){}, // check }, { - trigger: '.oe_optional_products_modal .js_product:eq(1) div:contains("Conference Chair (CONFIG) (Steel)")', + trigger: '.oe_optional_products_modal .js_product:eq(1) div:contains("Conference Chair (TEST) (Steel)")', run: function () { optionVariantImage = $('.oe_optional_products_modal .js_product:eq(1) img.variant_image').attr('src'); } }, { trigger: '.oe_optional_products_modal .js_product:eq(1) input[data-value_name="Aluminium"]', }, { - trigger: '.oe_optional_products_modal .js_product:eq(1) div:contains("Conference Chair (CONFIG) (Aluminium)")', + trigger: '.oe_optional_products_modal .js_product:eq(1) div:contains("Conference Chair (TEST) (Aluminium)")', run: function () { var newVariantImage = $('.oe_optional_products_modal .js_product:eq(1) img.variant_image').attr('src'); if (newVariantImage !== optionVariantImage) { diff --git a/addons/website_sale_wishlist/static/tests/tours/website_sale_wishlist.js b/addons/website_sale_wishlist/static/tests/tours/website_sale_wishlist.js index 935efb39ef2..ab9193608b1 100644 --- a/addons/website_sale_wishlist/static/tests/tours/website_sale_wishlist.js +++ b/addons/website_sale_wishlist/static/tests/tours/website_sale_wishlist.js @@ -6,7 +6,7 @@ var tour = require("web_tour.tour"); tour.register('shop_wishlist', { test: true, - url: '/shop', + url: '/shop?search=Customizable Desk', }, [ { @@ -41,7 +41,7 @@ tour.register('shop_wishlist', { run: function (){ $('.oe_login_form input[name="login"]').val("admin"); $('.oe_login_form input[name="password"]').val("admin"); - $('.oe_login_form input[name="redirect"]').val("/shop"); + $('.oe_login_form input[name="redirect"]').val("/shop?search=Customizable Desk"); $('.oe_login_form').submit(); }, }, @@ -51,8 +51,8 @@ tour.register('shop_wishlist', { run: function () {}, }, { - content: "click on Customizable Desk", - trigger: '.oe_product_cart a:contains("Customizable Desk")', + content: "click on Customizable Desk (TEST)", + trigger: '.oe_product_cart a:contains("Customizable Desk (TEST)")', }, { content: "check the first variant is already in wishlist", @@ -75,8 +75,8 @@ tour.register('shop_wishlist', { trigger: 'a[href="/shop/wishlist"]', }, { - content: "remove Customizable Desk", - trigger: 'tr:contains("Customizable Desk") .o_wish_rm:first', + content: "remove Customizable Desk (TEST)", + trigger: 'tr:contains("Customizable Desk (TEST)") .o_wish_rm:first', }, { content: "check that wishlist contains 1 item", diff --git a/addons/website_sale_wishlist/tests/test_wishlist_process.py b/addons/website_sale_wishlist/tests/test_wishlist_process.py index c9d487af8cf..dc995eda45e 100644 --- a/addons/website_sale_wishlist/tests/test_wishlist_process.py +++ b/addons/website_sale_wishlist/tests/test_wishlist_process.py @@ -6,4 +6,58 @@ import odoo.tests @odoo.tests.tagged('-at_install', 'post_install') class TestUi(odoo.tests.HttpCase): def test_01_wishlist_tour(self): + + self.env['product.template'].search([]).write({'website_published': False}) + # Setup attributes and attributes values + self.product_attribute_1 = self.env['product.attribute'].create({ + 'name': 'Legs', + 'sequence': 10, + }) + product_attribute_value_1 = self.env['product.attribute.value'].create({ + 'name': 'Steel', + 'attribute_id': self.product_attribute_1.id, + 'sequence': 1, + }) + product_attribute_value_2 = self.env['product.attribute.value'].create({ + 'name': 'Aluminium', + 'attribute_id': self.product_attribute_1.id, + 'sequence': 2, + }) + product_attribute_2 = self.env['product.attribute'].create({ + 'name': 'Color', + 'sequence': 20, + }) + product_attribute_value_3 = self.env['product.attribute.value'].create({ + 'name': 'White', + 'attribute_id': product_attribute_2.id, + 'sequence': 1, + }) + product_attribute_value_4 = self.env['product.attribute.value'].create({ + 'name': 'Black', + 'attribute_id': product_attribute_2.id, + 'sequence': 2, + }) + + # Create product template + self.product_product_4_product_template = self.env['product.template'].create({ + 'name': 'Customizable Desk (TEST)', + 'standard_price': 500.0, + 'list_price': 750.0, + 'website_published': True, + }) + + # Generate variants + self.env['product.template.attribute.line'].create([{ + 'product_tmpl_id': self.product_product_4_product_template.id, + 'attribute_id': self.product_attribute_1.id, + 'value_ids': [(4, product_attribute_value_1.id), (4, product_attribute_value_2.id)], + }, { + 'product_tmpl_id': self.product_product_4_product_template.id, + 'attribute_id': product_attribute_2.id, + 'value_ids': [(4, product_attribute_value_3.id), (4, product_attribute_value_4.id)], + + }]) + + self.env.ref('base.user_admin').name = 'Mitchell Admin' + self.start_tour("/", 'shop_wishlist') diff --git a/addons/website_slides/tests/test_ui_wslides.py b/addons/website_slides/tests/test_ui_wslides.py index 82b93de3ec1..4e60263553d 100644 --- a/addons/website_slides/tests/test_ui_wslides.py +++ b/addons/website_slides/tests/test_ui_wslides.py @@ -1,19 +1,104 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. +import base64 + +from dateutil.relativedelta import relativedelta from odoo import tests +from odoo.fields import Datetime +from odoo.modules.module import get_module_resource +from odoo.addons.base.tests.common import HttpCaseWithUserDemo, HttpCaseWithUserPortal + + +class TestUICommon(HttpCaseWithUserDemo, HttpCaseWithUserPortal): + + def setUp(self): + super(TestUICommon, self).setUp() + # Load pdf and img contents + pdf_path = get_module_resource('website_slides', 'static', 'src', 'img', 'presentation.pdf') + pdf_content = base64.b64encode(open(pdf_path, "rb").read()) + img_path = get_module_resource('website_slides', 'static', 'src', 'img', 'slide_demo_gardening_1.jpg') + img_content = base64.b64encode(open(img_path, "rb").read()) + + self.env['slide.channel'].create({ + 'name': 'Basics of Gardening - Test', + 'user_id': self.env.ref('base.user_admin').id, + 'enroll': 'public', + 'channel_type': 'training', + 'allow_comment': True, + 'promote_strategy': 'most_voted', + 'is_published': True, + 'description': 'Learn the basics of gardening !', + 'create_date': Datetime.now() - relativedelta(days=8), + 'slide_ids': [ + (0, 0, { + 'name': 'Gardening: The Know-How', + 'sequence': 1, + 'datas': pdf_content, + 'slide_type': 'presentation', + 'is_published': True, + 'is_preview': True, + }), (0, 0, { + 'name': 'Home Gardening', + 'sequence': 2, + 'image_1920': img_content, + 'slide_type': 'infographic', + 'is_published': True, + }), (0, 0, { + 'name': 'Mighty Carrots', + 'sequence': 3, + 'image_1920': img_content, + 'slide_type': 'infographic', + 'is_published': True, + }), (0, 0, { + 'name': 'How to Grow and Harvest The Best Strawberries | Basics', + 'sequence': 4, + 'datas': pdf_content, + 'slide_type': 'document', + 'is_published': True, + }), (0, 0, { + 'name': 'Test your knowledge', + 'sequence': 5, + 'slide_type': 'quiz', + 'is_published': True, + 'question_ids': [ + (0, 0, { + 'question': 'What is a strawberry ?', + 'answer_ids': [ + (0, 0, { + 'text_value': 'A fruit', + 'is_correct': True, + }), (0, 0, { + 'text_value': 'A vegetable', + }), (0, 0, { + 'text_value': 'A table', + }) + ] + }), (0, 0, { + 'question': 'What is the best tool to dig a hole for your plants ?', + 'answer_ids': [ + (0, 0, { + 'text_value': 'A shovel', + 'is_correct': True, + }), (0, 0, { + 'text_value': 'A spoon', + }) + ] + }) + ] + }) + ] + }) @tests.common.tagged('post_install', '-at_install') -class TestUi(tests.HttpCase): +class TestUi(TestUICommon): def test_course_member_employee(self): - # remove membership because we need to be able to join the course during the tour - user_demo = self.env.ref('base.user_demo') + user_demo = self.user_demo user_demo.flush() user_demo.write({ 'groups_id': [(5, 0), (4, self.env.ref('base.group_user').id)] }) - self.env.ref('website_slides.slide_channel_demo_0_gard_0')._remove_membership(self.env.ref('base.partner_demo').ids) self.browser_js( '/slides', @@ -22,14 +107,11 @@ class TestUi(tests.HttpCase): login=user_demo.login) def test_course_member_website_publisher(self): - # remove membership because we need to be able to join the course during the tour - # group_website_designer - user_demo = self.env.ref('base.user_demo') + user_demo = self.user_demo user_demo.flush() user_demo.write({ 'groups_id': [(5, 0), (4, self.env.ref('base.group_user').id), (4, self.env.ref('website.group_website_publisher').id)] }) - self.env.ref('website_slides.slide_channel_demo_0_gard_0')._remove_membership(self.env.ref('base.partner_demo').ids) self.browser_js( '/slides', @@ -38,11 +120,8 @@ class TestUi(tests.HttpCase): login=user_demo.login) def test_course_member_portal(self): - # remove membership because we need to be able to join the course during the tour - # group_website_designer - user_portal = self.env.ref('base.demo_user0') + user_portal = self.user_portal user_portal.flush() - self.env.ref('website_slides.slide_channel_demo_0_gard_0')._remove_membership(self.env.ref('base.partner_demo_portal').ids) self.browser_js( '/slides', @@ -52,11 +131,11 @@ class TestUi(tests.HttpCase): @tests.common.tagged('external', 'post_install', '-standard', '-at_install') -class TestUiYoutube(tests.HttpCase): +class TestUiYoutube(HttpCaseWithUserDemo): def test_course_member_yt_employee(self): # remove membership because we need to be able to join the course during the tour - user_demo = self.env.ref('base.user_demo') + user_demo = self.user_demo user_demo.flush() user_demo.write({ 'groups_id': [(5, 0), (4, self.env.ref('base.group_user').id)] @@ -72,7 +151,7 @@ class TestUiYoutube(tests.HttpCase): def test_course_publisher_website_designer(self): # remove membership because we need to be able to join the course during the tour # group_website_designer - user_demo = self.env.ref('base.user_demo') + user_demo = self.user_demo user_demo.flush() user_demo.write({ 'groups_id': [(5, 0), (4, self.env.ref('base.group_user').id), (4, self.env.ref('website.group_website_designer').id)] diff --git a/addons/website_slides/tests/tours/slides_course_member.js b/addons/website_slides/tests/tours/slides_course_member.js index 53e7b51f114..8a7e3076a87 100644 --- a/addons/website_slides/tests/tours/slides_course_member.js +++ b/addons/website_slides/tests/tours/slides_course_member.js @@ -18,7 +18,7 @@ tour.register('course_member', { }, [ // eLearning: go on free course and join it { - trigger: 'a:contains("Basics of Gardening")' + trigger: 'a:contains("Basics of Gardening - Test")' }, { trigger: 'a:contains("Join Course")' }, { diff --git a/odoo/addons/base/tests/__init__.py b/odoo/addons/base/tests/__init__.py index 54a68834374..e22f21be75c 100644 --- a/odoo/addons/base/tests/__init__.py +++ b/odoo/addons/base/tests/__init__.py @@ -1,4 +1,7 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import common from . import test_acl from . import test_api from . import test_base diff --git a/odoo/addons/base/tests/common.py b/odoo/addons/base/tests/common.py new file mode 100644 index 00000000000..4d7e7e00c87 --- /dev/null +++ b/odoo/addons/base/tests/common.py @@ -0,0 +1,196 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.tests.common import SavepointCase, TransactionCase, HttpCase + + +class TransactionCaseWithUserDemo(TransactionCase): + + def setUp(self): + super(TransactionCaseWithUserDemo, self).setUp() + + self.env.ref('base.partner_admin').write({'name': 'Mitchell Admin'}) + self.user_demo = self.env['res.users'].search([('login', '=', 'demo')]) + self.partner_demo = self.user_demo.partner_id + + if not self.user_demo: + self.env['ir.config_parameter'].sudo().set_param('auth_password_policy.minlength', 4) + # YTI TODO: This could be factorized between the different classes + self.partner_demo = self.env['res.partner'].create({ + 'name': 'Marc Demo', + 'email': 'mark.brown23@example.com', + }) + self.user_demo = self.env['res.users'].create({ + 'login': 'demo', + 'password': 'demo', + 'partner_id': self.partner_demo.id, + 'groups_id': [(6, 0, [self.env.ref('base.group_user').id, self.env.ref('base.group_partner_manager').id])], + }) + + +class HttpCaseWithUserDemo(HttpCase): + + def setUp(self): + super(HttpCaseWithUserDemo, self).setUp() + self.env.ref('base.partner_admin').write({'name': 'Mitchell Admin'}) + self.user_demo = self.env['res.users'].search([('login', '=', 'demo')]) + self.partner_demo = self.user_demo.partner_id + + if not self.user_demo: + self.env['ir.config_parameter'].sudo().set_param('auth_password_policy.minlength', 4) + self.partner_demo = self.env['res.partner'].create({ + 'name': 'Marc Demo', + 'email': 'mark.brown23@example.com', + }) + self.user_demo = self.env['res.users'].create({ + 'login': 'demo', + 'password': 'demo', + 'partner_id': self.partner_demo.id, + 'groups_id': [(6, 0, [self.env.ref('base.group_user').id, self.env.ref('base.group_partner_manager').id])], + }) + + +class SavepointCaseWithUserDemo(SavepointCase): + + @classmethod + def setUpClass(cls): + super(SavepointCaseWithUserDemo, cls).setUpClass() + + cls.user_demo = cls.env['res.users'].search([('login', '=', 'demo')]) + cls.partner_demo = cls.user_demo.partner_id + + if not cls.user_demo: + cls.env['ir.config_parameter'].sudo().set_param('auth_password_policy.minlength', 4) + cls.partner_demo = cls.env['res.partner'].create({ + 'name': 'Marc Demo', + 'email': 'mark.brown23@example.com', + }) + cls.user_demo = cls.env['res.users'].create({ + 'login': 'demo', + 'password': 'demo', + 'partner_id': cls.partner_demo.id, + 'groups_id': [(6, 0, [cls.env.ref('base.group_user').id, cls.env.ref('base.group_partner_manager').id])], + }) + + @classmethod + def _load_partners_set(cls): + cls.partner_category = cls.env['res.partner.category'].create({ + 'name': 'Sellers', + 'color': 2, + }) + cls.partner_category_child_1 = cls.env['res.partner.category'].create({ + 'name': 'Office Supplies', + 'parent_id': cls.partner_category.id, + }) + cls.partner_category_child_2 = cls.env['res.partner.category'].create({ + 'name': 'Desk Manufacturers', + 'parent_id': cls.partner_category.id, + }) + + # Load all the demo partners + cls.partners = cls.env['res.partner'].create([ + { + 'name': 'Inner Works', # Wood Corner + 'state_id': cls.env.ref('base.state_us_1').id, + 'category_id': [(6, 0, [cls.partner_category_child_1.id, cls.partner_category_child_2.id,])], + 'child_ids': [(0, 0, { + 'name': 'Sheila Ruiz', # 'Willie Burke', + }), (0, 0, { + 'name': 'Wyatt Howard', # 'Ron Gibson', + }), (0, 0, { + 'name': 'Austin Kennedy', # Tom Ruiz + })], + }, { + 'name': 'Pepper Street', # 'Deco Addict', + 'state_id': cls.env.ref('base.state_us_2').id, + 'child_ids': [(0, 0, { + 'name': 'Liam King', # 'Douglas Fletcher', + }), (0, 0, { + 'name': 'Craig Richardson', # 'Floyd Steward', + }), (0, 0, { + 'name': 'Adam Cox', # 'Addison Olson', + })], + }, { + 'name': 'AnalytIQ', #'Gemini Furniture', + 'state_id': cls.env.ref('base.state_us_3').id, + 'child_ids': [(0, 0, { + 'name': 'Pedro Boyd', # Edwin Hansen + }), (0, 0, { + 'name': 'Landon Roberts', # 'Jesse Brown', + 'company_id': cls.env.ref('base.main_company').id, + }), (0, 0, { + 'name': 'Leona Shelton', # 'Soham Palmer', + }), (0, 0, { + 'name': 'Scott Kim', # 'Oscar Morgan', + })], + }, { + 'name': 'Urban Trends', # 'Ready Mat', + 'state_id': cls.env.ref('base.state_us_4').id, + 'category_id': [(6, 0, [cls.partner_category_child_1.id, cls.partner_category_child_2.id,])], + 'child_ids': [(0, 0, { + 'name': 'Louella Jacobs', # 'Billy Fox', + }), (0, 0, { + 'name': 'Albert Alexander', # 'Kim Snyder', + }), (0, 0, { + 'name': 'Brad Castillo', # 'Edith Sanchez', + }), (0, 0, { + 'name': 'Sophie Montgomery', # 'Sandra Neal', + }), (0, 0, { + 'name': 'Chloe Bates', # 'Julie Richards', + }), (0, 0, { + 'name': 'Mason Crawford', # 'Travis Mendoza', + }), (0, 0, { + 'name': 'Elsie Kennedy', # 'Theodore Gardner', + })], + }, { + 'name': 'Ctrl-Alt-Fix', # 'The Jackson Group', + 'state_id': cls.env.ref('base.state_us_5').id, + 'child_ids': [(0, 0, { + 'name': 'carole miller', # 'Toni Rhodes', + }), (0, 0, { + 'name': 'Cecil Holmes', # 'Gordon Owens', + })], + }, { + 'name': 'Ignitive Labs', # 'Azure Interior', + 'state_id': cls.env.ref('base.state_us_6').id, + 'child_ids': [(0, 0, { + 'name': 'Jonathan Webb', # 'Brandon Freeman', + }), (0, 0, { + 'name': 'Clinton Clark', # 'Nicole Ford', + }), (0, 0, { + 'name': 'Howard Bryant', # 'Colleen Diaz', + })], + }, { + 'name': 'Amber & Forge', # 'Lumber Inc', + 'state_id': cls.env.ref('base.state_us_7').id, + 'child_ids': [(0, 0, { + 'name': 'Mark Webb', # 'Lorraine Douglas', + })], + }, { + 'name': 'Rebecca Day', # 'Chester Reed', + 'parent_id': cls.env.ref('base.main_partner').id, + }, { + 'name': 'Gabriella Jennings', # 'Dwayne Newman', + 'parent_id': cls.env.ref('base.main_partner').id, + } + ]) + +class HttpCaseWithUserPortal(HttpCase): + + def setUp(self): + super(HttpCaseWithUserPortal, self).setUp() + self.user_portal = self.env['res.users'].search([('login', '=', 'portal')]) + self.partner_portal = self.user_portal.partner_id + + if not self.user_portal: + self.env['ir.config_parameter'].sudo().set_param('auth_password_policy.minlength', 4) + self.partner_portal = self.env['res.partner'].create({ + 'name': 'Joel Willis', + 'email': 'joel.willis63@example.com', + }) + self.user_portal = self.env['res.users'].with_context(no_reset_password=True).create({ + 'login': 'portal', + 'password': 'portal', + 'partner_id': self.partner_portal.id, + 'groups_id': [(6, 0, [self.env.ref('base.group_portal').id])], + }) diff --git a/odoo/addons/base/tests/test_acl.py b/odoo/addons/base/tests/test_acl.py index 1648cf1dcea..fec7fda8ed5 100644 --- a/odoo/addons/base/tests/test_acl.py +++ b/odoo/addons/base/tests/test_acl.py @@ -4,19 +4,18 @@ from lxml import etree from odoo.exceptions import AccessError +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo from odoo.tests.common import TransactionCase from odoo.tools.misc import mute_logger # test group that demo user should not have -USER_DEMO = 'base.user_demo' GROUP_SYSTEM = 'base.group_system' -class TestACL(TransactionCase): +class TestACL(TransactionCaseWithUserDemo): def setUp(self): super(TestACL, self).setUp() - self.demo_user = self.env.ref(USER_DEMO) self.erp_system_group = self.env.ref(GROUP_SYSTEM) def _set_field_groups(self, model, field_name, groups): @@ -26,7 +25,7 @@ class TestACL(TransactionCase): def test_field_visibility_restriction(self): """Check that model-level ``groups`` parameter effectively restricts access to that field for users who do not belong to one of the explicitly allowed groups""" - currency = self.env['res.currency'].with_user(self.demo_user) + currency = self.env['res.currency'].with_user(self.user_demo) # Add a view that adds a label for the field we are going to check extension = self.env["ir.ui.view"].create({ @@ -50,7 +49,7 @@ class TestACL(TransactionCase): original_fields = currency.fields_get([]) form_view = currency.fields_view_get(False, 'form') view_arch = etree.fromstring(form_view.get('arch')) - has_group_system = self.demo_user.has_group(GROUP_SYSTEM) + has_group_system = self.user_demo.has_group(GROUP_SYSTEM) self.assertFalse(has_group_system, "`demo` user should not belong to the restricted group before the test") self.assertIn('decimal_places', original_fields, "'decimal_places' field must be properly visible before the test") self.assertNotEqual(view_arch.xpath("//field[@name='decimal_places'][@nolabel='1']"), [], @@ -71,8 +70,8 @@ class TestACL(TransactionCase): "Label for 'decimal_places' must not be found in view definition") # Make demo user a member of the restricted group and check that the field is back - self.erp_system_group.users += self.demo_user - has_group_system = self.demo_user.has_group(GROUP_SYSTEM) + self.erp_system_group.users += self.user_demo + has_group_system = self.user_demo.has_group(GROUP_SYSTEM) fields = currency.fields_get([]) form_view = currency.fields_view_get(False, 'form') view_arch = etree.fromstring(form_view.get('arch')) @@ -86,10 +85,10 @@ class TestACL(TransactionCase): @mute_logger('odoo.models') def test_field_crud_restriction(self): "Read/Write RPC access to restricted field should be forbidden" - partner = self.env['res.partner'].browse(1).with_user(self.demo_user) + partner = self.env['res.partner'].browse(1).with_user(self.user_demo) # Verify the test environment first - has_group_system = self.demo_user.has_group(GROUP_SYSTEM) + has_group_system = self.user_demo.has_group(GROUP_SYSTEM) self.assertFalse(has_group_system, "`demo` user should not belong to the restricted group") self.assertTrue(partner.read(['bank_ids'])) self.assertTrue(partner.write({'bank_ids': []})) @@ -103,8 +102,8 @@ class TestACL(TransactionCase): partner.write({'bank_ids': []}) # Add the restricted group, and check that it works again - self.erp_system_group.users += self.demo_user - has_group_system = self.demo_user.has_group(GROUP_SYSTEM) + self.erp_system_group.users += self.user_demo + has_group_system = self.user_demo.has_group(GROUP_SYSTEM) self.assertTrue(has_group_system, "`demo` user should now belong to the restricted group") self.assertTrue(partner.read(['bank_ids'])) self.assertTrue(partner.write({'bank_ids': []})) @@ -112,7 +111,10 @@ class TestACL(TransactionCase): @mute_logger('odoo.models') def test_fields_browse_restriction(self): """Test access to records having restricted fields""" - partner = self.env['res.partner'].with_user(self.demo_user) + # Invalidate cache to avoid restricted value to be available + # in the cache + self.user_demo.invalidate_cache() + partner = self.env['res.partner'].with_user(self.user_demo) self._set_field_groups(partner, 'email', GROUP_SYSTEM) # accessing fields must no raise exceptions... @@ -126,7 +128,7 @@ class TestACL(TransactionCase): def test_view_create_edit_button_invisibility(self): """ Test form view Create, Edit, Delete button visibility based on access right of model""" methods = ['create', 'edit', 'delete'] - company = self.env['res.company'].with_user(self.demo_user) + company = self.env['res.company'].with_user(self.user_demo) company_view = company.fields_view_get(False, 'form') view_arch = etree.fromstring(company_view['arch']) for method in methods: @@ -134,9 +136,9 @@ class TestACL(TransactionCase): def test_view_create_edit_button_visibility(self): """ Test form view Create, Edit, Delete button visibility based on access right of model""" - self.erp_system_group.users += self.demo_user + self.erp_system_group.users += self.user_demo methods = ['create', 'edit', 'delete'] - company = self.env['res.company'].with_user(self.demo_user) + company = self.env['res.company'].with_user(self.user_demo) company_view = company.fields_view_get(False, 'form') view_arch = etree.fromstring(company_view['arch']) for method in methods: @@ -145,7 +147,7 @@ class TestACL(TransactionCase): def test_m2o_field_create_edit_invisibility(self): """ Test many2one field Create and Edit option visibility based on access rights of relation field""" methods = ['create', 'write'] - company = self.env['res.company'].with_user(self.demo_user) + company = self.env['res.company'].with_user(self.user_demo) company_view = company.fields_view_get(False, 'form') view_arch = etree.fromstring(company_view['arch']) field_node = view_arch.xpath("//field[@name='currency_id']") @@ -155,9 +157,9 @@ class TestACL(TransactionCase): def test_m2o_field_create_edit_visibility(self): """ Test many2one field Create and Edit option visibility based on access rights of relation field""" - self.erp_system_group.users += self.demo_user + self.erp_system_group.users += self.user_demo methods = ['create', 'write'] - company = self.env['res.company'].with_user(self.demo_user) + company = self.env['res.company'].with_user(self.user_demo) company_view = company.fields_view_get(False, 'form') view_arch = etree.fromstring(company_view['arch']) field_node = view_arch.xpath("//field[@name='currency_id']") @@ -166,12 +168,11 @@ class TestACL(TransactionCase): self.assertEqual(field_node[0].get('can_' + method), 'true') -class TestIrRule(TransactionCase): +class TestIrRule(TransactionCaseWithUserDemo): def test_ir_rule(self): model_res_partner = self.env.ref('base.model_res_partner') group_user = self.env.ref('base.group_user') - user_demo = self.env.ref('base.user_demo') # create an ir_rule for the Employee group with an blank domain rule1 = self.env['ir.rule'].create({ @@ -182,7 +183,7 @@ class TestIrRule(TransactionCase): }) # read as demo user the partners (one blank domain) - partners_demo = self.env['res.partner'].with_user(user_demo) + partners_demo = self.env['res.partner'].with_user(self.user_demo) partners = partners_demo.search([]) self.assertTrue(partners, "Demo user should see some partner.") @@ -256,7 +257,7 @@ class TestIrRule(TransactionCase): # create a new group with demo user in it, and a complex rule group_test = self.env['res.groups'].create({ 'name': 'Test Group', - 'users': [(6, 0, user_demo.ids)], + 'users': [(6, 0, self.user_demo.ids)], }) # add the rule to the new group, with a domain containing an implicit diff --git a/odoo/addons/base/tests/test_api.py b/odoo/addons/base/tests/test_api.py index 158fe2ee500..149e7b3a261 100644 --- a/odoo/addons/base/tests/test_api.py +++ b/odoo/addons/base/tests/test_api.py @@ -2,14 +2,19 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import models +from odoo.addons.base.tests.common import SavepointCaseWithUserDemo from odoo.tools import mute_logger -from odoo.tests import common from odoo.exceptions import AccessError -class TestAPI(common.TransactionCase): +class TestAPI(SavepointCaseWithUserDemo): """ test the new API of the ORM """ + @classmethod + def setUpClass(cls): + super(TestAPI, cls).setUpClass() + cls._load_partners_set() + def assertIsRecordset(self, value, model): self.assertIsInstance(value, models.BaseModel) self.assertEqual(value._name, model) @@ -48,8 +53,8 @@ class TestAPI(common.TransactionCase): @mute_logger('odoo.models') def test_02_query_limit(self): """ Build a recordset with offset, and check equivalence. """ - partners1 = self.env['res.partner'].search([], limit=10) - partners2 = self.env['res.partner'].search([])[:10] + partners1 = self.env['res.partner'].search([], order='id asc', limit=10) + partners2 = self.env['res.partner'].search([], order='id asc')[:10] self.assertIsRecordset(partners1, 'res.partner') self.assertIsRecordset(partners2, 'res.partner') self.assertEqual(list(partners1), list(partners2)) @@ -57,8 +62,8 @@ class TestAPI(common.TransactionCase): @mute_logger('odoo.models') def test_03_query_offset_limit(self): """ Build a recordset with offset and limit, and check equivalence. """ - partners1 = self.env['res.partner'].search([], offset=3, limit=7) - partners2 = self.env['res.partner'].search([])[3:10] + partners1 = self.env['res.partner'].search([], order='id asc', offset=3, limit=7) + partners2 = self.env['res.partner'].search([], order='id asc')[3:10] self.assertIsRecordset(partners1, 'res.partner') self.assertIsRecordset(partners2, 'res.partner') self.assertEqual(list(partners1), list(partners2)) @@ -173,7 +178,7 @@ class TestAPI(common.TransactionCase): partners[0].company_id.write({'name': 'Fools'}) # create an environment with the demo user - demo = self.env['res.users'].search([('login', '=', 'demo')])[0] + demo = self.env['res.users'].search([('login', 'ilike', 'demo')])[0] demo_env = self.env(user=demo) self.assertNotEqual(demo_env, self.env) @@ -193,16 +198,18 @@ class TestAPI(common.TransactionCase): self.assertEqual(p.env, demo_env) # demo user can read but not modify company data - demo_partners[0].company_id.name + demo_partner = self.env['res.partner'].search([('name', '=', 'Landon Roberts')]).with_user(demo) + self.assertTrue(demo_partner.company_id, 'This partner is supposed to be linked to a company') + demo_partner.company_id.name with self.assertRaises(AccessError): - demo_partners[0].company_id.write({'name': 'Pricks'}) + demo_partner.company_id.write({'name': 'Pricks'}) # remove demo user from all groups demo.write({'groups_id': [(5,)]}) # demo user can no longer access partner data with self.assertRaises(AccessError): - demo_partners[0].company_id.name + demo_partner.company_id.name @mute_logger('odoo.models') def test_60_cache(self): @@ -319,7 +326,7 @@ class TestAPI(common.TransactionCase): # the recordset operations below share the prefetch set same_prefetch(partners, partners.browse(partners.ids)) - same_prefetch(partners, partners.with_user(self.env.ref('base.user_demo'))) + same_prefetch(partners, partners.with_user(self.user_demo)) same_prefetch(partners, partners.with_context(active_test=False)) same_prefetch(partners, partners[:10].with_prefetch(partners._prefetch_ids)) @@ -338,7 +345,7 @@ class TestAPI(common.TransactionCase): 'name': 'Non-empty relational fields', 'country_id': self.ref('base.be'), 'bank_ids': [(0, 0, {'acc_number': 'FOO42'})], - 'category_id': [(4, self.ref('base.res_partner_category_0'))], + 'category_id': [(4, self.partner_category.id)], } partners = partners.create(vals0) + partners.create(vals1) for partner in partners: @@ -511,5 +518,5 @@ class TestAPI(common.TransactionCase): self.assertEqual(ps.sorted('name').ids, by_name_ids) # sort by inverse name, with a field name - by_name_ids.reverse() + by_name_ids = [p.id for p in sorted(ps, key=lambda p: p.name, reverse=True)] self.assertEqual(ps.sorted('name', reverse=True).ids, by_name_ids) diff --git a/odoo/addons/base/tests/test_cache.py b/odoo/addons/base/tests/test_cache.py index d6c18dd4132..0efa36ca48a 100644 --- a/odoo/addons/base/tests/test_cache.py +++ b/odoo/addons/base/tests/test_cache.py @@ -6,11 +6,12 @@ import platform import psutil import unittest +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo from odoo.exceptions import CacheMiss from odoo.tests.common import TransactionCase -class TestRecordCache(TransactionCase): +class TestRecordCache(TransactionCaseWithUserDemo): def test_cache(self): """ Check the record cache object. """ @@ -37,7 +38,7 @@ class TestRecordCache(TransactionCase): check1(record, ref, ref_val) foo1, bar1 = Model.browse([1, 2]) - foo2, bar2 = Model.with_user(self.env.ref('base.user_demo')).browse([1, 2]) + foo2, bar2 = Model.with_user(self.user_demo).browse([1, 2]) self.assertNotEqual(foo1.env.uid, foo2.env.uid) # cache is empty diff --git a/odoo/addons/base/tests/test_expression.py b/odoo/addons/base/tests/test_expression.py index 7b5dfacadba..61d470e094c 100644 --- a/odoo/addons/base/tests/test_expression.py +++ b/odoo/addons/base/tests/test_expression.py @@ -3,13 +3,21 @@ import psycopg2 +from odoo.addons.base.tests.common import SavepointCaseWithUserDemo +from odoo.fields import Date from odoo.models import BaseModel from odoo.tests.common import TransactionCase from odoo.tools import mute_logger from odoo.osv import expression -class TestExpression(TransactionCase): +class TestExpression(SavepointCaseWithUserDemo): + + @classmethod + def setUpClass(cls): + super(TestExpression, cls).setUpClass() + cls._load_partners_set() + def _search(self, obj, domain, init_domain=[]): sql = obj.search(domain) allobj = obj.search(init_domain) @@ -111,7 +119,7 @@ class TestExpression(TransactionCase): Category = self.env['res.partner.category'] # search through m2m relation - partners = self._search(Partner, [('category_id', 'child_of', self.ref('base.res_partner_category_0'))]) + partners = self._search(Partner, [('category_id', 'child_of', self.partner_category.id)]) self.assertTrue(partners) # setup test partner categories @@ -217,8 +225,8 @@ class TestExpression(TransactionCase): Partner = self.env['res.partner'] all_partners = self._search(Partner, []) self.assertTrue(len(all_partners) > 1) - one = all_partners[0] - others = all_partners[1:] + one = self.env.ref('base.main_partner') + others = all_partners - one res_1 = self._search(Partner, [('id', '=', one.id)]) self.assertEqual(one, res_1) @@ -242,15 +250,15 @@ class TestExpression(TransactionCase): Partner = self.env['res.partner'] # testing equality with name - partners = self._search(Partner, [('parent_id', '=', 'Deco Addict')]) + partners = self._search(Partner, [('parent_id', '=', 'Pepper Street')]) self.assertTrue(partners) # testing the in operator with name - partners = self._search(Partner, [('parent_id', 'in', 'Deco Addict')]) + partners = self._search(Partner, [('parent_id', 'in', 'Pepper Street')]) self.assertTrue(partners) # testing the in operator with a list of names - partners = self._search(Partner, [('parent_id', 'in', ['Deco Addict', 'Wood Corner'])]) + partners = self._search(Partner, [('parent_id', 'in', ['Pepper Street', 'Inner Works'])]) self.assertTrue(partners) # check if many2one works with empty search list @@ -480,6 +488,22 @@ class TestExpression(TransactionCase): Currency = self.env['res.currency'] CurrencyRate = self.env['res.currency.rate'] + CurrencyRate.create([ + { + 'currency_id': self.env.ref('base.EUR').id, + 'name': '2000-01-01', + 'rate': 1.0, + }, { + 'currency_id': self.env.ref('base.USD').id, + 'name': '2000-01-01', + 'rate': 1.2834, + }, { + 'currency_id': self.env.ref('base.USD').id, + 'name': '2000-01-02', + 'rate': 1.5289, + } + ]) + # create a currency and a currency rate currency = Currency.create({'name': 'ZZZ', 'symbol': 'ZZZ', 'rounding': 1.0}) currency_rate = CurrencyRate.create({'name': '2010-01-01', 'currency_id': currency.id, 'rate': 1.0}) @@ -583,8 +607,8 @@ class TestExpression(TransactionCase): def test_like_wildcards(self): # check that =like/=ilike expressions are working on an untranslated field Partner = self.env['res.partner'] - partners = self._search(Partner, [('name', '=like', 'W_od_C_rn_r')]) - self.assertTrue(len(partners) == 1, "Must match one partner (Wood Corner)") + partners = self._search(Partner, [('name', '=like', 'I_ner_W_rk_')]) + self.assertTrue(all(partner.name == 'Inner Works' for partner in partners), "Must match only 'Inner Works'") partners = self._search(Partner, [('name', '=ilike', 'G%')]) self.assertTrue(len(partners) >= 1, "Must match one partner (Gemini Furniture)") @@ -608,12 +632,6 @@ class TestExpression(TransactionCase): countries = self._search(Country, domain) self.assertEqual(countries, belgium) - def test_long_table_alias(self): - # To test the 64 characters limit for table aliases in PostgreSQL - self.patch_order('res.users', 'partner_id') - self.patch_order('res.partner', 'commercial_partner_id,company_id,name') - self.env['res.users'].search([('name', '=', 'test')]) - @mute_logger('odoo.sql_db') def test_invalid(self): """ verify that invalid expressions are refused, even for magic fields """ @@ -640,12 +658,12 @@ class TestExpression(TransactionCase): vals = { 'name': 'OpenERP Test', 'active': False, - 'category_id': [(6, 0, [self.ref("base.res_partner_category_0")])], + 'category_id': [(6, 0, [self.partner_category.id])], 'child_ids': [(0, 0, {'name': 'address of OpenERP Test', 'country_id': self.ref("base.be")})], } Partner.create(vals) - partner = self._search(Partner, [('category_id', 'ilike', 'vendor'), ('active', '=', False)], [('active', '=', False)]) - self.assertTrue(partner, "Record not Found with category vendor and active False.") + partner = self._search(Partner, [('category_id', 'ilike', 'sellers'), ('active', '=', False)], [('active', '=', False)]) + self.assertTrue(partner, "Record not Found with category sellers and active False.") # testing for one2many field with country Belgium and active=False partner = self._search(Partner, [('child_ids.country_id','=','Belgium'),('active','=',False)], [('active', '=', False)]) @@ -655,7 +673,7 @@ class TestExpression(TransactionCase): """ Check that we can exclude translated fields (bug lp:1071710) """ # first install french language self.env['ir.translation']._load_module_terms(['base'], ['fr_FR']) - self.env.ref('base.res_partner_2').country_id = self.env.ref('base.be') + self.env['res.partner'].search([('name', '=', 'Pepper Street')]).country_id = self.env.ref('base.be') # actual test Country = self.env['res.country'].with_context(lang='fr_FR') be = self.env.ref('base.be') @@ -664,7 +682,7 @@ class TestExpression(TransactionCase): # indirect search via m2o Partner = self.env['res.partner'] - deco_addict = self._search(Partner, [('name', '=', 'Deco Addict')]) + deco_addict = self._search(Partner, [('name', '=', 'Pepper Street')]) not_be = self._search(Partner, [('country_id', '!=', 'Belgium')]) self.assertNotIn(deco_addict, not_be) @@ -715,6 +733,15 @@ class TestExpression(TransactionCase): self.assertEqual(expr, false) +class TestExpression2(TransactionCase): + + def test_long_table_alias(self): + # To test the 64 characters limit for table aliases in PostgreSQL + self.patch_order('res.users', 'partner_id') + self.patch_order('res.partner', 'commercial_partner_id,company_id,name') + self.env['res.users'].search([('name', '=', 'test')]) + + class TestAutoJoin(TransactionCase): def setUp(self): diff --git a/odoo/addons/base/tests/test_form_create.py b/odoo/addons/base/tests/test_form_create.py index 54757b68c57..9a787f46d2f 100644 --- a/odoo/addons/base/tests/test_form_create.py +++ b/odoo/addons/base/tests/test_form_create.py @@ -1,4 +1,6 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + from odoo.tests import TransactionCase, tagged, Form @@ -12,6 +14,22 @@ class TestFormCreate(TransactionCase): def test_create_res_partner(self): partner_form = Form(self.env['res.partner']) partner_form.name = 'a partner' + # YTI: Clean that brol + if hasattr(self.env['res.partner'], 'property_account_payable_id'): + property_account_payable_id = self.env['account.account'].create({ + 'name': 'Test Account', + 'user_type_id': self.env.ref('account.data_account_type_payable').id, + 'code': 'TestAccountPayable', + 'reconcile': True + }) + property_account_receivable_id = self.env['account.account'].create({ + 'name': 'Test Account', + 'user_type_id': self.env.ref('account.data_account_type_receivable').id, + 'code': 'TestAccountReceivable', + 'reconcile': True + }) + partner_form.property_account_payable_id = property_account_payable_id + partner_form.property_account_receivable_id = property_account_receivable_id partner_form.save() def test_create_res_users(self): diff --git a/odoo/addons/base/tests/test_ir_filters.py b/odoo/addons/base/tests/test_ir_filters.py index 040646cabba..1e0d0effc30 100644 --- a/odoo/addons/base/tests/test_ir_filters.py +++ b/odoo/addons/base/tests/test_ir_filters.py @@ -2,6 +2,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import exceptions +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo from odoo.tests.common import TransactionCase, ADMIN_USER_ID def noid(seq): @@ -12,7 +13,12 @@ def noid(seq): return seq -class FiltersCase(TransactionCase): +class FiltersCase(TransactionCaseWithUserDemo): + def setUp(self): + super(FiltersCase, self).setUp() + self.USER_NG = self.env['res.users'].name_search('demo')[0] + self.USER_ID = self.USER_NG[0] + def build(self, model, *args): Model = self.env[model].with_user(ADMIN_USER_ID) for vals in args: @@ -20,10 +26,6 @@ class FiltersCase(TransactionCase): class TestGetFilters(FiltersCase): - def setUp(self): - super(TestGetFilters, self).setUp() - self.USER_NG = self.env['res.users'].name_search('demo')[0] - self.USER_ID = self.USER_NG[0] def test_own_filters(self): self.build( @@ -77,10 +79,6 @@ class TestGetFilters(FiltersCase): class TestOwnDefaults(FiltersCase): - def setUp(self): - super(TestOwnDefaults, self).setUp() - self.USER_NG = self.env['res.users'].name_search('demo')[0] - self.USER_ID = self.USER_NG[0] def test_new_no_filter(self): """ @@ -180,10 +178,6 @@ class TestOwnDefaults(FiltersCase): class TestGlobalDefaults(FiltersCase): - def setUp(self): - super(TestGlobalDefaults, self).setUp() - self.USER_NG = self.env['res.users'].name_search('demo')[0] - self.USER_ID = self.USER_NG[0] def test_new_filter_not_default(self): """ diff --git a/odoo/addons/base/tests/test_misc.py b/odoo/addons/base/tests/test_misc.py index 34bd040eff8..29d0a021558 100644 --- a/odoo/addons/base/tests/test_misc.py +++ b/odoo/addons/base/tests/test_misc.py @@ -190,6 +190,7 @@ class TestDateRangeFunction(BaseCase): class TestFormatLangDate(TransactionCase): def test_00_accepted_types(self): + self.env.user.tz = 'Europe/Brussels' datetime_str = '2017-01-31 12:00:00' date_datetime = datetime.datetime.strptime(datetime_str, "%Y-%m-%d %H:%M:%S") date_date = date_datetime.date() diff --git a/odoo/addons/base/tests/test_qweb.py b/odoo/addons/base/tests/test_qweb.py index 9fa00468f06..13b95926f47 100644 --- a/odoo/addons/base/tests/test_qweb.py +++ b/odoo/addons/base/tests/test_qweb.py @@ -610,6 +610,7 @@ class TestQWeb(TransactionCase): return lambda: self.run_test_file(os.path.join(path, f)) def run_test_file(self, path): + self.env.user.tz = 'Europe/Brussels' doc = etree.parse(path).getroot() loader = FileSystemLoader(path) qweb = self.env['ir.qweb'] diff --git a/odoo/addons/base/tests/test_res_partner_bank.py b/odoo/addons/base/tests/test_res_partner_bank.py index 9d19b4ef395..1727cbb6916 100644 --- a/odoo/addons/base/tests/test_res_partner_bank.py +++ b/odoo/addons/base/tests/test_res_partner_bank.py @@ -3,10 +3,10 @@ # Copyright (c) 2015 ACSONE SA/NV () -from odoo.tests.common import TransactionCase +from odoo.addons.base.tests.common import SavepointCaseWithUserDemo -class TestResPartnerBank(TransactionCase): +class TestResPartnerBank(SavepointCaseWithUserDemo): """Tests acc_number """ @@ -17,7 +17,7 @@ class TestResPartnerBank(TransactionCase): self.assertEqual(0, len(vals)) partner_bank = partner_bank_model.create({ 'acc_number': acc_number, - 'partner_id': self.ref('base.res_partner_2'), + 'partner_id': self.env['res.partner'].create({'name': 'Pepper Test'}).id, 'acc_type': 'bank', }) vals = partner_bank_model.search([('acc_number', '=', acc_number)]) diff --git a/odoo/addons/test_access_rights/tests/test_access_monetary_related.py b/odoo/addons/test_access_rights/tests/test_access_monetary_related.py index 2abe53294ed..0bff8048f8c 100644 --- a/odoo/addons/test_access_rights/tests/test_access_monetary_related.py +++ b/odoo/addons/test_access_rights/tests/test_access_monetary_related.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import odoo.tests + +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo -class TestMonetaryAccess(odoo.tests.TransactionCase): +class TestMonetaryAccess(TransactionCaseWithUserDemo): def test_monetary_access_create(self): """Monetary fields that depend on compute/related currency @@ -13,7 +14,7 @@ class TestMonetaryAccess(odoo.tests.TransactionCase): as well as trigger spurious ACL errors. """ user_admin = self.env.ref("base.user_admin") - user_demo = self.env.ref("base.user_demo").with_user(user_admin) + user_demo = self.user_demo.with_user(user_admin) # this would raise without the fix introduced in this commit new_user = user_demo.copy({'monetary': 1/3}) diff --git a/odoo/addons/test_access_rights/tests/test_feedback.py b/odoo/addons/test_access_rights/tests/test_feedback.py index 09fd42589a8..40515026f3c 100644 --- a/odoo/addons/test_access_rights/tests/test_feedback.py +++ b/odoo/addons/test_access_rights/tests/test_feedback.py @@ -23,7 +23,15 @@ class TestSudo(Feedback): def test_sudo(self): record = self.env['test_access_right.some_obj'].create({'val': 5}) user1 = self.user - user2 = self.env.ref('base.user_demo') + partner_demo = self.env['res.partner'].create({ + 'name': 'Marc Demo', + }) + user2 = self.env['res.users'].create({ + 'login': 'demo2', + 'password': 'demo2', + 'partner_id': partner_demo.id, + 'groups_id': [(6, 0, [self.env.ref('base.group_user').id, self.env.ref('base.group_partner_manager').id])], + }) # with_user(user) record1 = record.with_user(user1) diff --git a/odoo/addons/test_convert/tests/test_env.py b/odoo/addons/test_convert/tests/test_env.py index fc5d9a094d3..1e549ce3db3 100644 --- a/odoo/addons/test_convert/tests/test_env.py +++ b/odoo/addons/test_convert/tests/test_env.py @@ -39,14 +39,14 @@ class TestEnv(common.TransactionCase): model="test_convert.usered", id="test_convert.testing" ), - uid="base.user_demo" + uid="base.default_user" ) ) r = self.env.ref('test_convert.testing') self.assertEqual(r.name, 'a') - self.assertEqual(r.create_uid, self.env.ref('base.user_demo')) - self.assertEqual(r.user_id, self.env.ref('base.user_demo')) + self.assertEqual(r.create_uid, self.env.ref('base.default_user')) + self.assertEqual(r.user_id, self.env.ref('base.default_user')) def test_uid_data_function(self): self.importer( @@ -56,14 +56,14 @@ class TestEnv(common.TransactionCase): name="create", eval="[[{'name': 'b'}]]", ), - uid="base.user_demo" + uid="base.default_user" ) ) r = self.env['test_convert.usered'].search([]) self.assertEqual(r.name, 'b') - self.assertEqual(r.create_uid, self.env.ref('base.user_demo')) - self.assertEqual(r.user_id, self.env.ref('base.user_demo')) + self.assertEqual(r.create_uid, self.env.ref('base.default_user')) + self.assertEqual(r.user_id, self.env.ref('base.default_user')) def test_uid_record(self): self.importer( @@ -72,7 +72,7 @@ class TestEnv(common.TransactionCase): field('c', name="name"), model="test_convert.usered", id="test_convert.testing", - uid="base.user_demo" + uid="base.default_user" ), uid="base.user_root" ) @@ -80,8 +80,8 @@ class TestEnv(common.TransactionCase): r = self.env.ref('test_convert.testing') self.assertEqual(r.name, 'c') - self.assertEqual(r.create_uid, self.env.ref('base.user_demo')) - self.assertEqual(r.user_id, self.env.ref('base.user_demo')) + self.assertEqual(r.create_uid, self.env.ref('base.default_user')) + self.assertEqual(r.user_id, self.env.ref('base.default_user')) def test_uid_function(self): @@ -90,7 +90,7 @@ class TestEnv(common.TransactionCase): function( model="test_convert.usered", name="create", - uid="base.user_demo", + uid="base.default_user", eval="[[{'name': 'd'}]]" ), uid="base.user_root" @@ -98,8 +98,8 @@ class TestEnv(common.TransactionCase): ) r = self.env['test_convert.usered'].search([]) self.assertEqual(r.name, 'd') - self.assertEqual(r.create_uid, self.env.ref('base.user_demo')) - self.assertEqual(r.user_id, self.env.ref('base.user_demo')) + self.assertEqual(r.create_uid, self.env.ref('base.default_user')) + self.assertEqual(r.user_id, self.env.ref('base.default_user')) def test_context_data_function(self): self.env.user.tz = 'UTC' diff --git a/odoo/addons/test_impex/tests/contacts.json b/odoo/addons/test_impex/tests/contacts.json index a024d2b7ee4..8bf490bb4c0 100644 --- a/odoo/addons/test_impex/tests/contacts.json +++ b/odoo/addons/test_impex/tests/contacts.json @@ -1 +1 @@ -[["Wood y Wood Pecker", "", "Snow Street, 25", "Kainuu", "Finland", "Vendor", "1", ""], ["Roger Pecker", "Contact", "Snow Street, 27", "Kainuu", "Finland", "Vendor", "0", "Wood y Wood Pecker"], ["Sharon Pecker", "Delivery Address", "Snow Street, 28", "Kainuu", "Finland", "Vendor", "0", "Wood y Wood Pecker"], ["Thomas Pecker", "Contact", "Snow Street, 27", "Kainuu", "Finland", "Vendor", "0", "Wood y Wood Pecker"], ["Norseman Roundabout", "", "Atonium Street, 45a", "Brussels", "Belgium", "Vendor", "1", ""], ["Yvan Holiday", "Invoice Address", "Atonium Street, 45b", "Brussels", "Belgium", "Vendor", "0", "Norseman Roundabout"], ["Jack Unsworth", "Contact", "Atonium Street, 45a", "Brussels", "Belgium", "Vendor", "0", "Norseman Roundabout"]] +[["Wood y Wood Pecker", "", "Snow Street, 25", "Kainuu", "Finland", "Sellers", "1", ""], ["Roger Pecker", "Contact", "Snow Street, 27", "Kainuu", "Finland", "Sellers", "0", "Wood y Wood Pecker"], ["Sharon Pecker", "Delivery Address", "Snow Street, 28", "Kainuu", "Finland", "Sellers", "0", "Wood y Wood Pecker"], ["Thomas Pecker", "Contact", "Snow Street, 27", "Kainuu", "Finland", "Sellers", "0", "Wood y Wood Pecker"], ["Norseman Roundabout", "", "Atonium Street, 45a", "Brussels", "Belgium", "Sellers", "1", ""], ["Yvan Holiday", "Invoice Address", "Atonium Street, 45b", "Brussels", "Belgium", "Sellers", "0", "Norseman Roundabout"], ["Jack Unsworth", "Contact", "Atonium Street, 45a", "Brussels", "Belgium", "Sellers", "0", "Norseman Roundabout"]] diff --git a/odoo/addons/test_impex/tests/test_load.py b/odoo/addons/test_impex/tests/test_load.py index edd346c6220..d2bd80f7e56 100644 --- a/odoo/addons/test_impex/tests/test_load.py +++ b/odoo/addons/test_impex/tests/test_load.py @@ -6,6 +6,7 @@ import pkgutil import re from odoo import fields +from odoo.addons.base.tests.common import SavepointCaseWithUserDemo from odoo.tests import common from odoo.tools.misc import mute_logger @@ -1007,7 +1008,13 @@ class test_o2m_multiple(ImporterCase): self.assertEqual(set(values(b.child2)), set([21, 22, 23])) -class test_realworld(common.TransactionCase): +class test_realworld(SavepointCaseWithUserDemo): + + @classmethod + def setUpClass(cls): + super(test_realworld, cls).setUpClass() + cls._load_partners_set() + def test_bigfile(self): data = json.loads(pkgutil.get_data(self.__module__, 'contacts_big.json').decode('utf-8')) result = self.env['res.partner'].load(['name', 'mobile', 'email', 'image_1920'], data) diff --git a/odoo/addons/test_inherit/tests/test_inherit.py b/odoo/addons/test_inherit/tests/test_inherit.py index d47f9b0dc93..8e5502d5671 100644 --- a/odoo/addons/test_inherit/tests/test_inherit.py +++ b/odoo/addons/test_inherit/tests/test_inherit.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo from odoo.tests import common class test_inherits(common.TransactionCase): @@ -68,10 +69,12 @@ class test_inherits(common.TransactionCase): self.assertEqual(mother._fields['state'].selection, [('a', 'A'), ('d', 'D'), ('b', 'B'), ('c', 'C')]) +class test_inherits_demo(TransactionCaseWithUserDemo): + def test_50_search_one2many(self): """ check search on one2many field based on inherited many2one field. """ # create a daughter record attached to partner Demo - partner_demo = self.env.ref('base.partner_demo') + partner_demo = self.partner_demo daughter = self.env['test.inherit.daughter'].create({'partner_id': partner_demo.id}) self.assertEqual(daughter.partner_id, partner_demo) self.assertIn(daughter, partner_demo.daughter_ids) diff --git a/odoo/addons/test_main_flows/static/tests/tours/main_flow.js b/odoo/addons/test_main_flows/static/tests/tours/main_flow.js index 4b49c9e7e08..272e98c5f54 100644 --- a/odoo/addons/test_main_flows/static/tests/tours/main_flow.js +++ b/odoo/addons/test_main_flows/static/tests/tours/main_flow.js @@ -665,12 +665,6 @@ tour.register('main_flow_tour', { trigger: ".o_statusbar_buttons > button:enabled:contains('Register Payment')", content: _t("Register Payment"), position: "bottom", -}, { - trigger: "select.o_field_widget[name=journal_id]", - extra_trigger: ".modal-dialog", - content: _t("Select Journal"), - position: "bottom", - run: 'text(Bank (USD))', }, { trigger: ".modal-footer .btn-primary", content: _t("Validate"), @@ -732,7 +726,7 @@ tour.register('main_flow_tour', { trigger: ".o_selected_row .o_field_widget[name=amount] input", content: _t("Write the amount received."), position: "bottom", - run: "text 12.65", + run: "text 11.00", }, { edition: "enterprise", trigger: ".o_selected_row .o_field_widget[name=partner_id] input", @@ -762,7 +756,7 @@ tour.register('main_flow_tour', { position: "bottom", }, { edition: "enterprise", - trigger: "button.o_reconcile", + trigger: "button.o_reconcile, button.o_validate", content: _t('

Click on Reconcile

'), position: "right", }, { diff --git a/odoo/addons/test_main_flows/tests/test_flow.py b/odoo/addons/test_main_flows/tests/test_flow.py index c412b031339..fe86f8187c6 100644 --- a/odoo/addons/test_main_flows/tests/test_flow.py +++ b/odoo/addons/test_main_flows/tests/test_flow.py @@ -7,4 +7,83 @@ import odoo.tests class TestUi(odoo.tests.HttpCase): def test_01_main_flow_tour(self): + # Define minimal accounting data to run without CoA + a_expense = self.env['account.account'].create({ + 'code': 'X2120', + 'name': 'Expenses - (test)', + 'user_type_id': self.env.ref('account.data_account_type_expenses').id, + }) + a_recv = self.env['account.account'].create({ + 'code': 'X1012', + 'name': 'Debtors - (test)', + 'reconcile': True, + 'user_type_id': self.env.ref('account.data_account_type_receivable').id, + }) + a_pay = self.env['account.account'].create({ + 'code': 'X1111', + 'name': 'Creditors - (test)', + 'user_type_id': self.env.ref('account.data_account_type_payable').id, + 'reconcile': True, + }) + a_sale = self.env['account.account'].create({ + 'code': 'X2020', + 'name': 'Product Sales - (test)', + 'user_type_id': self.env.ref('account.data_account_type_revenue').id, + }) + bnk = self.env['account.account'].create({ + 'code': 'X1014', + 'name': 'Bank Current Account - (test)', + 'user_type_id': self.env.ref('account.data_account_type_liquidity').id, + }) + + self.env['ir.property'].create([{ + 'name': 'property_account_receivable_id', + 'fields_id': self.env['ir.model.fields'].search([('model', '=', 'res.partner'), ('name', '=', 'property_account_receivable_id')], limit=1).id, + 'value': 'account.account,%s' % (a_recv.id), + 'company_id': self.env.company.id, + }, { + 'name': 'property_account_payable_id', + 'fields_id': self.env['ir.model.fields'].search([('model', '=', 'res.partner'), ('name', '=', 'property_account_payable_id')], limit=1).id, + 'value': 'account.account,%s' % (a_pay.id), + 'company_id': self.env.company.id, + }, { + 'name': 'property_account_position_id', + 'fields_id': self.env['ir.model.fields'].search([('model', '=', 'res.partner'), ('name', '=', 'property_account_position_id')], limit=1).id, + 'value': False, + 'company_id': self.env.company.id, + }, { + 'name': 'property_account_expense_categ_id', + 'fields_id': self.env['ir.model.fields'].search([('model', '=', 'product.category'), ('name', '=', 'property_account_expense_categ_id')], limit=1).id, + 'value': 'account.account,%s' % (a_expense.id), + 'company_id': self.env.company.id, + }, { + 'name': 'property_account_income_categ_id', + 'fields_id': self.env['ir.model.fields'].search([('model', '=', 'product.category'), ('name', '=', 'property_account_income_categ_id')], limit=1).id, + 'value': 'account.account,%s' % (a_sale.id), + 'company_id': self.env.company.id, + }]) + self.expenses_journal = self.env['account.journal'].create({ + 'name': 'Vendor Bills - Test', + 'code': 'TEXJ', + 'type': 'purchase', + 'default_credit_account_id': a_expense.id, + 'default_debit_account_id': a_expense.id, + 'refund_sequence': True, + }) + self.bank_journal = self.env['account.journal'].create({ + 'name': 'Bank - Test', + 'code': 'TBNK', + 'type': 'bank', + 'default_credit_account_id': bnk.id, + 'default_debit_account_id': bnk.id, + }) + self.sales_journal = self.env['account.journal'].create({ + 'name': 'Customer Invoices - Test', + 'code': 'TINV', + 'type': 'sale', + 'default_credit_account_id': a_sale.id, + 'default_debit_account_id': a_sale.id, + 'refund_sequence': True, + }) + self.start_tour("/web", 'main_flow_tour', login="admin", timeout=180) diff --git a/odoo/addons/test_new_api/__init__.py b/odoo/addons/test_new_api/__init__.py index a0fdc10fe11..dc5e6b693d1 100644 --- a/odoo/addons/test_new_api/__init__.py +++ b/odoo/addons/test_new_api/__init__.py @@ -1,2 +1,4 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + from . import models diff --git a/odoo/addons/test_new_api/__manifest__.py b/odoo/addons/test_new_api/__manifest__.py index 409fb15571a..f7ba4e9cdd8 100644 --- a/odoo/addons/test_new_api/__manifest__.py +++ b/odoo/addons/test_new_api/__manifest__.py @@ -1,4 +1,6 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + { 'name': 'Test API', 'version': '1.0', @@ -8,11 +10,11 @@ 'installable': True, 'auto_install': False, 'data': [ - 'ir.model.access.csv', - 'views.xml', - 'assets.xml', + 'security/ir.model.access.csv', + 'views/test_new_api_views.xml', + 'views/test_new_api_templates.xml', + 'data/test_new_api_data.xml', ], 'demo': [ - 'demo_data.xml', ], } diff --git a/odoo/addons/test_new_api/demo_data.xml b/odoo/addons/test_new_api/data/test_new_api_data.xml similarity index 95% rename from odoo/addons/test_new_api/demo_data.xml rename to odoo/addons/test_new_api/data/test_new_api_data.xml index ec6a5c8bced..678dabbece7 100644 --- a/odoo/addons/test_new_api/demo_data.xml +++ b/odoo/addons/test_new_api/data/test_new_api_data.xml @@ -10,7 +10,7 @@ Stuff - + @@ -20,7 +20,6 @@ - What's up? diff --git a/odoo/addons/test_new_api/models/__init__.py b/odoo/addons/test_new_api/models/__init__.py new file mode 100644 index 00000000000..8c9bb6618d1 --- /dev/null +++ b/odoo/addons/test_new_api/models/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import test_new_api diff --git a/odoo/addons/test_new_api/models.py b/odoo/addons/test_new_api/models/test_new_api.py similarity index 100% rename from odoo/addons/test_new_api/models.py rename to odoo/addons/test_new_api/models/test_new_api.py diff --git a/odoo/addons/test_new_api/ir.model.access.csv b/odoo/addons/test_new_api/security/ir.model.access.csv similarity index 100% rename from odoo/addons/test_new_api/ir.model.access.csv rename to odoo/addons/test_new_api/security/ir.model.access.csv diff --git a/odoo/addons/test_new_api/tests/test_new_fields.py b/odoo/addons/test_new_api/tests/test_new_fields.py index 7622ec7e5a1..bb7c4ccbc1b 100644 --- a/odoo/addons/test_new_api/tests/test_new_fields.py +++ b/odoo/addons/test_new_api/tests/test_new_fields.py @@ -1,3 +1,6 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + # # test cases for new-style fields # @@ -9,6 +12,7 @@ from PIL import Image import psycopg2 from odoo import fields +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo from odoo.exceptions import AccessError, UserError, ValidationError from odoo.tests import common from odoo.tools import mute_logger, float_repr @@ -16,7 +20,16 @@ from odoo.tools.date_utils import add, subtract, start_of, end_of from odoo.tools.image import image_data_uri -class TestFields(common.TransactionCase): +class TestFields(TransactionCaseWithUserDemo): + + def setUp(self): + super(TestFields, self).setUp() + self.env.ref('test_new_api.discussion_0').write({'participants': [(4, self.user_demo.id)]}) + # YTI FIX ME: The cache shouldn't be inconsistent (rco is gonna fix it) + # self.env.ref('test_new_api.discussion_0').participants -> 1 user + # self.env.ref('test_new_api.discussion_0').invalidate_cache() + # self.env.ref('test_new_api.discussion_0').with_context(active_test=False).participants -> 2 users + self.env.ref('test_new_api.message_0_1').write({'author': self.user_demo.id}) def test_00_basics(self): """ test accessing new fields """ @@ -110,6 +123,9 @@ class TestFields(common.TransactionCase): def test_10_computed_custom(self): """ check definition of custom computed fields """ + # Flush demo user before creating a new ir.model.fields to avoid + # a deadlock + self.user_demo.flush() self.env['ir.model.fields'].create({ 'name': 'x_bool_false_computed', 'model_id': self.env.ref('test_new_api.model_test_new_api_message').id, @@ -148,7 +164,7 @@ class TestFields(common.TransactionCase): # create a message, assign body, and check size in several environments message1 = self.env['test_new_api.message'].create({}) - message2 = message1.with_user(self.env.ref('base.user_demo')) + message2 = message1.with_user(self.user_demo) self.assertEqual(message1.size, 0) self.assertEqual(message2.size, 0) @@ -177,6 +193,10 @@ class TestFields(common.TransactionCase): check_stored(discussion1) # switch message from discussion, and check again + + # See YTI FIXME + discussion1.invalidate_cache() + discussion2 = discussion1.copy({'name': 'Another discussion'}) message2 = discussion1.messages[0] message2.discussion = discussion2 @@ -184,7 +204,7 @@ class TestFields(common.TransactionCase): # create a new discussion with messages, and check their name user_root = self.env.ref('base.user_root') - user_demo = self.env.ref('base.user_demo') + user_demo = self.user_demo discussion3 = self.env['test_new_api.discussion'].create({ 'name': 'Stuff', 'participants': [(4, user_root.id), (4, user_demo.id)], @@ -265,7 +285,7 @@ class TestFields(common.TransactionCase): # We need to force the read in order to test the security access User.invalidate_cache() # group users as a recordset, and read them as user demo - users = (user1 + user2 + user3).with_user(self.env.ref('base.user_demo')) + users = (user1 + user2 + user3).with_user(self.user_demo) user1, user2, user3 = users # regression test: a bug invalidated the field's value from cache user1.company_type @@ -480,6 +500,7 @@ class TestFields(common.TransactionCase): def test_15_constraint(self): """ test new-style Python constraints """ discussion = self.env.ref('test_new_api.discussion_0') + discussion.flush() # remove oneself from discussion participants: we can no longer create # messages in discussion @@ -773,7 +794,7 @@ class TestFields(common.TransactionCase): def test_23_relation(self): """ test relation fields """ - demo = self.env.ref('base.user_demo') + demo = self.user_demo message = self.env.ref('test_new_api.message_0_0') # check environment of record and related records @@ -792,6 +813,9 @@ class TestFields(common.TransactionCase): self.assertEqual(demo_message.env, demo_env) self.assertEqual(demo_message.discussion.env, demo_env) + # See YTI FIXME + message.discussion.invalidate_cache() + # assign record's parent to a record in demo_env message.discussion = message.discussion.copy({'name': 'Copy'}) @@ -1249,7 +1273,7 @@ class TestFields(common.TransactionCase): access.write({'perm_read': False}) # create an environment for demo user - env = self.env(user=self.env.ref('base.user_demo')) + env = self.env(user=self.user_demo) self.assertEqual(env.user.login, "demo") # create a new message as demo user @@ -1274,7 +1298,7 @@ class TestFields(common.TransactionCase): access.write({'perm_read': False}) # create an environment for demo user - env = self.env(user=self.env.ref('base.user_demo')) + env = self.env(user=self.user_demo) self.assertEqual(env.user.login, "demo") # create a new discussion and a new message as demo user @@ -1328,6 +1352,9 @@ class TestFields(common.TransactionCase): def test_70_x2many_write(self): discussion = self.env.ref('test_new_api.discussion_0') + # See YTI FIXME + discussion.invalidate_cache() + Message = self.env['test_new_api.message'] # There must be 3 messages, 0 important self.assertEqual(len(discussion.messages), 3) @@ -1353,11 +1380,15 @@ class TestFields(common.TransactionCase): def test_70_relational_inverse(self): """ Check the consistency of relational fields with inverse(s). """ discussion = self.env.ref('test_new_api.discussion_0') - demo_discussion = discussion.with_user(self.env.ref('base.user_demo')) + demo_discussion = discussion.with_user(self.user_demo) # check that the demo user sees the same messages self.assertEqual(demo_discussion.messages, discussion.messages) + # See YTI FIXME + discussion.invalidate_cache() + demo_discussion.invalidate_cache() + # add a message as user demo messages = demo_discussion.messages message = messages.create({'discussion': discussion.id}) @@ -1413,7 +1444,7 @@ class TestFields(common.TransactionCase): # And this gives error with self.assertRaises(UserError): self.env['test_new_api.binary_svg'].with_user( - self.env.ref('base.user_demo'), + self.user_demo, ).create({ 'name': 'Test without attachment', 'image_wo_attachment': SVG, @@ -1434,7 +1465,7 @@ class TestFields(common.TransactionCase): self.assertEqual(attachment.mimetype, 'image/svg+xml') # ...but this should be neutered with demo user record = self.env['test_new_api.binary_svg'].with_user( - self.env.ref('base.user_demo'), + self.user_demo, ).create({ 'name': 'Test without attachment', 'image_attachment': SVG, @@ -1448,7 +1479,7 @@ class TestFields(common.TransactionCase): def test_92_binary_self_avatar_svg(self): from odoo.addons.base.tests.test_mimetypes import SVG - demo_user = self.env.ref('base.user_demo') + demo_user = self.user_demo # User demo changes his own avatar demo_user.with_user(demo_user).image_1920 = SVG # The SVG file should have been neutered diff --git a/odoo/addons/test_new_api/tests/test_onchange.py b/odoo/addons/test_new_api/tests/test_onchange.py index 2359acd78fe..5d544bd2875 100644 --- a/odoo/addons/test_new_api/tests/test_onchange.py +++ b/odoo/addons/test_new_api/tests/test_onchange.py @@ -1,16 +1,19 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + try: from unittest.mock import patch except ImportError: from mock import patch +from odoo.addons.base.tests.common import SavepointCaseWithUserDemo from odoo.tests import common def strip_prefix(prefix, names): size = len(prefix) return [name[size:] for name in names if name.startswith(prefix)] -class TestOnChange(common.TransactionCase): +class TestOnChange(SavepointCaseWithUserDemo): def setUp(self): super(TestOnChange, self).setUp() @@ -229,7 +232,7 @@ class TestOnChange(common.TransactionCase): def test_onchange_one2many_multi(self): """ test the effect of multiple onchange methods on one2many fields """ - partner1 = self.env.ref('base.res_partner_1') + partner1 = self.env['res.partner'].create({'name': 'A partner'}) multi = self.env['test_new_api.multi'].create({'partner': partner1.id}) line1 = multi.lines.create({'multi': multi.id}) @@ -255,7 +258,7 @@ class TestOnChange(common.TransactionCase): # -> set 'partner' on all lines # -> recompute 'name' # -> set 'name' on all lines - partner2 = self.env.ref('base.res_partner_2') + partner2 = self.env['res.partner'].create({'name': 'A second partner'}) values = { 'name': partner1.name, 'partner': partner2.id, # this one just changed @@ -326,7 +329,7 @@ class TestOnChange(common.TransactionCase): def test_onchange_specific(self): """ test the effect of field-specific onchange method """ discussion = self.env.ref('test_new_api.discussion_0') - demo = self.env.ref('base.user_demo') + demo = self.user_demo field_onchange = self.Discussion._onchange_spec() self.assertEqual(field_onchange.get('moderator'), '1') @@ -381,7 +384,7 @@ class TestOnChange(common.TransactionCase): def test_onchange_one2many_value(self): """ test the value of the one2many field inside the onchange """ discussion = self.env.ref('test_new_api.discussion_0') - demo = self.env.ref('base.user_demo') + demo = self.user_demo field_onchange = self.Discussion._onchange_spec() self.assertEqual(field_onchange.get('messages'), '1') @@ -406,7 +409,7 @@ class TestOnChange(common.TransactionCase): def test_onchange_one2many_with_domain_on_related_field(self): """ test the value of the one2many field when defined with a domain on a related field""" discussion = self.env.ref('test_new_api.discussion_0') - demo = self.env.ref('base.user_demo') + demo = self.user_demo # mimic UI behaviour, so we get subfields # (we need at least subfield: 'important_emails.important') @@ -489,7 +492,7 @@ class TestOnChange(common.TransactionCase): self.assertEqual(result['value'], onchange_result) self.env.cache.invalidate() - Message = self.env(user=self.env.ref('base.user_demo').id)['test_new_api.related'] + Message = self.env(user=self.user_demo.id)['test_new_api.related'] result = Message.onchange(value, ['message', 'message_name', 'message_currency'], field_onchange) self.assertEqual(result['value'], onchange_result) diff --git a/odoo/addons/test_new_api/tests/test_ui.py b/odoo/addons/test_new_api/tests/test_ui.py index 6fa360ac9ae..979bf8064a9 100644 --- a/odoo/addons/test_new_api/tests/test_ui.py +++ b/odoo/addons/test_new_api/tests/test_ui.py @@ -1,9 +1,13 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + import odoo.tests from odoo.tools import mute_logger +from odoo.addons.base.tests.common import HttpCaseWithUserDemo @odoo.tests.common.tagged('post_install', '-at_install') -class TestUi(odoo.tests.HttpCase): +class TestUi(HttpCaseWithUserDemo): def test_01_admin_widget_x2many(self): # FIXME: breaks if too many children of base.menu_tests diff --git a/odoo/addons/test_new_api/assets.xml b/odoo/addons/test_new_api/views/test_new_api_templates.xml similarity index 100% rename from odoo/addons/test_new_api/assets.xml rename to odoo/addons/test_new_api/views/test_new_api_templates.xml diff --git a/odoo/addons/test_new_api/views.xml b/odoo/addons/test_new_api/views/test_new_api_views.xml similarity index 100% rename from odoo/addons/test_new_api/views.xml rename to odoo/addons/test_new_api/views/test_new_api_views.xml diff --git a/odoo/addons/test_performance/__manifest__.py b/odoo/addons/test_performance/__manifest__.py index ec3daa51a3f..e33ff4d4328 100644 --- a/odoo/addons/test_performance/__manifest__.py +++ b/odoo/addons/test_performance/__manifest__.py @@ -7,7 +7,4 @@ 'data': [ 'security/ir.model.access.csv', ], - 'demo': [ - 'demo/demo.xml', - ], } diff --git a/odoo/addons/test_performance/demo/demo.xml b/odoo/addons/test_performance/demo/demo.xml deleted file mode 100644 index 327e9082319..00000000000 --- a/odoo/addons/test_performance/demo/demo.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - Object 0 - 0 - - - - Object 1 - 10 - - - - Object 2 - 20 - - - - Object 3 - 30 - - - - Object 4 - 40 - - - - diff --git a/odoo/addons/test_performance/tests/test_performance.py b/odoo/addons/test_performance/tests/test_performance.py index 1db2e33f6d2..eaae5f41f10 100644 --- a/odoo/addons/test_performance/tests/test_performance.py +++ b/odoo/addons/test_performance/tests/test_performance.py @@ -4,11 +4,44 @@ from collections import defaultdict import json +from odoo.addons.base.tests.common import SavepointCaseWithUserDemo from odoo.tests.common import TransactionCase, users, warmup, tagged from odoo.tools import mute_logger -class TestPerformance(TransactionCase): +class TestPerformance(SavepointCaseWithUserDemo): + + @classmethod + def setUpClass(cls): + super(TestPerformance, cls).setUpClass() + cls._load_partners_set() + + partner3 = cls.env['res.partner'].search([('name', '=', 'AnalytIQ')], limit=1) + partner4 = cls.env['res.partner'].search([('name', '=', 'Urban Trends')], limit=1) + partner10 = cls.env['res.partner'].search([('name', '=', 'Ctrl-Alt-Fix')], limit=1) + partner12 = cls.env['res.partner'].search([('name', '=', 'Ignitive Labs')], limit=1) + + cls.env['test_performance.base'].create([{ + 'name': 'Object 0', + 'value': 0, + 'partner_id': partner3.id, + }, { + 'name': 'Object 1', + 'value': 10, + 'partner_id': partner3.id, + }, { + 'name': 'Object 2', + 'value': 20, + 'partner_id': partner4.id, + }, { + 'name': 'Object 3', + 'value': 30, + 'partner_id': partner10.id, + }, { + 'name': 'Object 4', + 'value': 40, + 'partner_id': partner12.id, + }]) @users('__system__', 'demo') @warmup @@ -377,9 +410,10 @@ class TestPerformance(TransactionCase): def expected_read_group(self): groups = defaultdict(list) - for record in self.env['test_performance.base'].search([]): + all_records = self.env['test_performance.base'].search([]) + for record in all_records: groups[record.partner_id.id].append(record.value) - partners = self.env['res.partner'].search([('id', 'in', list(groups))]) + partners = self.env['res.partner'].search([('id', 'in', all_records.mapped('partner_id').ids)]) return [{ '__domain': [('partner_id', '=', partner.id)], 'partner_id': (partner.id, partner.display_name),