Files
public/rsbu_payroll/models/rsbu_employee_child.py

85 lines
4.6 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.
"""Дети сотрудника для стандартного вычета по НДФЛ (ст. 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)