web_direct_print/models/direct_print.py
2025-10-21 11:39:27 +07:00

212 lines
8.7 KiB
Python

from odoo import models, fields, api
import base64
import logging
_logger = logging.getLogger(__name__)
class DirectPrint(models.Model):
_name = 'web.direct.print'
_description = 'Web Direct Print'
@api.model
def get_report_data(self, report_name, docids, data=None):
"""
Generate report data for direct printing
:param report_name: Name of the report
:param docids: Document IDs to print
:param data: Additional report data
:return: Report content in base64
"""
try:
_logger.info(f"get_report_data called with report_name={report_name} (type: {type(report_name)}), docids={docids} (type: {type(docids)})")
# Handle report_name parameter - it could be a string, list, or ID
if isinstance(report_name, list):
if report_name and isinstance(report_name[0], int):
# It's a list of IDs, get the report by ID
report = self.env['ir.actions.report'].browse(report_name[0])
else:
# It's a list with string names
report_name_str = report_name[0] if report_name else ''
report = self.env['ir.actions.report'].search([('report_name', '=', report_name_str)], limit=1)
elif isinstance(report_name, int):
# It's an ID
report = self.env['ir.actions.report'].browse(report_name)
elif isinstance(report_name, str):
# It's a string name - try to find by report_name or use env.ref
if '.' in report_name:
# It looks like a module.xml_id format, try env.ref first
try:
ref_obj = self.env.ref(report_name)
# Check if the referenced object is actually a report
if hasattr(ref_obj, '_name') and ref_obj._name == 'ir.actions.report':
report = ref_obj
else:
# It's not a report (probably a view), search by report_name instead
report = self.env['ir.actions.report'].search([('report_name', '=', report_name)], limit=1)
except ValueError:
# If env.ref fails, try searching by report_name
report = self.env['ir.actions.report'].search([('report_name', '=', report_name)], limit=1)
else:
# Search by report_name
report = self.env['ir.actions.report'].search([('report_name', '=', report_name)], limit=1)
else:
report = None
# Generate the report content
if report:
# Generate the pdf content with proper context
current_context = self.env.context.copy()
# Handle docids parameter - ensure it's a list of integers
if isinstance(docids, str):
# If it's a string, try to convert to int
try:
docids = [int(docids)]
except ValueError:
# If it contains commas, split and convert
if ',' in docids:
docids = [int(d.strip()) for d in docids.split(',') if d.strip()]
else:
docids = [int(docids)]
elif isinstance(docids, int):
docids = [docids]
elif isinstance(docids, list):
# Ensure all elements are integers
processed_ids = []
for d in docids:
if isinstance(d, str):
try:
processed_ids.append(int(d))
except ValueError:
continue
elif isinstance(d, int):
processed_ids.append(d)
docids = processed_ids
else:
docids = []
_logger.info(f"Processed docids: {docids}")
if not docids:
return {
'success': False,
'error': 'No valid document IDs provided'
}
# Use the standard Odoo report rendering approach
# Ensure report_name is a string, not a list
report_name_str = str(report.report_name) if report.report_name else report.name
_logger.info(f"Using report_name_str: {report_name_str} (type: {type(report_name_str)})")
# Generate PDF using the standard method
pdf_content, report_format = self.env['ir.actions.report'].with_context(**current_context)._render_qweb_pdf(report_name_str, docids, data or {})
# Encode the content in base64 for transmission
encoded_content = base64.b64encode(pdf_content).decode('utf-8')
return {
'success': True,
'content': encoded_content,
'report_name': report_name,
'docids': docids,
'content_type': 'application/pdf'
}
else:
return {
'success': False,
'error': f'Report "{report_name}" not found'
}
except Exception as e:
_logger.error(f"Error generating report for direct print: {str(e)}")
_logger.exception("Full traceback:")
return {
'success': False,
'error': str(e)
}
@api.model
def prepare_print_data(self, report_name, docids, data=None):
"""
Prepare data for direct printing
:param report_name: Name of the report to print
:param docids: IDs of documents to print
:param data: Additional data for the report
:return: Dictionary with report data
"""
try:
result = self.get_report_data(report_name, docids, data)
return result
except Exception as e:
_logger.error(f"Error preparing print data: {str(e)}")
return {
'success': False,
'error': str(e)
}
@api.model
def get_available_reports(self):
"""
Get list of available reports for direct printing
:return: List of available reports
"""
try:
reports = self.env['ir.actions.report'].search([
('active', '=', True),
('report_type', 'in', ['qweb-pdf', 'qweb-html'])
])
report_list = []
for report in reports:
report_list.append({
'id': report.id,
'name': report.name,
'report_name': report.report_name,
'model': report.model,
})
return {
'success': True,
'reports': report_list
}
except Exception as e:
_logger.error(f"Error getting available reports: {str(e)}")
return {
'success': False,
'error': str(e)
}
@api.model
def direct_print_action(self, report_name, docids, data=None, context=None):
"""
Execute direct print action for a given report
:param report_name: Name of the report to print
:param docids: IDs of documents to print
:param data: Additional data for the report
:param context: Context data
:return: Result of the print action
"""
try:
# Update the environment context if provided
if context:
self = self.with_context(**context)
# Prepare the print data
print_data = self.prepare_print_data(report_name, docids, data)
if print_data['success']:
# In a real implementation, we might want to add additional
# processing here, such as tracking print jobs or handling
# special printer configurations
# Return the print data for client-side processing
return print_data
else:
return print_data
except Exception as e:
_logger.error(f"Error in direct print action: {str(e)}")
return {
'success': False,
'error': str(e)
}