# -*- 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 += '| Employee | Amount | Pay Period | '
html += '
'
for cheque in wizard.cheque_ids:
html += f'| {cheque.employee_id.name} | '
html += f'${cheque.amount:,.2f} | '
html += f'{cheque.pay_period_display or ""} |
'
html += '
'
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,
}
}