from odoo import api, models # Определения демо-шаблонов. # Формат: code -> dict(name, resolver_key, usn_recognition, is_refund, # roles={role: account_code}) TEMPLATES = { # --- Инвойсы --- 'DEMO_SALE': { 'name': 'Продажа клиенту', 'resolver_key': 'shipment_upd', 'usn_recognition': 'none', # доход по УСН признаётся по оплате 'is_refund': False, 'roles': { 'receivable': '62.01', 'revenue': '90.01', 'revenue_vat': '90.03', 'vat_output': '68.НДС', # роли для зачёта аванса и вычета авансового НДС при отгрузке 'advance_received': '62.АВ', 'vat_advance': '76.АВ', }, }, 'DEMO_SALE_REFUND': { 'name': 'Возврат от клиента (кредит-нота)', 'resolver_key': 'sale_credit_note', 'usn_recognition': 'none', 'is_refund': True, 'roles': { 'receivable': '62.01', 'revenue': '90.01', 'revenue_vat': '90.03', 'vat_output': '68.НДС', }, }, 'DEMO_PURCHASE': { 'name': 'Счёт поставщика', 'resolver_key': 'purchase_bill', 'usn_recognition': 'none', # расход по УСН признаётся по оплате 'is_refund': False, 'roles': { 'expense': '44', 'payable': '60', }, }, 'DEMO_PURCHASE_REFUND': { 'name': 'Возврат поставщику (кредит-нота)', 'resolver_key': 'purchase_credit_note', 'usn_recognition': 'none', 'is_refund': True, 'roles': { 'expense': '44', 'payable': '60', }, }, # --- Платежи --- 'DEMO_PAY_CUSTOMER': { 'name': 'Оплата от клиента', 'resolver_key': 'customer_payment', 'usn_recognition': 'income', 'is_refund': False, 'roles': { 'bank': '51', 'receivable': '62.01', 'advance_received': '62.АВ', 'vat_advance': '76.АВ', 'vat_output': '68.НДС', }, }, 'DEMO_REFUND_CUSTOMER': { 'name': 'Возврат клиенту', 'resolver_key': 'advance_refund', 'usn_recognition': 'refund_customer', 'is_refund': True, 'roles': { 'bank': '51', 'advance_received': '62.АВ', 'vat_advance': '76.АВ', 'vat_output': '68.НДС', }, }, 'DEMO_PAY_SUPPLIER': { 'name': 'Оплата поставщику', 'resolver_key': 'supplier_payment', 'usn_recognition': 'expense', 'is_refund': False, 'roles': { 'bank': '51', 'payable': '60', }, }, 'DEMO_REFUND_SUPPLIER': { 'name': 'Возврат от поставщика', 'resolver_key': 'supplier_refund', 'usn_recognition': 'refund_supplier', 'is_refund': True, 'roles': { 'bank': '51', 'payable': '60', }, }, } # Правила матрицы: (name, doc_kind, partner_kind, has_advance, template_code, priority) MATRIX = [ ('Продажа клиенту', 'out_invoice', 'any', 'any', 'DEMO_SALE', 10), ('Возврат от клиента', 'out_refund', 'any', 'any', 'DEMO_SALE_REFUND', 10), ('Счёт поставщика', 'in_invoice', 'any', 'any', 'DEMO_PURCHASE', 10), ('Возврат поставщику', 'in_refund', 'any', 'any', 'DEMO_PURCHASE_REFUND', 10), ('Оплата от клиента', 'payment_inbound', 'customer', 'any', 'DEMO_PAY_CUSTOMER', 10), ('Возврат клиенту', 'payment_outbound', 'customer', 'any', 'DEMO_REFUND_CUSTOMER', 10), ('Оплата поставщику', 'payment_outbound', 'supplier', 'any', 'DEMO_PAY_SUPPLIER', 10), ('Возврат от поставщика', 'payment_inbound', 'supplier', 'any', 'DEMO_REFUND_SUPPLIER', 10), ] class RsbuDemoTemplatesLoader(models.AbstractModel): """Загрузчик демо-шаблонов и матрицы связности по компаниям.""" _name = 'rsbu.demo.templates.loader' _description = 'РСБУ — Загрузчик демо-шаблонов' @api.model def _account(self, company, code): return self.env['rsbu.account'].search([ ('company_id', '=', company.id), ('code', '=', code)], limit=1) @api.model def load_for_company(self, company): Template = self.env['rsbu.operation.template'] Matrix = self.env['rsbu.operation.matrix'] code_to_tmpl = {} for code, spec in TEMPLATES.items(): existing = Template.search([ ('code', '=', code), ('company_id', '=', company.id)], limit=1) if existing: code_to_tmpl[code] = existing continue role_cmds = [] skip = False for role, acc_code in spec['roles'].items(): account = self._account(company, acc_code) if not account: skip = True break role_cmds.append((0, 0, { 'role': role, 'account_id': account.id})) if skip: continue tmpl = Template.create({ 'code': code, 'name': spec['name'], 'resolver_key': spec['resolver_key'], 'usn_recognition': spec['usn_recognition'], 'is_refund': spec['is_refund'], 'company_id': company.id, 'role_ids': role_cmds, }) code_to_tmpl[code] = tmpl for name, doc_kind, partner_kind, has_advance, tmpl_code, prio \ in MATRIX: tmpl = code_to_tmpl.get(tmpl_code) if not tmpl: continue exists = Matrix.search([ ('company_id', '=', company.id), ('doc_kind', '=', doc_kind), ('partner_kind', '=', partner_kind), ('template_id', '=', tmpl.id)], limit=1) if exists: continue Matrix.create({ 'name': name, 'doc_kind': doc_kind, 'partner_kind': partner_kind, 'has_advance': has_advance, 'template_id': tmpl.id, 'priority': prio, 'company_id': company.id, })