# -*- coding: utf-8 -*- """ Payroll Report Controller ========================= Handles AJAX requests for payroll reports: - Loading report data - Exporting PDF/Excel - Updating filters """ import base64 import json from datetime import date from odoo import http from odoo.http import request, content_disposition class PayrollReportController(http.Controller): """Controller for payroll report endpoints.""" @http.route('/payroll/report/get_report_data', type='jsonrpc', auth='user') def get_report_data(self, report_model, options=None): """ Get report data for the given report model. Args: report_model: The report model name (e.g., 'payroll.report.paycheque.history') options: Filter options dictionary Returns: dict: Report data with columns, lines, and options """ try: # Check if model exists if report_model not in request.env.registry: return {'error': f'Report model {report_model} not found in registry'} # Get the model class (works for abstract models) report = request.env[report_model] # Build options if options: if isinstance(options, str): options = json.loads(options) final_options = report._get_options(options) # Get report data columns = report._get_columns() lines = report._get_lines(final_options) return { 'report_name': report.report_name, 'report_code': report.report_code, 'options': final_options, 'columns': columns, 'lines': lines, 'date_filter_options': report.DATE_FILTER_OPTIONS, 'filter_date_range': report.filter_date_range, 'filter_employee': report.filter_employee, 'filter_department': report.filter_department, } except KeyError as e: return {'error': f'Report model {report_model} not found: {str(e)}'} except AttributeError as e: return {'error': f'Report model {report_model} missing required attribute: {str(e)}'} except Exception as e: import traceback import logging _logger = logging.getLogger(__name__) _logger.error(f"Error in get_report_data: {str(e)}\n{traceback.format_exc()}") return {'error': str(e), 'traceback': traceback.format_exc()} @http.route('/payroll/report/get_lines', type='jsonrpc', auth='user') def get_lines(self, report_model, options): """ Get report lines with current options. """ try: if report_model not in request.env: return {'error': f'Report model {report_model} not found'} report = request.env[report_model] if isinstance(options, str): options = json.loads(options) final_options = report._get_options(options) return { 'lines': report._get_lines(final_options), 'options': final_options, } except Exception as e: import traceback return {'error': str(e), 'traceback': traceback.format_exc()} @http.route('/payroll/report/get_detail_lines', type='jsonrpc', auth='user') def get_detail_lines(self, report_model, line_id, options): """ Get expanded detail lines for a specific line. Used for drill-down functionality. """ try: if report_model not in request.env: return {'error': f'Report model {report_model} not found'} report = request.env[report_model] if isinstance(options, str): options = json.loads(options) # Parse line_id to get record id if '_' in str(line_id): parts = line_id.split('_') record_id = int(parts[-1]) else: record_id = int(line_id) if hasattr(report, '_get_detail_lines'): return { 'detail_lines': report._get_detail_lines(record_id, options) } return {'detail_lines': []} except Exception as e: import traceback return {'error': str(e), 'traceback': traceback.format_exc()} @http.route('/payroll/report/export_xlsx', type='http', auth='user') def export_xlsx(self, report_model, options, **kw): """ Export report to Excel format. """ report = request.env[report_model] if isinstance(options, str): options = json.loads(options) final_options = report._get_options(options) try: xlsx_data = report.get_xlsx(final_options) filename = f"{report.report_code}_{date.today().strftime('%Y%m%d')}.xlsx" return request.make_response( xlsx_data, headers=[ ('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'), ('Content-Disposition', content_disposition(filename)), ('Content-Length', len(xlsx_data)), ], ) except Exception as e: return request.make_response( json.dumps({'error': str(e)}), headers=[('Content-Type', 'application/json')], status=500, ) @http.route('/payroll/report/export_pdf', type='http', auth='user') def export_pdf(self, report_model, options, **kw): """ Export report to PDF format. """ report = request.env[report_model] if isinstance(options, str): options = json.loads(options) final_options = report._get_options(options) try: pdf_data = report.get_pdf(final_options) filename = f"{report.report_code}_{date.today().strftime('%Y%m%d')}.pdf" return request.make_response( pdf_data, headers=[ ('Content-Type', 'application/pdf'), ('Content-Disposition', content_disposition(filename)), ('Content-Length', len(pdf_data)), ], ) except Exception as e: return request.make_response( json.dumps({'error': str(e)}), headers=[('Content-Type', 'application/json')], status=500, ) @http.route('/payroll/report/get_employees', type='jsonrpc', auth='user') def get_employees(self, search_term=''): """ Get employees for filter dropdown. """ try: domain = [('company_id', '=', request.env.company.id)] if search_term: domain.append(('name', 'ilike', search_term)) employees = request.env['hr.employee'].search(domain, limit=50, order='name') return [ {'id': emp.id, 'name': emp.name, 'department': emp.department_id.name or ''} for emp in employees ] except Exception as e: import traceback return {'error': str(e), 'traceback': traceback.format_exc()} @http.route('/payroll/report/get_departments', type='jsonrpc', auth='user') def get_departments(self): """ Get departments for filter dropdown. """ try: departments = request.env['hr.department'].search([ ('company_id', '=', request.env.company.id), ], order='name') return [ {'id': dept.id, 'name': dept.name} for dept in departments ] except Exception as e: import traceback return {'error': str(e), 'traceback': traceback.format_exc()} @http.route('/payroll/report/action_open_record', type='jsonrpc', auth='user') def action_open_record(self, model, res_id): """ Get action to open a specific record. """ try: return { 'type': 'ir.actions.act_window', 'res_model': model, 'res_id': res_id, 'view_mode': 'form', 'target': 'current', } except Exception as e: import traceback return {'error': str(e), 'traceback': traceback.format_exc()}