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:
@@ -65,6 +65,20 @@ class FusionClockPortal(CustomerPortal):
|
|||||||
], limit=1)
|
], limit=1)
|
||||||
return employee
|
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
|
# Clock Page
|
||||||
# =========================================================================
|
# =========================================================================
|
||||||
@@ -157,6 +171,7 @@ class FusionClockPortal(CustomerPortal):
|
|||||||
'google_maps_key': google_maps_key,
|
'google_maps_key': google_maps_key,
|
||||||
'enable_sounds': enable_sounds,
|
'enable_sounds': enable_sounds,
|
||||||
'locations_json': locations_json,
|
'locations_json': locations_json,
|
||||||
|
'show_payslips': self._payroll_available(),
|
||||||
'page_name': 'clock',
|
'page_name': 'clock',
|
||||||
}
|
}
|
||||||
return request.render('fusion_clock.portal_clock_page', values)
|
return request.render('fusion_clock.portal_clock_page', values)
|
||||||
@@ -234,6 +249,7 @@ class FusionClockPortal(CustomerPortal):
|
|||||||
'total_hours': round(total_hours, 1),
|
'total_hours': round(total_hours, 1),
|
||||||
'net_hours': round(net_hours, 1),
|
'net_hours': round(net_hours, 1),
|
||||||
'total_breaks': round(total_breaks, 0),
|
'total_breaks': round(total_breaks, 0),
|
||||||
|
'show_payslips': self._payroll_available(),
|
||||||
'page_name': 'timesheets',
|
'page_name': 'timesheets',
|
||||||
}
|
}
|
||||||
return request.render('fusion_clock.portal_timesheet_page', values)
|
return request.render('fusion_clock.portal_timesheet_page', values)
|
||||||
@@ -257,6 +273,7 @@ class FusionClockPortal(CustomerPortal):
|
|||||||
values = {
|
values = {
|
||||||
'employee': employee,
|
'employee': employee,
|
||||||
'reports': reports,
|
'reports': reports,
|
||||||
|
'show_payslips': self._payroll_available(),
|
||||||
'page_name': 'clock_reports',
|
'page_name': 'clock_reports',
|
||||||
}
|
}
|
||||||
return request.render('fusion_clock.portal_report_page', values)
|
return request.render('fusion_clock.portal_report_page', values)
|
||||||
@@ -285,3 +302,64 @@ class FusionClockPortal(CustomerPortal):
|
|||||||
('Content-Disposition', f'attachment; filename="{filename}"'),
|
('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),
|
||||||
|
])
|
||||||
|
|||||||
Reference in New Issue
Block a user