feat(fusion_clock): portal routes for employee payslips (list / inline paystub / pdf)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-05-30 21:34:53 -04:00
parent 60c25f8241
commit 2fb774e4fa

View File

@@ -65,6 +65,20 @@ class FusionClockPortal(CustomerPortal):
], limit=1)
return employee
def _payroll_available(self):
"""True when fusion_payroll (hr.payslip) is installed on this DB."""
return 'hr.payslip' in request.env
def _get_my_payslips(self, employee):
"""Finalized payslips for this employee, newest first.
Caller must ensure payroll is installed (see _payroll_available).
"""
return request.env['hr.payslip'].sudo().search(
[('employee_id', '=', employee.id), ('state', 'in', ('done', 'paid'))],
order='date_to desc, id desc',
)
# =========================================================================
# Clock Page
# =========================================================================
@@ -157,6 +171,7 @@ class FusionClockPortal(CustomerPortal):
'google_maps_key': google_maps_key,
'enable_sounds': enable_sounds,
'locations_json': locations_json,
'show_payslips': self._payroll_available(),
'page_name': 'clock',
}
return request.render('fusion_clock.portal_clock_page', values)
@@ -234,6 +249,7 @@ class FusionClockPortal(CustomerPortal):
'total_hours': round(total_hours, 1),
'net_hours': round(net_hours, 1),
'total_breaks': round(total_breaks, 0),
'show_payslips': self._payroll_available(),
'page_name': 'timesheets',
}
return request.render('fusion_clock.portal_timesheet_page', values)
@@ -257,6 +273,7 @@ class FusionClockPortal(CustomerPortal):
values = {
'employee': employee,
'reports': reports,
'show_payslips': self._payroll_available(),
'page_name': 'clock_reports',
}
return request.render('fusion_clock.portal_report_page', values)
@@ -285,3 +302,64 @@ class FusionClockPortal(CustomerPortal):
('Content-Disposition', f'attachment; filename="{filename}"'),
],
)
# =========================================================================
# Payslips
# =========================================================================
@http.route('/my/clock/payslips', type='http', auth='user', website=True)
def portal_payslips(self, **kw):
"""List the employee's finalized pay slips."""
employee = self._get_portal_employee()
if not employee or not self._payroll_available():
return request.redirect('/my/clock')
values = {
'employee': employee,
'payslips': self._get_my_payslips(employee),
'show_payslips': True,
'page_name': 'payslips',
}
return request.render('fusion_clock.portal_payslip_list_page', values)
@http.route('/my/clock/payslips/<int:payslip_id>', type='http', auth='user', website=True)
def portal_payslip_detail(self, payslip_id, **kw):
"""Inline paystub for one finalized slip the employee owns."""
employee = self._get_portal_employee()
if not employee or not self._payroll_available():
return request.redirect('/my/clock')
payslip = request.env['hr.payslip'].sudo().browse(payslip_id)
if not payslip.exists() or payslip.employee_id.id != employee.id \
or payslip.state not in ('done', 'paid'):
return request.redirect('/my/clock/payslips')
pdf_report = request.env['ir.actions.report'].sudo().search(
[('model', '=', 'hr.payslip'), ('report_type', '=', 'qweb-pdf')], limit=1)
values = {
'employee': employee,
'payslip': payslip,
'has_pdf': bool(pdf_report),
'show_payslips': True,
'page_name': 'payslips',
}
return request.render('fusion_clock.portal_payslip_detail_page', values)
@http.route('/my/clock/payslips/<int:payslip_id>/pdf', type='http', auth='user', website=True)
def portal_payslip_pdf(self, payslip_id, **kw):
"""Render the standard payslip PDF (sudo) for a slip the employee owns."""
employee = self._get_portal_employee()
if not employee or not self._payroll_available():
return request.redirect('/my/clock')
payslip = request.env['hr.payslip'].sudo().browse(payslip_id)
if not payslip.exists() or payslip.employee_id.id != employee.id \
or payslip.state not in ('done', 'paid'):
return request.redirect('/my/clock/payslips')
report = request.env['ir.actions.report'].sudo().search(
[('model', '=', 'hr.payslip'), ('report_type', '=', 'qweb-pdf')], limit=1)
if not report:
return request.redirect('/my/clock/payslips/%s' % payslip_id)
pdf_content, _ctype = report._render_qweb_pdf(report.report_name, [payslip.id])
slip_ref = payslip.number if 'number' in payslip._fields else False
filename = 'Payslip-%s.pdf' % (slip_ref or payslip.id)
return request.make_response(pdf_content, headers=[
('Content-Type', 'application/pdf'),
('Content-Disposition', 'attachment; filename="%s"' % filename),
])