from odoo import Command from odoo.tests import tagged, HttpCase from odoo.addons.sale.tests.common import TestSaleCommon @tagged('post_install', '-at_install') class TestCommissionTours(TestSaleCommon, HttpCase): """Сквозной UI-тест модуля комиссий через web_tour. Данные готовятся через ORM (R1), действия пользователя выполняются в интерфейсе турами, результат каждого этапа проверяется по БД. """ @classmethod def setUpClass(cls): super().setUpClass() company = cls.company_data['company'] cls.purchase_journal = cls.company_data['default_journal_purchase'] cls.expense_account = cls.company_data['default_account_expense'] # --- Клиент --- cls.customer = cls.env['res.partner'].create({ 'name': 'Tour Customer', 'company_id': False, }) # --- Товар: складируемый/потребляемый, цена 100, без налогов --- cls.tour_product = cls.env['product.product'].create({ 'name': 'Tour Product', 'type': 'consu', 'list_price': 100.0, 'taxes_id': [Command.clear()], }) # --- Партнёры-получатели комиссий --- cls.agent_10 = cls.env['res.partner'].create({'name': 'Tour Agent Ten'}) cls.agent_5 = cls.env['res.partner'].create({'name': 'Tour Agent Five'}) Commission = cls.env['commission.commission'] cls.commission_10 = Commission.create({ 'name': 'Tour Commission 10', 'calc_type': 'percentage', 'percentage': 10.0, 'partner_id': cls.agent_10.id, 'journal_id': cls.purchase_journal.id, 'account_id': cls.expense_account.id, 'company_id': company.id, }) cls.commission_5 = Commission.create({ 'name': 'Tour Commission 5', 'calc_type': 'percentage', 'percentage': 5.0, 'partner_id': cls.agent_5.id, 'journal_id': cls.purchase_journal.id, 'account_id': cls.expense_account.id, 'company_id': company.id, }) # --- Пользователь: продавец + менеджер комиссий --- # group_commission_manager включает group_commission_viewer. cls.tour_user = cls.env['res.users'].create({ 'name': 'Tour Commission Manager', 'login': 'tour_commission', 'password': 'tour_commission', 'company_id': company.id, 'company_ids': [Command.set([company.id])], 'group_ids': [Command.set([ cls.env.ref('sales_team.group_sale_salesman_all_leads').id, cls.env.ref('ruodoo_commission.group_commission_manager').id, # Право просматривать счета поставщика (открытие по смарт-кнопке). cls.env.ref('account.group_account_invoice').id, ])], }) # ------------------------------------------------------------------ def _get_order(self): return self.env['sale.order'].search( [('partner_id', '=', self.customer.id)], limit=1, ) def test_commission_full_flow(self): # =============== Этап 1: заказ + комиссии + начисление =============== self.start_tour( '/odoo', 'ruodoo_commission_order_tour', login='tour_commission', ) order = self._get_order() self.assertTrue(order, msg="Этап 1: заказ должен быть создан") self.assertEqual( order.state, 'sale', msg="Этап 1: заказ должен быть подтверждён (state='sale')", ) self.assertEqual( len(order.order_line), 1, msg="Этап 1: в заказе должна быть одна строка", ) line = order.order_line self.assertEqual( line.product_id, self.tour_product, msg="Этап 1: товар строки — Tour Product", ) self.assertEqual( line.product_uom_qty, 10.0, msg="Этап 1: количество должно быть 10", ) self.assertEqual( line.commission_ids, self.commission_10 | self.commission_5, msg="Этап 1: к строке должны быть привязаны обе комиссии", ) # Суммы комиссий: 10 шт × 100 = 1000; 10% = 100; 5% = 50; итог 150. self.assertAlmostEqual( line.commission_amount, 150.0, msg="Этап 1: сумма комиссий строки должна быть 150", ) self.assertAlmostEqual( order.amount_commission, 150.0, msg="Этап 1: «ИТОГО КОМИССИЙ» заказа должно быть 150", ) # Комиссии не входят в итог заказа. self.assertAlmostEqual( order.amount_total, 1000.0, msg="Этап 1: итог заказа не должен включать комиссии (1000)", ) # Начислены счета комиссий: два партнёра-получателя → два билла. bills = order.commission_bill_ids self.assertEqual( len(bills), 2, msg="Этап 1: должно быть два счёта комиссий (по получателям)", ) self.assertEqual( set(bills.mapped('move_type')), {'in_invoice'}, msg="Этап 1: счета комиссий — счета поставщика (in_invoice)", ) self.assertEqual( set(bills.mapped('state')), {'posted'}, msg="Этап 1: счета комиссий должны быть проведены", ) # Суммы в биллах совпадают с суммами комиссий заказа. bill_10 = bills.filtered(lambda m: m.partner_id == self.agent_10) bill_5 = bills.filtered(lambda m: m.partner_id == self.agent_5) self.assertAlmostEqual( bill_10.amount_total, 100.0, msg="Этап 1: счёт агенту 10% должен быть на 100", ) self.assertAlmostEqual( bill_5.amount_total, 50.0, msg="Этап 1: счёт агенту 5% должен быть на 50", ) self.assertAlmostEqual( sum(bills.mapped('amount_total')), order.amount_commission, msg="Этап 1: сумма счетов должна совпадать с итогом комиссий заказа", ) # Счета подставляются правильно: журнал и счёт расходов из карточки. self.assertEqual( set(bills.mapped('journal_id')), {self.purchase_journal}, msg="Этап 1: журнал счетов — из настроек комиссии", ) self.assertEqual( set(bills.invoice_line_ids.mapped('account_id')), {self.expense_account}, msg="Этап 1: счёт расходов строк — из настроек комиссии", ) # =============== Этап 2: смарт-кнопка «Комиссии» =============== self.assertEqual( order.commission_bill_count, 2, msg="Этап 2: счётчик смарт-кнопки должен быть 2", ) self.start_tour( '/odoo', 'ruodoo_commission_smart_button_tour', login='tour_commission', ) # =============== Этап 3: отмена заказа =============== bill_ids = bills.ids self.start_tour( '/odoo', 'ruodoo_commission_cancel_tour', login='tour_commission', ) order.invalidate_recordset() self.assertEqual( order.state, 'cancel', msg="Этап 3: заказ должен быть отменён", ) remaining = self.env['account.move'].search([('id', 'in', bill_ids)]) self.assertFalse( remaining, msg="Этап 3: счета комиссий должны быть удалены при отмене заказа", )