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