import logging _logger = logging.getLogger(__name__) # Стабильный внешний идентификатор профиля «Основной договор». # По нему на профиль можно ссылаться из данных (в т.ч. демо) через ref, # не зная реального id записи в БД. MAIN_PROFILE_XMLID = 'l10n_ru_contract_account.contract_profile_main' def _find_company_accounting(env, company): """Вернуть (journal_sale, receivable, payable, payment_term) для компании. Счета берём ДЕФОЛТНЫЕ для контрагентов (property_account_receivable_id / property_account_payable_id) — именно они попадают в строки инвойсов. Так профиль договора будет согласован со счётом дебиторки инвойса и проверка invoice_fields_check пройдёт. Любой элемент может быть пустым, если план счетов ещё не настроен. """ journal = env['account.journal'].search( [('type', '=', 'sale'), ('company_id', '=', company.id)], limit=1) # Дефолтные счета контрагента в контексте компании. partner_model = env['res.partner'].with_company(company) receivable = partner_model.default_get( ['property_account_receivable_id']).get('property_account_receivable_id') payable = partner_model.default_get( ['property_account_payable_id']).get('property_account_payable_id') receivable = env['account.account'].browse(receivable) if receivable else \ env['account.account'].search( [('account_type', '=', 'asset_receivable'), ('company_ids', 'in', company.id)], limit=1) payable = env['account.account'].browse(payable) if payable else \ env['account.account'].search( [('account_type', '=', 'liability_payable'), ('company_ids', 'in', company.id)], limit=1) payment_term = env.ref('account.account_payment_term_immediate', raise_if_not_found=False) return journal, receivable, payable, payment_term def ensure_main_profile(env, company=None): """Создать/дозаполнить профиль «Основной договор» и закрепить xmlid. Возвращает запись профиля или None, если бухгалтерия ещё не настроена (нет журнала/счетов) — тогда создание откладывается до момента, когда план счетов будет загружен (напр. pre_init демо-данных). """ module, name = MAIN_PROFILE_XMLID.split('.') profile = env.ref(MAIN_PROFILE_XMLID, raise_if_not_found=False) if profile and profile.journal_id: return profile # уже настроен — уважаем существующее company = company or env.company or env['res.company'].search([], limit=1) if not company: return None journal, receivable, payable, payment_term = _find_company_accounting( env, company) if not (journal and receivable and payable and payment_term): _logger.info( 'l10n_ru_contract_account: профиль «Основной договор» пока не ' 'создан — в компании %s не настроен план счетов. Будет создан ' 'после настройки бухгалтерии.', company.display_name) return None vals = { 'name': 'Основной договор', 'journal_id': journal.id, 'receivable_account_id': receivable.id, 'payable_account_id': payable.id, 'payment_term_id': payment_term.id, 'max_receivable_id': 0.0, } if profile: profile.write(vals) else: profile = env['contract.profile'].create(vals) env['ir.model.data'].create({ 'name': name, 'module': module, 'model': 'contract.profile', 'res_id': profile.id, 'noupdate': True, }) _logger.info( 'l10n_ru_contract_account: профиль «Основной договор» готов ' '(компания %s, журнал %s).', company.display_name, journal.code) return profile def post_init_hook(env): """При установке модуля пытаемся создать профиль сразу. В чистой базе журналов ещё нет — тогда профиль создаётся позже (см. pre_init демо-данных или повторный вызов). """ ensure_main_profile(env)