# -*- coding:utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import api, fields, models, _ from markupsafe import Markup, escape class HrPayrollEditPayslipLinesWizard(models.TransientModel): _name = 'hr.payroll.edit.payslip.lines.wizard' _description = 'Edit payslip lines wizard' payslip_id = fields.Many2one('hr.payslip', required=True, readonly=True) line_ids = fields.One2many('hr.payroll.edit.payslip.line', 'edit_payslip_lines_wizard_id', string='Payslip Lines') worked_days_line_ids = fields.One2many('hr.payroll.edit.payslip.worked.days.line', 'edit_payslip_lines_wizard_id', string='Worked Days Lines') ytd_computation = fields.Boolean(related='payslip_id.ytd_computation') def recompute_following_lines(self, line_id): self.ensure_one() wizard_line = self.env['hr.payroll.edit.payslip.line'].browse(line_id) reload_wizard = { 'type': 'ir.actions.act_window', 'res_model': 'hr.payroll.edit.payslip.lines.wizard', 'view_mode': 'form', 'res_id': self.id, 'views': [(False, 'form')], 'target': 'new', } if not wizard_line.salary_rule_id: return reload_wizard localdict = self.payslip_id._get_localdict() result_rules_dict = localdict['result_rules'] remove_lines = False lines_to_remove = [] blacklisted_rule_ids = [] for line in sorted(self.line_ids, key=lambda x: x.sequence): if remove_lines and line.code in self.payslip_id.line_ids.mapped('code'): lines_to_remove.append((2, line.id, 0)) else: if line == wizard_line: line._compute_total() remove_lines = True blacklisted_rule_ids.append(line.salary_rule_id.id) localdict[line.code] = line.total result_rules_dict[line.code] = {'total': line.total, 'amount': line.amount, 'quantity': line.quantity, 'rate': line.rate, 'ytd': line.ytd} localdict = line.salary_rule_id.category_id._sum_salary_rule_category(localdict, line.total) payslip = self.payslip_id.with_context(force_payslip_localdict=localdict, prevent_payslip_computation_line_ids=blacklisted_rule_ids) self.line_ids = lines_to_remove + [(0, 0, line) for line in payslip._get_payslip_lines()] return reload_wizard def recompute_worked_days_lines(self): self.ensure_one() total_amount = sum(l.amount for l in self.worked_days_line_ids) lines = sorted(self.line_ids, key=lambda x: x.sequence) if not lines: return False lines[0].update({ 'amount': total_amount, 'rate': 100, 'quantity': 1, }) return self.recompute_following_lines(lines[0].id) def action_validate_edition(self): today = fields.Date.today() old_lines_data = { line.salary_rule_id.id: { 'name': line.name, 'quantity': line.quantity, 'rate': line.rate, 'amount': line.amount, 'total': line.total, 'ytd': line.ytd } for line in self.payslip_id.line_ids } old_worked_days_data = { wd.work_entry_type_id.id: { 'name': wd.name, 'number_of_days': wd.number_of_days, 'number_of_hours': wd.number_of_hours, 'amount': wd.amount, 'ytd': wd.ytd, } for wd in self.payslip_id.worked_days_line_ids } self.mapped('payslip_id.line_ids').unlink() self.mapped('payslip_id.worked_days_line_ids').unlink() for wizard in self: lines = [(0, 0, line) for line in wizard.line_ids._export_to_payslip_line()] worked_days_lines = [(0, 0, line) for line in wizard.worked_days_line_ids._export_to_worked_days_line()] wizard.payslip_id.with_context(payslip_no_recompute=True).write({ 'edited': True, 'line_ids': lines, 'worked_days_line_ids': worked_days_lines, 'compute_date': today }) line_fields = { 'name': _('Name'), 'quantity': _('Quantity'), 'rate': _('Rate'), 'amount': _('Amount'), 'total': _('Total'), 'ytd': _('YTD'), } worked_days_fields = { 'name': _('Name'), 'number_of_hours': _('Number of Hours'), 'number_of_days': _('Number of Days'), 'amount': _('Amount'), 'ytd': _('YTD'), } worked_days_changes = self._generate_changed_values(worked_days_lines, old_worked_days_data, worked_days_fields, 'work_entry_type_id') line_changes = self._generate_changed_values(lines, old_lines_data, line_fields, 'salary_rule_id') if line_changes or worked_days_changes: message_body = Markup('%s
') % _( "This payslip has been manually edited by %(user)s.", user=self.env.user.name ) message_body += worked_days_changes + line_changes wizard.payslip_id.message_post(body=message_body) def _generate_changed_values(self, new_items, old_data, fields, item): changes_list = [] for new_item in new_items: new_item_data = new_item[2] old_item_data = old_data.get(new_item_data[item], {}) changes = [] line_name = new_item_data['name'] for field, field_name in fields.items(): if field == 'ytd' and not self.ytd_computation: continue old_value = old_item_data.get(field, None) new_value = new_item_data.get(field, None) if old_value != new_value: changes.append(Markup('
  • %s: %s → %s
  • ') % (field_name, old_value, new_value)) if changes: changes_list.append( Markup('
  • %s
  • ') ) if not changes_list: return '' if item == 'salary_rule_id': message_body = Markup('%s