# -*- coding: utf-8 -*- from odoo.tests import TransactionCase, tagged @tagged('post_install', '-at_install') class TestEnpNotification(TransactionCase): """Уведомление об исчисленных суммах (ЕНП, UT_UVISCHSUMNAL 5.03).""" @classmethod def setUpClass(cls): super().setUpClass() cls.company = cls.env.company cls.company.write({ 'rsbu_tax_office_code': '5050', 'rsbu_oktmo': '46788000381', 'rsbu_kbk_insurance': '18210201000011000160', 'rsbu_kbk_ndfl': '18210102010011000110', 'rsbu_kbk_usn': '18210501011011000110', }) cls.company.partner_id.write({'inn': '5050164162', 'kpp': '505001001'}) user = cls.env['res.users'].search([], limit=1) cls.company.rsbu_signatory_id = user.id user.partner_id.write({'name': 'Коробков Сергей Васильевич'}) cls.employee = cls.env['hr.employee'].create({ 'name': 'Петров Пётр Петрович', 'company_id': cls.company.id, 'rsbu_insured_category': 'НР', }) cls.Summary = cls.env['rsbu.rsv.summary'] cls.Notif = cls.env['rsbu.enp.notification'] def _summary(self, month, ops, oms, vnim): return self.Summary.create({ 'company_id': self.company.id, 'employee_id': self.employee.id, 'year': 2026, 'month': month, 'insured_category': 'НР', 'base': ops + oms + vnim, 'ops': ops, 'oms': oms, 'vnim': vnim, }) def test_01_period_mapping(self): """Код периода и номер месяца в квартале — как в образцах 1С. Ноябрь → Период 34, месяц 02; март → Период 21, месяц 03. """ nov = self.Notif.create({ 'year': 2026, 'month': 11, 'company_id': self.company.id}) self.assertEqual(nov._quarter(), 4) from odoo.addons.rsbu_fns_reporting.models.rsbu_enp_notification \ import ENP_PERIOD_CODE self.assertEqual(ENP_PERIOD_CODE[nov._quarter()], '34') self.assertEqual(nov._month_in_quarter(), '02') mar = self.Notif.create({ 'year': 2026, 'month': 3, 'company_id': self.company.id}) self.assertEqual(ENP_PERIOD_CODE[mar._quarter()], '21') self.assertEqual(mar._month_in_quarter(), '03') def test_02_autofill_insurance(self): """Автозаполнение: строка взносов = ОПС+ОМС+ВНиМ за месяц.""" self._summary(3, 22000.0, 5100.0, 2900.0) notif = self.Notif.create({ 'year': 2026, 'month': 3, 'company_id': self.company.id}) notif.fill_lines() ins = notif.line_ids.filtered(lambda l: l.kind == 'insurance') self.assertTrue(ins, 'Строка взносов должна появиться') self.assertAlmostEqual(ins.amount, 30000.0, 2) self.assertEqual(ins.kbk, '18210201000011000160') self.assertEqual(ins.period_code, '21') self.assertEqual(ins.month_in_quarter, '03') self.assertEqual(ins.oktmo, '46788000381') def test_03_xml_valid_against_xsd(self): """Сгенерированное уведомление проходит XSD 5.03.""" self._summary(3, 22000.0, 5100.0, 2900.0) notif = self.Notif.create({ 'year': 2026, 'month': 3, 'company_id': self.company.id}) notif.fill_lines() fname = notif._enp_xml_filename() xml_bytes = notif._enp_build_xml(filename=fname) ok, errors = notif._enp_validate_xml(xml_bytes) self.assertTrue(ok, 'Уведомление не прошло XSD: %s' % '; '.join(errors[:8])) self.assertIn(b'windows-1251', xml_bytes[:60]) self.assertTrue(fname.startswith('UT_UVISCHSUMNAL_')) from lxml import etree root = etree.fromstring(xml_bytes) self.assertEqual(root.get('ИдФайл'), fname) doc = root.find('Документ') self.assertEqual(doc.get('КНД'), '1110355') line = doc.find('УвИсчСумНалог') self.assertEqual(line.get('Период'), '21') self.assertEqual(line.get('НомерМесКварт'), '03') self.assertEqual(line.get('СумНалогАванс'), '30000.00') def test_04_matches_live_sample_march(self): """Сверка с живым образцом 1С: март 2026, взносы 78008.48. Образец УФНС принят: Период 21, месяц 03, КБК взносов, ОКТМО 11. """ self._summary(3, 57000.0, 13000.0, 8008.48) # сумма 78008.48 notif = self.Notif.create({ 'year': 2026, 'month': 3, 'company_id': self.company.id}) notif.fill_lines() ins = notif.line_ids.filtered(lambda l: l.kind == 'insurance') self.assertAlmostEqual(ins.amount, 78008.48, 2) self.assertEqual(ins.kbk, '18210201000011000160') self.assertEqual(ins.period_code, '21') self.assertEqual(ins.month_in_quarter, '03')