# -*- coding: utf-8 -*- import logging from odoo import api, models _logger = logging.getLogger(__name__) # Название налоговой группы НДС (РФ). Общее для всех компаний. TAX_GROUP_NAME = "НДС" # Эталонный набор ставок НДС по НК РФ — 1:1 из прежнего account_tax_data.xml. # Способы расчёта: # * «плюс НДС» — налог сверх суммы (amount_type=percent, tax_excluded) # * «в т.ч. НДС» — налог внутри суммы (amount_type=division, tax_included) # Направление: продажа (sale) / покупка (purchase). # «Без НДС» и «НДС 0%» намеренно без «в т.ч.»-вариантов (деление на 0% бессмысленно). # (name, type_tax_use, amount_type, amount, price_include_override) VAT_TAXES = [ ("Без НДС (продажа)", "sale", "percent", 0.0, "tax_excluded"), ("Без НДС (покупка)", "purchase", "percent", 0.0, "tax_excluded"), ("НДС 0% (продажа)", "sale", "percent", 0.0, "tax_excluded"), ("НДС 0% (покупка)", "purchase", "percent", 0.0, "tax_excluded"), ("НДС 5% (продажа)", "sale", "percent", 5.0, "tax_excluded"), ("НДС 5% в т.ч. (продажа)", "sale", "division", 5.0, "tax_included"), ("НДС 5% (покупка)", "purchase", "percent", 5.0, "tax_excluded"), ("НДС 5% в т.ч. (покупка)", "purchase", "division", 5.0, "tax_included"), ("НДС 7% (продажа)", "sale", "percent", 7.0, "tax_excluded"), ("НДС 7% в т.ч. (продажа)", "sale", "division", 7.0, "tax_included"), ("НДС 7% (покупка)", "purchase", "percent", 7.0, "tax_excluded"), ("НДС 7% в т.ч. (покупка)", "purchase", "division", 7.0, "tax_included"), ("НДС 10% (продажа)", "sale", "percent", 10.0, "tax_excluded"), ("НДС 10% в т.ч. (продажа)", "sale", "division", 10.0, "tax_included"), ("НДС 10% (покупка)", "purchase", "percent", 10.0, "tax_excluded"), ("НДС 10% в т.ч. (покупка)", "purchase", "division", 10.0, "tax_included"), ("НДС 22% (продажа)", "sale", "percent", 22.0, "tax_excluded"), ("НДС 22% в т.ч. (продажа)", "sale", "division", 22.0, "tax_included"), ("НДС 22% (покупка)", "purchase", "percent", 22.0, "tax_excluded"), ("НДС 22% в т.ч. (покупка)", "purchase", "division", 22.0, "tax_included"), ] class AccountTax(models.Model): _inherit = "account.tax" def _rsbu_ensure_tax_group(self, company, country): """Найти/создать налоговую группу НДС для компании. Идемпотентно.""" Group = self.env['account.tax.group'] group = Group.search([ ('company_id', '=', company.id), ('name', '=', TAX_GROUP_NAME), ], limit=1) if not group: group = Group.create({ 'name': TAX_GROUP_NAME, 'company_id': company.id, 'country_id': country.id if country else False, }) return group def _rsbu_ensure_vat_taxes(self, company, group, country): """Создать недостающие ставки НДС для корневой компании. Идемпотентно. Дедуп выполняется в границах всей иерархии компании-корня (`company_id child_of root_id`), повторяя область действия штатного ограничения уникальности `account.tax._constrains_name`. Иначе на базах с филиалами (branch) создание ставки с тем же именем вызовет «Tax names must be unique!». """ Tax = self.env['account.tax'] created = 0 for name, use, atype, amount, incl in VAT_TAXES: exists = Tax.with_context(active_test=False).search([ ('company_id', 'child_of', company.root_id.id), ('name', '=', name), ('type_tax_use', '=', use), ('country_id', '=', country.id if country else False), ], limit=1) if exists: continue Tax.create({ 'name': name, 'type_tax_use': use, 'amount_type': atype, 'amount': amount, 'price_include_override': incl, 'tax_group_id': group.id, 'country_id': country.id if country else False, 'company_id': company.id, }) created += 1 return created @api.model def _rsbu_setup_vat_taxes(self): """Создать налоговую группу НДС и 20 ставок НДС для каждой КОРНЕВОЙ компании. Вызывается через в data при установке И при каждом `-u`. Ставки НДС создаются на уровне корневой компании (root_id). Филиалы (branch, parent_id задан) наследуют план счетов и налоги родителя — это штатное поведение бухгалтерии Odoo, и штатное ограничение уникальности `account.tax` запрещает дублировать ставки с тем же именем внутри одной иерархии компании. Поэтому мы перебираем только корневые компании (`parent_id = False`); филиалы получают доступ к ставкам родителя. Идемпотентно: дедуп по (иерархия root, name, type_tax_use, country_id), поэтому повторный запуск / установка на новую компанию не создают дублей. """ country = self.env.ref('base.ru', raise_if_not_found=False) root_companies = self.env['res.company'].search([('parent_id', '=', False)]) for company in root_companies: group = self._rsbu_ensure_tax_group(company, country) n = self._rsbu_ensure_vat_taxes(company, group, country) _logger.info( "rsbu_vat_templates: корневая компания %s — создано ставок НДС: %s", company.display_name, n)