129 lines
8.4 KiB
Python
129 lines
8.4 KiB
Python
from odoo import fields, models
|
||
|
||
|
||
class HrEmployee(models.Model):
|
||
_inherit = 'hr.employee'
|
||
|
||
# --- Персональные данные для отчётности (перс. сведения, РСВ, ЕФС-1,
|
||
# 6-НДФЛ). Дата рождения/гражданство берутся из штатных hr-полей
|
||
# (birthday, country_id). TODO(сверка форматов/справочников). ---
|
||
rsbu_snils = fields.Char(
|
||
string='СНИЛС',
|
||
help='Страховой номер индивидуального лицевого счёта (формат '
|
||
'XXX-XXX-XXX YY). Обязателен для персонифицированной отчётности '
|
||
'и ЕФС-1.')
|
||
rsbu_inn = fields.Char(
|
||
string='ИНН физлица',
|
||
help='ИНН сотрудника (12 знаков). Для 6-НДФЛ и РСВ.')
|
||
rsbu_insured_category = fields.Char(
|
||
string='Код категории застрахованного',
|
||
default='НР',
|
||
help='Код категории застрахованного лица для РСВ/перс. сведений '
|
||
'(напр. «НР» — наёмные работники по единому тарифу, «МС» — '
|
||
'выплаты сверх МРОТ по льготному тарифу МСП). TODO(сверка '
|
||
'справочника кодов).')
|
||
# --- Реквизиты для раздела 3 РСВ (персонифицированные сведения) ---
|
||
rsbu_citizenship_code = fields.Char(
|
||
string='Гражданство (ОКСМ)', default='643', size=3,
|
||
help='Числовой код страны гражданства по ОКСМ (643 — Россия). '
|
||
'Атрибут «Гражд» в разделе 3 РСВ.')
|
||
rsbu_sex = fields.Selection(
|
||
selection=[('1', 'Мужской'), ('2', 'Женский')],
|
||
string='Пол',
|
||
help='Пол застрахованного лица (атрибут «Пол» в разделе 3 РСВ).')
|
||
rsbu_id_doc_code = fields.Char(
|
||
string='Код вида документа (ДУЛ)', default='21', size=2,
|
||
help='Код вида документа, удостоверяющего личность (21 — паспорт '
|
||
'гражданина РФ). Атрибут «КодВидДок» в разделе 3 РСВ.')
|
||
rsbu_id_doc_number = fields.Char(
|
||
string='Серия и номер документа',
|
||
help='Серия и номер документа, удостоверяющего личность (атрибут '
|
||
'«СерНомДок» в разделе 3 РСВ), напр. «45 04 123456».')
|
||
rsbu_okz_code = fields.Char(
|
||
string='Код по ОКЗ', size=6,
|
||
help='Кодовое обозначение занятия по Общероссийскому классификатору '
|
||
'занятий (ОКЗ), формат NNNN.N (напр. «2512.1»). Элемент '
|
||
'«КодВФпоОКЗ» мероприятия ЕФС-1 (СЗВ-ТД); обязателен для приёма, '
|
||
'перевода, увольнения и ряда других мероприятий.')
|
||
rsbu_taxpayer_status = fields.Selection(
|
||
selection=[
|
||
('1', 'Резидент РФ'),
|
||
('2', 'Нерезидент РФ'),
|
||
('3', 'Высококвалифицированный специалист'),
|
||
('4', 'Участник госпрограммы переселения'),
|
||
('5', 'Беженец / временное убежище'),
|
||
('6', 'Иностранец по патенту'),
|
||
('7', 'Гражданин ЕАЭС'),
|
||
],
|
||
string='Статус налогоплательщика', default='1',
|
||
help='Статус для 6-НДФЛ и порядка исчисления НДФЛ (ст.224 НК): '
|
||
'резидент, ВКС, патент, ЕАЭС — прогрессивная шкала 13–22%; '
|
||
'обычный нерезидент — 30% без вычетов. TODO(сверка справочника).')
|
||
|
||
# --- Стандартные вычеты по НДФЛ (ст. 218 НК) ---
|
||
rsbu_child_ids = fields.One2many(
|
||
'rsbu.employee.child', 'employee_id', string='Дети (для вычетов)',
|
||
help='Дети сотрудника для стандартного вычета по НДФЛ. Очередность '
|
||
'и возраст определяют размер вычета; система прекращает вычет '
|
||
'по достижении лимита дохода 450 000 ₽ и по возрасту ребёнка.')
|
||
rsbu_personal_deduction_code = fields.Selection(
|
||
selection=[
|
||
('none', 'Нет'),
|
||
('104', '500 ₽/мес (код 104)'),
|
||
('105', '3000 ₽/мес (код 105)'),
|
||
],
|
||
string='Личный вычет', default='none',
|
||
help='Личный стандартный вычет на работника (пп.1–2 п.1 ст.218 НК): '
|
||
'3000 ₽ (чернобыльцы, инвалиды ВОВ), 500 ₽ (Герои, инвалиды '
|
||
'I–II гр., ветераны). Лимита по доходу нет.')
|
||
rsbu_gto_deduction = fields.Boolean(
|
||
string='Вычет ГТО (18 000 ₽/год)',
|
||
help='Сотрудник сдал нормативы ГТО и получил знак отличия — разовый '
|
||
'годовой вычет 18 000 ₽ (пп.2.1 п.1 ст.218 НК, с 2025).')
|
||
|
||
def rsbu_is_progressive_ndfl(self):
|
||
"""Применяется ли прогрессивная шкала 13–22% (иначе 30% нерезидент).
|
||
|
||
Прогрессия — резиденты (1), ВКС (3), патент (6), ЕАЭС (7). Обычный
|
||
нерезидент (2) — 30% без вычетов. Переселенцы (4) и беженцы (5)
|
||
облагаются как резиденты по трудовым доходам — прогрессия. (ст.224 НК)
|
||
"""
|
||
self.ensure_one()
|
||
return self.rsbu_taxpayer_status != '2'
|
||
|
||
def rsbu_allows_deductions(self):
|
||
"""Право на стандартные вычеты (только резиденты-статус для шкалы).
|
||
|
||
Нерезиденты (в т.ч. ВКС/патент/ЕАЭС до приобретения резидентства)
|
||
вычеты не получают (п.3 ст.210, п.3 ст.224 НК). В базовом сценарии
|
||
вычеты даём статусу «резидент РФ»; для остальных — TODO по факту
|
||
резидентства (нужен учёт дней пребывания).
|
||
"""
|
||
self.ensure_one()
|
||
return self.rsbu_taxpayer_status == '1'
|
||
|
||
# Данные для расчёта пособий (больничный и т.п.).
|
||
# Позже средний заработок будет вычисляться калькулятором за 2 года.
|
||
rsbu_insurance_years = fields.Float(
|
||
string='Страховой стаж, лет',
|
||
default=0.0,
|
||
help='Страховой стаж сотрудника. Определяет процент оплаты больничного: '
|
||
'≥8 лет — 100%, 5–8 лет — 80%, <5 лет — 60%.')
|
||
rsbu_avg_daily_wage = fields.Monetary(
|
||
string='Средний дневной заработок',
|
||
currency_field='rsbu_currency_id',
|
||
help='Средний дневной заработок для расчёта пособий (больничный, '
|
||
'отпускные). Пока задаётся вручную; позже — калькулятор за 2 года.')
|
||
rsbu_currency_id = fields.Many2one(
|
||
'res.currency', related='company_id.currency_id', readonly=True)
|
||
|
||
def rsbu_sick_rate(self):
|
||
"""Процент оплаты больничного по страховому стажу (доля 0..1)."""
|
||
self.ensure_one()
|
||
years = self.rsbu_insurance_years or 0.0
|
||
if years >= 8:
|
||
return 1.0
|
||
if years >= 5:
|
||
return 0.8
|
||
return 0.6
|