Files
public/ruodoo_commission/models/commission.py

142 lines
6.3 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 import fields, models, _
from odoo.exceptions import UserError
from odoo.tools.safe_eval import safe_eval
# Подсказка для поля формулы: доступные переменные и обязательный результат.
CODE_HELP = (
"Python-код расчёта комиссии. Результат присвоить переменной `result`.\n"
"Доступные переменные:\n"
" line — строка заказа (sale.order.line)\n"
" order — заказ (sale.order)\n"
" product — товар строки (product.product)\n"
" qty — количество (product_uom_qty)\n"
" price_unit — цена за единицу\n"
" price_subtotal — сумма строки без налогов\n"
" partner — контрагент заказа (res.partner)\n"
" commission — текущий вид комиссии (commission.commission)\n"
"Пример: result = price_subtotal * 0.05"
)
DEFAULT_CODE = "result = price_subtotal * 0.0"
class CommissionCommission(models.Model):
_name = 'commission.commission'
_description = 'Вид комиссии агенту'
_order = 'name'
name = fields.Char(string='Наименование', required=True, translate=True)
active = fields.Boolean(string='Активно', default=True)
company_id = fields.Many2one(
'res.company', string='Компания', required=True,
default=lambda self: self.env.company,
)
calc_type = fields.Selection(
selection=[
('percentage', 'Процент'),
('code', 'Формула'),
],
string='Способ расчёта', required=True, default='percentage',
)
percentage = fields.Float(
string='Процент, %', digits=(16, 4),
help='Процент от суммы строки без налогов (для способа «Процент»).',
)
amount_python_compute = fields.Text(
string='Формула (Python)', default=DEFAULT_CODE, help=CODE_HELP,
)
# --- Настройки будущих проводок вендор-билла ---
journal_id = fields.Many2one(
'account.journal', string='Журнал', required=True,
domain="[('type', '=', 'purchase'), ('company_id', '=', company_id)]",
help='Журнал для счетов поставщика (Vendor Bill) по комиссии.',
)
account_id = fields.Many2one(
'account.account', string='Счёт расходов', required=True,
domain="[('account_type', 'in', ('expense', 'expense_depreciation', 'expense_direct_cost'))]",
help='Счёт расходов (тип «Расходы»), на котором копятся комиссии.',
)
partner_id = fields.Many2one(
'res.partner', string='Получатель', required=True,
help='Партнёр-агент, на кого выставляется вендор-билл по комиссии.',
)
analytic_account_id = fields.Many2one(
'account.analytic.account', string='Аналитический счёт',
help='Опциональный аналитический счёт для строки вендор-билла.',
)
# ------------------------------------------------------------------
# Расчёт суммы комиссии
# ------------------------------------------------------------------
def _get_eval_context(self, line):
"""Ограниченный контекст выполнения формулы комиссии."""
self.ensure_one()
return {
'line': line,
'order': line.order_id,
'product': line.product_id,
'qty': line.product_uom_qty,
'price_unit': line.price_unit,
'price_subtotal': line.price_subtotal,
'partner': line.order_id.partner_id,
'commission': self,
'result': 0.0,
}
def _compute_amount(self, line):
"""Сумма комиссии для конкретной строки заказа.
:param line: sale.order.line
:return: float — сумма комиссии в валюте заказа
"""
self.ensure_one()
if self.calc_type == 'percentage':
return line.price_subtotal * (self.percentage or 0.0) / 100.0
# calc_type == 'code' — формула result = ...
localdict = self._get_eval_context(line)
try:
safe_eval(
self.amount_python_compute or '',
localdict, mode='exec',
)
except Exception as ex:
raise UserError(_(
"Ошибка в формуле комиссии «%(name)s»:\n%(err)s",
name=self.name, err=ex,
)) from ex
try:
return float(localdict.get('result', 0.0))
except (TypeError, ValueError):
raise UserError(_(
"Формула комиссии «%(name)s» вернула нечисловой результат.",
name=self.name,
)) from None
def _prepare_bill_line_vals(self, line, amount):
"""Значения строки вендор-билла для этой комиссии по строке заказа.
:param line: sale.order.line — исходная строка заказа
:param amount: float — рассчитанная сумма комиссии
:return: dict значений для account.move.line (invoice_line_ids)
"""
self.ensure_one()
vals = {
'name': _(
"Комиссия «%(commission)s» по %(order)s / %(product)s",
commission=self.name,
order=line.order_id.name,
product=line.product_id.display_name or line.name,
),
'account_id': self.account_id.id,
'quantity': 1.0,
'price_unit': amount,
}
if self.analytic_account_id:
# analytic_distribution — JSON {id_счёта: процент}, сумма = 100%.
vals['analytic_distribution'] = {str(self.analytic_account_id.id): 100.0}
return vals