Initial commit
This commit is contained in:
129
Fusion Accounting/controllers/main.py
Normal file
129
Fusion Accounting/controllers/main.py
Normal file
@@ -0,0 +1,129 @@
|
||||
# Fusion Accounting - HTTP Controllers
|
||||
# Provides web endpoints for report file generation and attachment downloads
|
||||
|
||||
import json
|
||||
|
||||
from werkzeug.exceptions import InternalServerError
|
||||
|
||||
from odoo import http
|
||||
from odoo.addons.fusion_accounting.models.account_report import AccountReportFileDownloadException
|
||||
from odoo.addons.account.controllers.download_docs import _get_headers
|
||||
from odoo.http import content_disposition, request
|
||||
from odoo.models import check_method_name
|
||||
from odoo.tools.misc import html_escape
|
||||
|
||||
|
||||
class AccountReportController(http.Controller):
|
||||
"""Handles HTTP requests for generating and downloading
|
||||
accounting report files in various formats."""
|
||||
|
||||
@http.route('/fusion_accounting', type='http', auth='user', methods=['POST'], csrf=False)
|
||||
def get_report(self, options, file_generator, **kwargs):
|
||||
"""Generate a report file based on the provided options and generator method.
|
||||
|
||||
:param options: JSON-encoded report configuration options
|
||||
:param file_generator: name of the method that produces the file
|
||||
:returns: HTTP response with the generated file content
|
||||
"""
|
||||
current_uid = request.uid
|
||||
parsed_options = json.loads(options)
|
||||
|
||||
# Determine which companies are in scope for this report
|
||||
company_ids = request.env['account.report'].get_report_company_ids(parsed_options)
|
||||
if not company_ids:
|
||||
cookie_cids = request.cookies.get('cids', str(request.env.user.company_id.id))
|
||||
company_ids = [int(cid) for cid in cookie_cids.split('-')]
|
||||
|
||||
target_report = (
|
||||
request.env['account.report']
|
||||
.with_user(current_uid)
|
||||
.with_context(allowed_company_ids=company_ids)
|
||||
.browse(parsed_options['report_id'])
|
||||
)
|
||||
|
||||
try:
|
||||
check_method_name(file_generator)
|
||||
file_data = target_report.dispatch_report_action(parsed_options, file_generator)
|
||||
|
||||
raw_content = file_data['file_content']
|
||||
output_type = file_data['file_type']
|
||||
resp_headers = self._build_response_headers(
|
||||
output_type, file_data['file_name'], raw_content,
|
||||
)
|
||||
|
||||
if output_type == 'xlsx':
|
||||
# Stream binary spreadsheet data
|
||||
http_response = request.make_response(None, headers=resp_headers)
|
||||
http_response.stream.write(raw_content)
|
||||
else:
|
||||
http_response = request.make_response(raw_content, headers=resp_headers)
|
||||
|
||||
if output_type in ('zip', 'xaf'):
|
||||
# Enable streaming for large archive files to avoid
|
||||
# loading the entire content into memory at once
|
||||
http_response.direct_passthrough = True
|
||||
|
||||
return http_response
|
||||
|
||||
except AccountReportFileDownloadException as exc:
|
||||
if exc.content:
|
||||
exc.content['file_content'] = exc.content['file_content'].decode()
|
||||
error_payload = {
|
||||
'name': type(exc).__name__,
|
||||
'arguments': [exc.errors, exc.content],
|
||||
}
|
||||
raise InternalServerError(
|
||||
response=self._format_error_response(error_payload)
|
||||
) from exc
|
||||
|
||||
except Exception as exc: # noqa: BLE001
|
||||
error_payload = http.serialize_exception(exc)
|
||||
raise InternalServerError(
|
||||
response=self._format_error_response(error_payload)
|
||||
) from exc
|
||||
|
||||
def _format_error_response(self, error_data):
|
||||
"""Wrap error details into a JSON response matching the Odoo RPC error format."""
|
||||
envelope = {
|
||||
'code': 200,
|
||||
'message': 'Odoo Server Error',
|
||||
'data': error_data,
|
||||
}
|
||||
return request.make_response(html_escape(json.dumps(envelope)))
|
||||
|
||||
def _build_response_headers(self, file_type, file_name, raw_content):
|
||||
"""Construct HTTP response headers appropriate for the given file type."""
|
||||
mime_type = request.env['account.report'].get_export_mime_type(file_type)
|
||||
header_list = [
|
||||
('Content-Type', mime_type),
|
||||
('Content-Disposition', content_disposition(file_name)),
|
||||
]
|
||||
|
||||
# Include Content-Length for text-based formats
|
||||
if file_type in ('xml', 'txt', 'csv', 'kvr'):
|
||||
header_list.append(('Content-Length', len(raw_content)))
|
||||
|
||||
return header_list
|
||||
|
||||
@http.route(
|
||||
'/fusion_accounting/download_attachments/<models("ir.attachment"):attachments>',
|
||||
type='http',
|
||||
auth='user',
|
||||
)
|
||||
def download_report_attachments(self, attachments):
|
||||
"""Download one or more report attachments, packaging them
|
||||
into a zip archive when multiple files are requested."""
|
||||
attachments.check_access('read')
|
||||
assert all(
|
||||
att.res_id and att.res_model == 'res.partner'
|
||||
for att in attachments
|
||||
)
|
||||
|
||||
if len(attachments) == 1:
|
||||
single = attachments
|
||||
resp_headers = _get_headers(single.name, single.mimetype, single.raw)
|
||||
return request.make_response(single.raw, resp_headers)
|
||||
else:
|
||||
zip_data = attachments._build_zip_from_attachments()
|
||||
resp_headers = _get_headers('attachments.zip', 'zip', zip_data)
|
||||
return request.make_response(zip_data, resp_headers)
|
||||
Reference in New Issue
Block a user