Files
odoo-addons/addons/at_accounting/wizard/report_export_wizard.py

134 lines
6.4 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, models, fields, _
from odoo.exceptions import UserError
from odoo.models import check_method_name
import json
import base64
import types
from urllib.parse import urlparse, parse_qs
class ReportExportWizard(models.TransientModel):
""" Wizard allowing to export an accounting report in several different formats
at once, saving them as attachments.
"""
_name = 'account_reports.export.wizard'
_description = "Export wizard for accounting's reports"
export_format_ids = fields.Many2many(string="Export to", comodel_name='account_reports.export.wizard.format', relation="dms_acc_rep_export_wizard_format_rel")
report_id = fields.Many2one(string="Parent Report Id", comodel_name='account.report', required=True)
doc_name = fields.Char(string="Documents Name", help="Name to give to the generated documents.")
@api.model_create_multi
def create(self, vals_list):
wizards = super().create(vals_list)
for wizard in wizards:
wizard.doc_name = wizard.report_id.name
# We create one export format object per available export type of the report,
# with the right generation function associated to it.
# This is done so to allow selecting them as Many2many tags in the wizard.
for button_dict in self._context.get('account_report_generation_options', {}).get('buttons', []):
if button_dict.get('file_export_type'):
self.env['account_reports.export.wizard.format'].create({
'name': button_dict['file_export_type'],
'fun_to_call': button_dict['action'],
'fun_param': button_dict.get('action_param'),
'export_wizard_id': wizard.id,
})
return wizards
def export_report(self):
self.ensure_one()
created_attachments = self.env['ir.attachment']
for vals in self._get_attachments_to_save():
created_attachments |= self.env['ir.attachment'].create(vals)
return {
'type': 'ir.actions.act_window',
'name': _('Generated Documents'),
'view_mode': 'kanban,form',
'res_model': 'ir.attachment',
'domain': [('id', 'in', created_attachments.ids)],
}
def _get_attachments_to_save(self):
self.ensure_one()
to_create_attachments = []
report_options = self.env.context['account_report_generation_options']
for format in self.export_format_ids:
# format.fun_to_call is a button function, so it has to be public
fun_name = format.fun_to_call
check_method_name(fun_name)
if self.report_id.custom_handler_model_id and hasattr(self.env[self.report_id.custom_handler_model_name], fun_name):
report_function = getattr(self.env[self.report_id.custom_handler_model_name], fun_name)
else:
report_function = getattr(self.report_id, fun_name)
report_function_params = [format.fun_param] if format.fun_param else []
report_action = report_function(report_options, *report_function_params)
to_create_attachments.append(format.apply_export(report_action))
return to_create_attachments
class ReportExportWizardOption(models.TransientModel):
_name = 'account_reports.export.wizard.format'
_description = "Export format for accounting's reports"
name = fields.Char(string="Name", required=True)
fun_to_call = fields.Char(string="Function to Call", required=True)
fun_param = fields.Char(string="Function Parameter")
export_wizard_id = fields.Many2one(string="Parent Wizard", comodel_name='account_reports.export.wizard', required=True, ondelete='cascade')
def apply_export(self, report_action):
self.ensure_one()
if report_action['type'] == 'ir_actions_account_report_download':
report_options = json.loads(report_action['data']['options'])
# file_generator functions are always public for ir_actions_account_report_download
file_generator = report_action['data']['file_generator']
check_method_name(file_generator)
report = self.export_wizard_id.report_id
if report.custom_handler_model_id and hasattr(self.env[report.custom_handler_model_name], file_generator):
generation_function = getattr(self.env[report.custom_handler_model_name], file_generator)
else:
generation_function = getattr(report, file_generator)
export_result = generation_function(report_options)
# We use the options from the action, as the action may have added or modified
# stuff into them (see l10n_es_reports, with BOE wizard)
file_content = base64.encodebytes(export_result['file_content']) if isinstance(export_result['file_content'], bytes) else export_result['file_content']
# We need to unpack the content in case of a generator
if isinstance(file_content, types.GeneratorType):
file_content = base64.encodebytes(b''.join(file_content))
file_name = f"{self.export_wizard_id.doc_name or self.export_wizard_id.report_id.name}.{export_result['file_type']}"
mimetype = self.export_wizard_id.report_id.get_export_mime_type(export_result['file_type'])
elif report_action['type'] == 'ir.actions.act_url':
query_params = parse_qs(urlparse(report_action['url']).query)
model = query_params['model'][0]
model_id = int(query_params['id'][0])
wizard = self.env[model].browse(model_id)
file_name = wizard[query_params['filename_field'][0]]
file_content = wizard[query_params['field'][0]]
mimetype = self.env['account.report'].get_export_mime_type(file_name.split('.')[-1])
else:
raise UserError(_("One of the formats chosen can not be exported in the DMS"))
return self.get_attachment_vals(file_name, file_content, mimetype, report_options)
def get_attachment_vals(self, file_name, file_content, mimetype, log_options_dict):
self.ensure_one()
return {
'name': file_name,
'company_id': self.env.company.id,
'datas': file_content,
'mimetype': mimetype,
'description': json.dumps(log_options_dict)
}