[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
This commit is contained in:
committed by
Yannick Tivisse
parent
3e9102bb50
commit
dbf7257971
@@ -4,3 +4,4 @@
|
||||
from . import models
|
||||
from . import report
|
||||
from . import wizard
|
||||
from . import controllers
|
||||
|
||||
@@ -35,4 +35,7 @@
|
||||
'wizard/hr_benefit_employee_views.xml',
|
||||
],
|
||||
'demo': ['data/hr_payroll_demo.xml'],
|
||||
'qweb': [
|
||||
"static/src/xml/payslip_tree_views.xml",
|
||||
],
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import main
|
||||
@@ -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)
|
||||
@@ -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'
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<templates>
|
||||
<t t-name="PayslipListView.print_button">
|
||||
<button type="button" class="btn btn-secondary o_button_print_payslip">
|
||||
Print
|
||||
</button>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -4,6 +4,7 @@
|
||||
<template id="assets_backend" inherit_id="web.assets_backend">
|
||||
<xpath expr="script[last()]" position="after">
|
||||
<script type="text/javascript" src="/hr_payroll/static/src/js/benefit.js"></script>
|
||||
<script type="text/javascript" src="/hr_payroll/static/src/js/payslip.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<field name="name">hr.payslip.tree</field>
|
||||
<field name="model">hr.payslip</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree decoration-info="state in ('confirm','hr_check','accont_check')" decoration-muted="state == 'cancel'" string="Payslips">
|
||||
<tree decoration-info="state in ('confirm','verify')" decoration-muted="state == 'cancel'" js_class="hr_payroll_payslip_tree" string="Payslips">
|
||||
<field name="number"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="name"/>
|
||||
@@ -133,7 +133,8 @@
|
||||
<button string="Set to Draft" name="action_payslip_draft" type="object" states="cancel"/>
|
||||
<button string="Compute Sheet" name="compute_sheet" type="object" states="draft" class="oe_highlight"/>
|
||||
<button string="Cancel Payslip" name="action_payslip_cancel" type="object" states="draft,confirm,verify"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,verify,confirm"/>
|
||||
<button string="Print" name="action_print_payslip" type="object"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,confirm"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="parent_id"/>
|
||||
<field name="report_id"/>
|
||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
|
||||
Reference in New Issue
Block a user