from odoo import api, fields, models from odoo.exceptions import ValidationError class AccountMoveTemplateTag(models.Model): _name = 'account.move.template.tag' _description = 'Признак шаблона' name = fields.Char(string='Название', required=True, translate=True) color = fields.Integer(string='Цвет') class AccountMoveTemplate(models.Model): _name = 'account.move.template' _description = 'Шаблон типовой операции' name = fields.Char(string='Название', required=True) description = fields.Text(string='Описание') tag_ids = fields.Many2many( comodel_name='account.move.template.tag', string='Признаки', ) line_ids = fields.One2many( comodel_name='account.move.template.line', inverse_name='template_id', string='Строки шаблона', ) @api.constrains('line_ids') def _check_balance(self): for template in self: if not template.line_ids: raise ValidationError( 'Шаблон должен содержать хотя бы одну строку.' ) debit_sum = sum( line.percent for line in template.line_ids if line.move_type == 'debit' ) credit_sum = sum( line.percent for line in template.line_ids if line.move_type == 'credit' ) if round(debit_sum, 2) != round(credit_sum, 2): diff = round(abs(debit_sum - credit_sum), 2) raise ValidationError( f'Сумма дебета ({debit_sum:.2f}%) не равна сумме кредита ' f'({credit_sum:.2f}%), разница: {diff:.2f}%' ) class AccountMoveTemplateLine(models.Model): _name = 'account.move.template.line' _description = 'Строка шаблона типовой операции' template_id = fields.Many2one( comodel_name='account.move.template', string='Шаблон', required=True, ondelete='cascade', ) account_id = fields.Many2one( comodel_name='account.account', string='Счёт', required=True, ondelete='restrict', ) move_type = fields.Selection( selection=[('debit', 'Дебет'), ('credit', 'Кредит')], string='Сторона', required=True, ) percent = fields.Float( string='Процент', required=True, digits=(5, 2), ) line_type = fields.Selection( selection=[ ('product', 'Продуктовая строка (заменяет счёт)'), ('payment', 'Строка оплаты (receivable/payable)') ], string='Тип строки', required=True, default='product', help='Продуктовая строка заменяет счёт в существующих product-строках инвойса. ' 'Строка оплаты создаёт новую payment_term строку.' ) @api.constrains('percent') def _check_percent(self): for line in self: if line.percent < 0.01 or line.percent > 100.0: raise ValidationError( 'Процент должен быть от 0.01 до 100.00.' )