Files
public/ruodoo_commission/tests/test_commission.py

186 lines
8.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from odoo.tests import tagged
from odoo.exceptions import UserError
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
@tagged('post_install', '-at_install')
class TestCommission(AccountTestInvoicingCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
# AccountTestInvoicingCommon работает под пользователем бухгалтерии
# в контексте тестовой компании, но без прав на продажи и комиссии.
# Добавляем нужные группы этому пользователю (компания сохраняется).
cls.env.user.group_ids |= (
cls.env.ref('sales_team.group_sale_salesman_all_leads')
| cls.env.ref('ruodoo_commission.group_commission_manager')
)
cls.company = cls.company_data['company']
cls.purchase_journal = cls.company_data['default_journal_purchase']
cls.expense_account = cls.company_data['default_account_expense']
cls.agent_a = cls.env['res.partner'].create({'name': 'Агент А'})
cls.agent_b = cls.env['res.partner'].create({'name': 'Агент Б'})
cls.customer = cls.env['res.partner'].create({'name': 'Покупатель ООО'})
cls.product = cls.env['product.product'].create({
'name': 'Товар А', 'type': 'consu', 'lst_price': 100.0,
})
cls.commission_pct = cls.env['commission.commission'].create({
'name': 'Комиссия 10%',
'calc_type': 'percentage',
'percentage': 10.0,
'partner_id': cls.agent_a.id,
'journal_id': cls.purchase_journal.id,
'account_id': cls.expense_account.id,
})
cls.commission_code = cls.env['commission.commission'].create({
'name': 'Комиссия по формуле',
'calc_type': 'code',
'amount_python_compute': 'result = price_subtotal * 0.05',
'partner_id': cls.agent_b.id,
'journal_id': cls.purchase_journal.id,
'account_id': cls.expense_account.id,
})
def _make_order(self, commissions=None, price_unit=1000.0, qty=1):
line_vals = {
'product_id': self.product.id,
'product_uom_qty': qty,
'price_unit': price_unit,
}
if commissions:
line_vals['commission_ids'] = [(6, 0, [c.id for c in commissions])]
return self.env['sale.order'].create({
'partner_id': self.customer.id,
'order_line': [(0, 0, line_vals)],
})
# ---------------- Расчёт ----------------
def test_percentage_amount(self):
order = self._make_order([self.commission_pct], price_unit=1000.0)
line = order.order_line
# 10% от price_subtotal (1000) = 100
self.assertAlmostEqual(line.commission_amount, 100.0)
def test_code_formula_amount(self):
order = self._make_order([self.commission_code], price_unit=1000.0)
# 5% от 1000 = 50
self.assertAlmostEqual(order.order_line.commission_amount, 50.0)
def test_multiple_commissions_on_line(self):
order = self._make_order(
[self.commission_pct, self.commission_code], price_unit=1000.0,
)
# 100 + 50 = 150
self.assertAlmostEqual(order.order_line.commission_amount, 150.0)
self.assertAlmostEqual(order.amount_commission, 150.0)
def test_commission_not_in_amount_total(self):
order = self._make_order([self.commission_pct], price_unit=1000.0)
# amount_total не должен включать комиссию
self.assertNotEqual(order.amount_total, 0.0)
self.assertAlmostEqual(order.amount_total, order.amount_untaxed + order.amount_tax)
def test_bad_formula_raises(self):
bad = self.env['commission.commission'].create({
'name': 'Плохая формула',
'calc_type': 'code',
'amount_python_compute': 'result = undefined_var + 1',
'partner_id': self.agent_a.id,
'journal_id': self.purchase_journal.id,
'account_id': self.expense_account.id,
})
# Сумма комиссии — хранимое вычисляемое поле, ошибка формулы
# проявляется при вычислении (создании строки заказа).
with self.assertRaises(UserError):
order = self._make_order([bad], price_unit=1000.0)
order.order_line._compute_commission_amount()
# ---------------- Начисление ----------------
def test_accrue_creates_posted_bills_by_partner(self):
order = self._make_order(
[self.commission_pct, self.commission_code], price_unit=1000.0,
)
order.action_confirm()
self.assertEqual(order.state, 'sale')
order.action_accrue_commission()
bills = order.commission_bill_ids
# Два разных получателя -> два билла
self.assertEqual(len(bills), 2)
self.assertEqual(set(bills.mapped('move_type')), {'in_invoice'})
self.assertEqual(set(bills.mapped('state')), {'posted'})
self.assertEqual(bills.mapped('commission_sale_order_id'), order)
bill_a = bills.filtered(lambda m: m.partner_id == self.agent_a)
bill_b = bills.filtered(lambda m: m.partner_id == self.agent_b)
self.assertAlmostEqual(bill_a.amount_total, 100.0)
self.assertAlmostEqual(bill_b.amount_total, 50.0)
# Счёт расходов проставлен на строках
self.assertEqual(
set(bill_a.invoice_line_ids.mapped('account_id')),
{self.expense_account},
)
def test_accrue_requires_confirmed(self):
order = self._make_order([self.commission_pct])
with self.assertRaises(UserError):
order.action_accrue_commission()
def test_accrue_dedup(self):
order = self._make_order([self.commission_pct])
order.action_confirm()
order.action_accrue_commission()
with self.assertRaises(UserError):
order.action_accrue_commission()
def test_accrue_skips_zero(self):
zero = self.env['commission.commission'].create({
'name': 'Комиссия 0%',
'calc_type': 'percentage', 'percentage': 0.0,
'partner_id': self.agent_a.id,
'journal_id': self.purchase_journal.id,
'account_id': self.expense_account.id,
})
order = self._make_order([zero])
order.action_confirm()
with self.assertRaises(UserError):
order.action_accrue_commission()
self.assertFalse(order.commission_bill_ids)
# ---------------- Отмена заказа ----------------
def test_cancel_order_removes_bills(self):
order = self._make_order([self.commission_pct])
order.action_confirm()
order.action_accrue_commission()
self.assertTrue(order.commission_bill_ids)
bill_ids = order.commission_bill_ids.ids
order.action_cancel()
self.assertEqual(order.state, 'cancel')
# Биллы удалены
remaining = self.env['account.move'].search([('id', 'in', bill_ids)])
self.assertFalse(remaining)
def test_cancel_order_no_bills_ok(self):
order = self._make_order([self.commission_pct])
order.action_confirm()
# Без начисления отмена не должна падать
order.action_cancel()
self.assertEqual(order.state, 'cancel')
# ---------------- Смарт-кнопка ----------------
def test_bill_count_and_action(self):
order = self._make_order(
[self.commission_pct, self.commission_code],
)
order.action_confirm()
order.action_accrue_commission()
self.assertEqual(order.commission_bill_count, 2)
action = order.action_view_commission_bills()
self.assertEqual(action['res_model'], 'account.move')
self.assertIn('commission_sale_order_id', str(action['domain']))