Initial commit

This commit is contained in:
gsinghpal
2026-02-22 01:22:18 -05:00
commit 5200d5baf0
2394 changed files with 386834 additions and 0 deletions

View 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)