Files
public/rsbu_payroll/models/hr_employee.py

129 lines
8.4 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
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