# -*- coding: utf-8 -*- """Персонифицированные сведения о физических лицах (ПСВ, КНД 1151162). Форма ФНС NO_PERSSVFL версии 5.01. Подаётся ЕЖЕМЕСЯЧНО в налоговый орган: по каждому застрахованному лицу — ФИО, СНИЛС, ИНН и сумма выплат за месяц. Автозаполнение строк из помесячных итогов выплат rsbu.rsv.summary (поле payments) за отчётный месяц. """ from odoo import api, fields, models class RsbuPersInfo(models.Model): _name = 'rsbu.pers.info' _description = 'РСБУ — Персонифицированные сведения (ПСВ)' _order = 'year desc, month desc, id desc' _check_company_auto = True name = fields.Char(string='Наименование', compute='_compute_name', store=True) company_id = fields.Many2one( 'res.company', string='Компания', required=True, index=True, default=lambda self: self.env.company) year = fields.Integer(string='Год', required=True, default=lambda self: fields.Date.today().year) month = fields.Integer( string='Отчётный месяц', required=True, default=lambda self: fields.Date.today().month, help='Календарный месяц, за который подаются сведения.') date_doc = fields.Date( string='Дата документа', default=fields.Date.context_today) currency_id = fields.Many2one( 'res.currency', related='company_id.currency_id') state = fields.Selection( selection=[('draft', 'Черновик'), ('computed', 'Рассчитано')], default='draft', string='Состояние', copy=False) line_ids = fields.One2many( 'rsbu.pers.info.line', 'report_id', string='Сведения по физлицам') @api.depends('year', 'month') def _compute_name(self): names = ['', 'январь', 'февраль', 'март', 'апрель', 'май', 'июнь', 'июль', 'август', 'сентябрь', 'октябрь', 'ноябрь', 'декабрь'] for rec in self: m = names[rec.month] if rec.month and 1 <= rec.month <= 12 else '?' rec.name = 'Перс. сведения: %s %s' % (m, rec.year or '?') def _month_bounds(self): import calendar self.ensure_one() last = calendar.monthrange(self.year, self.month)[1] return (fields.Date.to_date('%04d-%02d-01' % (self.year, self.month)), fields.Date.to_date('%04d-%02d-%02d' % ( self.year, self.month, last))) # ------------------------------------------------------------------ def action_compute(self): """Пересобрать итоги выплат за месяц и автозаполнить строки.""" Summary = self.env['rsbu.rsv.summary'].sudo() for rec in self: df, dt = rec._month_bounds() Summary.recompute_period(df, dt, rec.company_id) return self.fill_lines() def fill_lines(self): """Автозаполнить строки по сотрудникам из итогов выплат за месяц. Отделено от action_compute, чтобы заполнять по существующим данным без принудительного пересбора (тесты, повторный расчёт). """ Summary = self.env['rsbu.rsv.summary'].sudo() Line = self.env['rsbu.pers.info.line'] for rec in self: rec.line_ids.unlink() recs = Summary.search([ ('company_id', '=', rec.company_id.id), ('year', '=', rec.year), ('month', '=', rec.month), ]) # Суммируем выплаты по сотруднику (на случай нескольких записей). by_emp = {} for r in recs: by_emp.setdefault(r.employee_id, 0.0) by_emp[r.employee_id] += r.payments vals = [] for emp, pay in by_emp.items(): vals.append({ 'report_id': rec.id, 'employee_id': emp.id, 'amount': round(pay, 2), }) if vals: Line.create(vals) rec.state = 'computed' return True class RsbuPersInfoLine(models.Model): _name = 'rsbu.pers.info.line' _description = 'РСБУ — Строка ПСВ (физлицо)' _order = 'report_id, employee_id' report_id = fields.Many2one( 'rsbu.pers.info', string='Сведения', required=True, ondelete='cascade', index=True) currency_id = fields.Many2one( 'res.currency', related='report_id.currency_id') employee_id = fields.Many2one('hr.employee', string='Сотрудник', required=True) snils = fields.Char(string='СНИЛС', related='employee_id.rsbu_snils') inn = fields.Char(string='ИНН', related='employee_id.rsbu_inn') amount = fields.Monetary(string='Сумма выплат', currency_field='currency_id') cancelled = fields.Boolean( string='Аннулирующие сведения', help='Признак аннулирования ранее поданных сведений (ПрАннулир).')