From dbf7257971f53db1cdb2b61806e58572d7a413d5 Mon Sep 17 00:00:00 2001 From: jbm-odoo Date: Wed, 19 Dec 2018 14:23:37 +0000 Subject: [PATCH] [IMP] hr_payroll: Add a multi-report printing mechanism Purpose ======= We can't have only one report template for all the payslips. Some things are specific to belgium, or another country. (For example, display the amount on meal vouchers on the payslip). We should add an multi action, and a button on the payslip form to print it. Add a report field on a salary structure. This report is used on printing. That way we can specify another report for a given salary structure and print all the document of a employee with the correct report on each payslip. closes odoo/odoo#29674 --- addons/hr_payroll/__init__.py | 1 + addons/hr_payroll/__manifest__.py | 3 ++ addons/hr_payroll/controllers/__init__.py | 4 ++ addons/hr_payroll/controllers/main.py | 50 +++++++++++++++++++ addons/hr_payroll/models/hr_payslip.py | 8 +++ addons/hr_payroll/models/hr_salary_rule.py | 6 +++ addons/hr_payroll/static/src/js/payslip.js | 43 ++++++++++++++++ .../static/src/xml/payslip_tree_views.xml | 9 ++++ .../hr_payroll/views/hr_benefit_template.xml | 1 + addons/hr_payroll/views/hr_payslip_views.xml | 5 +- .../hr_payroll/views/hr_salary_rule_views.xml | 1 + 11 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 addons/hr_payroll/controllers/__init__.py create mode 100644 addons/hr_payroll/controllers/main.py create mode 100644 addons/hr_payroll/static/src/js/payslip.js create mode 100644 addons/hr_payroll/static/src/xml/payslip_tree_views.xml 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 @@