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