diff --git a/addons/hr_payroll/__init__.py b/addons/hr_payroll/__init__.py index 7d9f0331149..ac339e32fe7 100644 --- a/addons/hr_payroll/__init__.py +++ b/addons/hr_payroll/__init__.py @@ -4,3 +4,4 @@ from . import models from . import report from . import wizard +from . import controllers diff --git a/addons/hr_payroll/__manifest__.py b/addons/hr_payroll/__manifest__.py index 5483d60de8c..3cc7f2ba363 100644 --- a/addons/hr_payroll/__manifest__.py +++ b/addons/hr_payroll/__manifest__.py @@ -35,4 +35,7 @@ 'wizard/hr_benefit_employee_views.xml', ], 'demo': ['data/hr_payroll_demo.xml'], + 'qweb': [ + "static/src/xml/payslip_tree_views.xml", + ], } diff --git a/addons/hr_payroll/controllers/__init__.py b/addons/hr_payroll/controllers/__init__.py new file mode 100644 index 00000000000..5d4b25db9c0 --- /dev/null +++ b/addons/hr_payroll/controllers/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import main diff --git a/addons/hr_payroll/controllers/main.py b/addons/hr_payroll/controllers/main.py new file mode 100644 index 00000000000..df5d6d4fdf7 --- /dev/null +++ b/addons/hr_payroll/controllers/main.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import io +import re + +from PyPDF2 import PdfFileReader, PdfFileWriter + +from odoo.http import request, route, Controller +from odoo.tools.safe_eval import safe_eval + + +class HrPayroll(Controller): + + @route(["/print/payslips"], type='http', auth='user') + def get_payroll_report_print(self, list_ids='', **post): + if not request.env.user.has_group('hr_payroll.group_hr_payroll_user') or not list_ids or re.search("[^0-9|,]", list_ids): + return request.not_found() + + ids = [int(s) for s in list_ids.split(',')] + payslips = request.env['hr.payslip'].browse(ids) + + pdf_writer = PdfFileWriter() + + for payslip in payslips: + if not payslip.struct_id or not payslip.struct_id.report_id: + continue + pdf_content, _ = payslip.struct_id.report_id.render_qweb_pdf(payslip.id) + reader = PdfFileReader(io.BytesIO(pdf_content), strict=False, overwriteWarnings=False) + + for page in range(reader.getNumPages()): + pdf_writer.addPage(reader.getPage(page)) + + _buffer = io.BytesIO() + pdf_writer.write(_buffer) + merged_pdf = _buffer.getvalue() + _buffer.close() + + if len(payslips) == 1 and payslips.struct_id.report_id.print_report_name: + report_name = safe_eval(payslips.struct_id.report_id.print_report_name, {'object': payslips}) + else: + report_name = "Payslips" + + pdfhttpheaders = [ + ('Content-Type', 'application/pdf'), + ('Content-Length', len(merged_pdf)), + ('Content-Disposition', 'attachment; filename=' + report_name + '.pdf;') + ] + + return request.make_response(merged_pdf, headers=pdfhttpheaders) diff --git a/addons/hr_payroll/models/hr_payslip.py b/addons/hr_payroll/models/hr_payslip.py index 626d84c9414..b2b085b3639 100644 --- a/addons/hr_payroll/models/hr_payslip.py +++ b/addons/hr_payroll/models/hr_payslip.py @@ -311,6 +311,14 @@ class HrPayslip(models.Model): else: return 0.0 + @api.multi + def action_print_payslip(self): + return { + 'name': 'Payslip', + 'type': 'ir.actions.act_url', + 'url': '/print/payslips?list_ids=%(list_ids)s' % {'list_ids': ','.join(str(x) for x in self.ids)}, + } + class HrPayslipLine(models.Model): _name = 'hr.payslip.line' diff --git a/addons/hr_payroll/models/hr_salary_rule.py b/addons/hr_payroll/models/hr_salary_rule.py index 65d6562be4e..0fe344897db 100644 --- a/addons/hr_payroll/models/hr_salary_rule.py +++ b/addons/hr_payroll/models/hr_salary_rule.py @@ -21,6 +21,10 @@ class HrPayrollStructure(models.Model): def _get_parent(self): return self.env.ref('hr_payroll.structure_base', False) + @api.model + def _get_default_report_id(self): + return self.env.ref('hr_payroll.action_report_payslip', False) + name = fields.Char(required=True) code = fields.Char(string='Reference', required=True) company_id = fields.Many2one('res.company', string='Company', required=True, @@ -29,6 +33,8 @@ class HrPayrollStructure(models.Model): parent_id = fields.Many2one('hr.payroll.structure', string='Parent', default=_get_parent) children_ids = fields.One2many('hr.payroll.structure', 'parent_id', string='Children', copy=True) rule_ids = fields.Many2many('hr.salary.rule', 'hr_structure_salary_rule_rel', 'struct_id', 'rule_id', string='Salary Rules') + report_id = fields.Many2one('ir.actions.report', + string="Report", required=True, domain="[('model','=','hr.payslip'),('report_type','=','qweb-pdf')]", default=_get_default_report_id) @api.constrains('parent_id') def _check_parent_id(self): diff --git a/addons/hr_payroll/static/src/js/payslip.js b/addons/hr_payroll/static/src/js/payslip.js new file mode 100644 index 00000000000..c5df787ab52 --- /dev/null +++ b/addons/hr_payroll/static/src/js/payslip.js @@ -0,0 +1,43 @@ +odoo.define('hr_payroll.payslip.tree', function (require) { +"use strict"; + var core = require('web.core'); + var ListController = require('web.ListController'); + var ListView = require('web.ListView'); + var viewRegistry = require('web.view_registry'); + + var QWeb = core.qweb; + + var PayslipListController = ListController.extend({ + /** + * Extends the renderButtons function of ListView by adding a button + * on the payslip list. + * + * @override + */ + renderButtons: function () { + this._super.apply(this, arguments); + this.$buttons.append($(QWeb.render("PayslipListView.print_button", this))); + var self = this; + this.$buttons.on('click', '.o_button_print_payslip', function () { + if (self.getSelectedIds().length == 0) { + return; + } + return self._rpc({ + model: 'hr.payslip', + method: 'action_print_payslip', + args: [self.getSelectedIds()], + }).then(function (results) { + self.do_action(results); + }); + }); + } + }); + + var PayslipListView = ListView.extend({ + config: _.extend({}, ListView.prototype.config, { + Controller: PayslipListController, + }), + }); + + viewRegistry.add('hr_payroll_payslip_tree', PayslipListView); +}); diff --git a/addons/hr_payroll/static/src/xml/payslip_tree_views.xml b/addons/hr_payroll/static/src/xml/payslip_tree_views.xml new file mode 100644 index 00000000000..588c3510fc1 --- /dev/null +++ b/addons/hr_payroll/static/src/xml/payslip_tree_views.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/addons/hr_payroll/views/hr_benefit_template.xml b/addons/hr_payroll/views/hr_benefit_template.xml index 1db60d24ac0..ae1bc4d0f3d 100644 --- a/addons/hr_payroll/views/hr_benefit_template.xml +++ b/addons/hr_payroll/views/hr_benefit_template.xml @@ -4,6 +4,7 @@ diff --git a/addons/hr_payroll/views/hr_payslip_views.xml b/addons/hr_payroll/views/hr_payslip_views.xml index 7fe8164662f..85c3f03fe71 100644 --- a/addons/hr_payroll/views/hr_payslip_views.xml +++ b/addons/hr_payroll/views/hr_payslip_views.xml @@ -70,7 +70,7 @@ hr.payslip.tree hr.payslip - + @@ -133,7 +133,8 @@