169 lines
7.7 KiB
Python
169 lines
7.7 KiB
Python
from collections import defaultdict
|
|
|
|
from odoo import api, models, _
|
|
from odoo.fields import Domain
|
|
|
|
|
|
class AccountJournal(models.Model):
|
|
_inherit = 'account.journal'
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
journals = super().create(vals_list)
|
|
journals.sudo()._documents_configure_sync()
|
|
return journals
|
|
|
|
def _documents_configure_sync(self):
|
|
"""Configure the synchronization of accounting with documents.
|
|
|
|
* Create synchronization settings for the journals (skip if missing data).
|
|
* Embed relevant server actions on the specific journal folder.
|
|
* Embed relevant server actions on the company's parent 'Finance' folder.
|
|
"""
|
|
FolderSetting = self.env['documents.account.folder.setting']
|
|
Journal = self.env['account.journal']
|
|
sync_journals = self.filtered(
|
|
lambda j: j.type and j.name and j.company_id.account_folder_id)
|
|
if not sync_journals:
|
|
return
|
|
journal_type_labels = dict(Journal.fields_get(['type'], ['selection'])['type']['selection'])
|
|
folders_by_journal_type = sync_journals._documents_ensure_journal_folder_created(journal_type_labels)
|
|
tag_by_name = sync_journals._documents_ensure_journal_tags_created().grouped('name')
|
|
actions_to_embed = self._documents_get_embed_on_sync_actions()
|
|
|
|
settings_to_create = []
|
|
folders_to_embed = defaultdict(lambda: self.env['documents.document'])
|
|
|
|
for journal in sync_journals:
|
|
company = journal.company_id
|
|
journal_type = journal.type
|
|
target_folder = folders_by_journal_type[journal.company_id, journal.type]
|
|
|
|
settings_to_create.append({
|
|
'company_id': company.id,
|
|
'journal_id': journal.id,
|
|
'folder_id': target_folder.id,
|
|
'tag_ids': tag_by_name[journal.name].ids,
|
|
})
|
|
|
|
actions_xml_ids = actions_to_embed.get(journal_type, [])
|
|
if not actions_xml_ids:
|
|
continue
|
|
|
|
for xml_id in actions_xml_ids:
|
|
folders_to_embed[xml_id] |= target_folder | company.account_folder_id
|
|
|
|
if settings_to_create:
|
|
FolderSetting.create(settings_to_create)
|
|
|
|
for action_xml_id, folders in folders_to_embed.items():
|
|
if action := self.env.ref(action_xml_id, raise_if_not_found=False):
|
|
folders._embed_action(action.id)
|
|
|
|
@api.model
|
|
def _documents_get_embed_on_sync_actions(self):
|
|
"""Return a dictionary mapping journal types to action XML IDs to embed."""
|
|
return {
|
|
'purchase': [
|
|
'documents_account.ir_actions_server_create_vendor_bill',
|
|
'documents_account.ir_actions_server_create_vendor_refund',
|
|
],
|
|
'sale': [
|
|
'documents_account.ir_actions_server_create_customer_invoice',
|
|
'documents_account.ir_actions_server_create_credit_note',
|
|
],
|
|
'bank': [
|
|
'documents_account.ir_actions_server_bank_statement',
|
|
],
|
|
'general': [
|
|
'documents_account.ir_actions_server_create_misc_entry',
|
|
],
|
|
}
|
|
|
|
def _documents_ensure_journal_tags_created(self):
|
|
"""Create the missing tags and returns all tags for the journals."""
|
|
tag_names = set(self.mapped('name'))
|
|
existing = self.env['documents.tag'].search([('name', 'in', list(tag_names))])
|
|
created = self.env['documents.tag'].create([{
|
|
'name': tag_name,
|
|
} for tag_name in tag_names - set(existing.mapped('name'))])
|
|
self._documents_sync_translations(self, 'name', created, 'name')
|
|
return existing + created
|
|
|
|
def _documents_ensure_journal_folder_created(self, type_labels):
|
|
"""Create the missing sync folders and returns all sync folders for the journals."""
|
|
FolderSetting = self.env['documents.account.folder.setting']
|
|
Documents = self.env['documents.document']
|
|
required_refs = set(self.mapped(lambda j: (j.company_id, j.type)))
|
|
|
|
existing_settings = FolderSetting.search(Domain.OR([
|
|
[('company_id', '=', c.id), ('journal_id.type', '=', j_type)]
|
|
for c, j_type in required_refs
|
|
]), order='create_date')
|
|
existing_settings = {(s.company_id, s.journal_id.type): s.folder_id for s in existing_settings}
|
|
|
|
existing_folders = Documents.search(
|
|
Domain('id', 'not in', FolderSetting._search([]).select('folder_id')) &
|
|
Domain.OR([
|
|
[('company_id', '=', company.id), ('folder_id', '=', company.account_folder_id.id),
|
|
('name', '=', type_labels[journal_type]), ('type', '=', 'folder')]
|
|
for company, journal_type in required_refs
|
|
]), order="create_date")
|
|
existing_folders = {(f.company_id, f.name): f for f in existing_folders}
|
|
|
|
existing = {
|
|
(company, journal_type): folder
|
|
for company, journal_type in required_refs
|
|
if (folder :=
|
|
existing_settings.get((company, journal_type))
|
|
or
|
|
existing_folders.get((company, type_labels[journal_type])))
|
|
}
|
|
missing_refs = required_refs - existing.keys()
|
|
created = Documents.create([{
|
|
'company_id': company.id,
|
|
'folder_id': company.account_folder_id.id,
|
|
'name': type_labels[journal_type],
|
|
'owner_id': False,
|
|
'type': 'folder',
|
|
} for company, journal_type in missing_refs])
|
|
|
|
# Update translation of the created folders
|
|
selection_options = self.env['ir.model.fields.selection'].sudo().search(
|
|
[('field_id', '=', self.env.ref('account.field_account_journal__type').id)])
|
|
self._documents_sync_translations(selection_options, 'name', created, 'name')
|
|
return {**existing, **dict(zip(missing_refs, created))}
|
|
|
|
def _documents_sync_translations(self, source_records, source_field, target_records, target_field):
|
|
"""Copy the translation from source_records to target_records.
|
|
|
|
Field values of the source_records must be aligned with those of the target_records for the main language.
|
|
"""
|
|
sources = {r[source_field]: r for r in source_records.with_context(prefetch_langs=True)}
|
|
for target_rec in target_records:
|
|
value = target_rec[target_field]
|
|
target_rec.update_field_translations(target_field, {
|
|
lang_code: sources[value].with_context(lang=lang_code)[source_field]
|
|
for lang_code, __ in self.env['res.lang'].get_installed()
|
|
})
|
|
|
|
def create_document_from_attachment(self, attachment_ids=None):
|
|
""" When running an action on several documents, this method is called
|
|
in a loop (because of the "multi" server action). When it is the
|
|
case, we try to redirect to a list of all created journal entries
|
|
instead of just the last one, using the context. """
|
|
|
|
action = super().create_document_from_attachment(attachment_ids)
|
|
documents_active_ids = self.env.context.get('documents_active_ids', [])
|
|
if self.env.context.get('active_model') != 'documents.document' or len(documents_active_ids) <= 1:
|
|
return action
|
|
|
|
account_move_ids = self.env['documents.document'].browse(documents_active_ids).mapped('res_id')
|
|
action.update({
|
|
'name': _("Generated Bank Statements") if action.get('res_model', '') == 'account.bank.statement' else action.get('name', ''),
|
|
'domain': [('id', 'in', account_move_ids)],
|
|
'views': [[False, 'list'], [False, 'kanban'], [False, 'form']],
|
|
'view_mode': 'list,kanban,form',
|
|
})
|
|
return action
|