"""Дети сотрудника для стандартного вычета по НДФЛ (ст. 218 НК РФ). Размер вычета зависит от очерёдности рождения и возраста ребёнка; вычет на ребёнка-инвалида суммируется с вычетом по очерёдности. Право на вычет прекращается по достижении возраста (18 лет, либо 24 при очной форме обучения) и при превышении дохода 450 000 ₽ нарастающим итогом (проверяется при расчёте НДФЛ, не здесь). """ from dateutil.relativedelta import relativedelta from odoo import _, api, fields, models # Размеры детских вычетов по очерёдности (₽/мес), с 2025 (пп.4 п.1 ст.218 НК). CHILD_DEDUCTION_BY_ORDER = {1: 1400.0, 2: 2800.0, 3: 6000.0} # Вычет на ребёнка-инвалида (₽/мес): родитель/усыновитель — 12000, # опекун/попечитель/приёмный — 6000. DISABLED_DEDUCTION_PARENT = 12000.0 DISABLED_DEDUCTION_GUARDIAN = 6000.0 class RsbuEmployeeChild(models.Model): _name = 'rsbu.employee.child' _description = 'РСБУ — Ребёнок сотрудника (вычет НДФЛ)' _order = 'birthdate, id' employee_id = fields.Many2one( 'hr.employee', string='Сотрудник', required=True, ondelete='cascade', index=True) name = fields.Char(string='ФИО ребёнка') birthdate = fields.Date(string='Дата рождения', required=True) order = fields.Integer( string='Очерёдность', required=True, default=1, help='Порядковый номер ребёнка по рождению (1-й, 2-й, 3-й…). ' 'Определяет размер вычета: 1400 / 2800 / 6000 ₽. Учитываются ' 'все дети, включая совершеннолетних, при определении очерёдности.') is_disabled = fields.Boolean( string='Ребёнок-инвалид', help='Добавляет вычет 12 000 ₽ (родителю/усыновителю) или 6 000 ₽ ' '(опекуну), суммируется с вычетом по очерёдности.') is_student = fields.Boolean( string='Очная форма обучения', help='Продлевает право на вычет до 24 лет (иначе — до 18 лет).') is_guardian = fields.Boolean( string='Опекун/попечитель', help='Отмечено — применяется вычет на ребёнка-инвалида 6 000 ₽ ' '(опекун), иначе 12 000 ₽ (родитель/усыновитель).') single_parent = fields.Boolean( string='Единственный родитель', help='Двойной вычет единственному родителю (пп.4 п.1 ст.218 НК).') def _age_on(self, date): """Полных лет ребёнку на указанную дату.""" self.ensure_one() if not self.birthdate: return 0 return relativedelta(date, self.birthdate).years def _is_eligible_on(self, date): """Даёт ли ребёнок право на вычет на указанную дату (по возрасту).""" self.ensure_one() age = self._age_on(date) limit = 24 if self.is_student else 18 return age < limit def _deduction_amount(self, date): """Сумма месячного вычета по ребёнку на дату (по очерёдности + инвалидность), с учётом двойного вычета единственному родителю.""" self.ensure_one() if not self._is_eligible_on(date): return 0.0 amount = CHILD_DEDUCTION_BY_ORDER.get( self.order, CHILD_DEDUCTION_BY_ORDER[3]) if self.order else 0.0 if self.is_disabled: amount += (DISABLED_DEDUCTION_GUARDIAN if self.is_guardian else DISABLED_DEDUCTION_PARENT) if self.single_parent: amount *= 2.0 return amount @api.depends('name', 'order', 'birthdate') def _compute_display_name(self): for rec in self: rec.display_name = '%s (%s, №%s)' % ( rec.name or _('Ребёнок'), rec.birthdate or '?', rec.order or 0)