# -*- coding: utf-8 -*- """ Payroll Cheque Print Wizard =========================== Wizard that appears after payroll submission when cheques need to be printed. """ from odoo import api, fields, models, _ from odoo.exceptions import UserError class PayrollChequePrintWizard(models.TransientModel): """Wizard to print cheques after payroll submission.""" _name = 'payroll.cheque.print.wizard' _description = 'Print Payroll Cheques' payslip_run_id = fields.Many2one( 'hr.payslip.run', string='Payslip Batch', readonly=True, ) cheque_ids = fields.Many2many( 'payroll.cheque', string='Cheques to Print', ) cheque_count = fields.Integer(string='Number of Cheques') # Starting cheque number (optional override) starting_cheque_number = fields.Char( string='Starting Cheque Number', help='Leave blank to use automatic numbering', ) # Preview of cheques cheque_preview = fields.Html( string='Cheque Preview', compute='_compute_cheque_preview', ) @api.depends('cheque_ids') def _compute_cheque_preview(self): for wizard in self: if not wizard.cheque_ids: wizard.cheque_preview = '

No cheques to print

' continue html = '' html += '' html += '' for cheque in wizard.cheque_ids: html += f'' html += f'' html += f'' html += '
EmployeeAmountPay Period
{cheque.employee_id.name}${cheque.amount:,.2f}{cheque.pay_period_display or ""}
' wizard.cheque_preview = html def action_print_all(self): """Print all cheques.""" self.ensure_one() if not self.cheque_ids: raise UserError(_("No cheques to print.")) # Assign numbers if custom starting number provided if self.starting_cheque_number: try: start_num = int(self.starting_cheque_number) for i, cheque in enumerate(self.cheque_ids.sorted(key=lambda c: c.employee_id.name)): cheque.cheque_number = str(start_num + i).zfill(6) except ValueError: raise UserError(_("Starting cheque number must be numeric.")) else: # Use sequence for cheque in self.cheque_ids: if not cheque.cheque_number: cheque.action_assign_number() # Mark all as printed self.cheque_ids.write({ 'state': 'printed', 'printed_date': fields.Datetime.now(), }) # Generate report return self.env.ref('fusion_payroll.action_report_payroll_cheque').report_action(self.cheque_ids) def action_skip_print(self): """Skip printing and go to payslip view.""" return { 'type': 'ir.actions.act_window', 'name': _('Payslips'), 'res_model': 'hr.payslip.run', 'res_id': self.payslip_run_id.id, 'view_mode': 'form', 'target': 'current', } def action_view_cheques(self): """View cheques list.""" return { 'type': 'ir.actions.act_window', 'name': _('Cheques'), 'res_model': 'payroll.cheque', 'view_mode': 'list,form', 'domain': [('id', 'in', self.cheque_ids.ids)], 'target': 'current', } class HrPayslipRunCheque(models.Model): """Extend payslip batch with cheque functionality.""" _inherit = 'hr.payslip.run' cheque_ids = fields.One2many( 'payroll.cheque', 'payslip_run_id', string='Cheques', ) cheque_count = fields.Integer( string='Cheque Count', compute='_compute_cheque_count', ) cheques_to_print = fields.Integer( string='Cheques to Print', compute='_compute_cheque_count', ) @api.depends('cheque_ids', 'cheque_ids.state') def _compute_cheque_count(self): for batch in self: batch.cheque_count = len(batch.cheque_ids) batch.cheques_to_print = len(batch.cheque_ids.filtered(lambda c: c.state == 'draft')) def action_view_cheques(self): """Open cheques for this batch.""" self.ensure_one() return { 'type': 'ir.actions.act_window', 'name': _('Cheques'), 'res_model': 'payroll.cheque', 'view_mode': 'list,form', 'domain': [('payslip_run_id', '=', self.id)], 'context': {'default_payslip_run_id': self.id}, } def action_print_cheques(self): """Print all draft cheques for this batch.""" self.ensure_one() cheques = self.cheque_ids.filtered(lambda c: c.state == 'draft') if not cheques: # Check if there are employees needing cheques employees_needing_cheques = self.slip_ids.filtered( lambda s: hasattr(s.employee_id, 'payment_method') and s.employee_id.payment_method == 'cheque' ).mapped('employee_id') if employees_needing_cheques: # Create cheques for slip in self.slip_ids: if hasattr(slip.employee_id, 'payment_method') and \ slip.employee_id.payment_method == 'cheque': self.env['payroll.cheque'].create_from_payslip(slip) cheques = self.cheque_ids.filtered(lambda c: c.state == 'draft') if not cheques: from odoo.exceptions import UserError raise UserError(_("No cheques to print. Make sure employees have payment method set to 'Cheque'.")) return { 'type': 'ir.actions.act_window', 'name': _('Print Cheques'), 'res_model': 'payroll.cheque.print.wizard', 'view_mode': 'form', 'target': 'new', 'context': { 'default_payslip_run_id': self.id, 'default_cheque_ids': [(6, 0, cheques.ids)], 'default_cheque_count': len(cheques), }, } def action_create_cheques(self): """Create cheques for all employees paid by cheque.""" self.ensure_one() created_count = 0 for slip in self.slip_ids: if hasattr(slip.employee_id, 'payment_method') and \ slip.employee_id.payment_method == 'cheque': # Check if cheque already exists existing = self.env['payroll.cheque'].search([ ('payslip_id', '=', slip.id), ], limit=1) if not existing: self.env['payroll.cheque'].create_from_payslip(slip) created_count += 1 return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': { 'title': _('Cheques Created'), 'message': _('%d cheques created.') % created_count, 'type': 'success', 'sticky': False, } }