102 lines
4.8 KiB
Python
102 lines
4.8 KiB
Python
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)
|