From c08f8c1c45f157f222465adf6d7990586ce140c6 Mon Sep 17 00:00:00 2001 From: dufresnedavid Date: Thu, 12 Feb 2015 10:00:22 -0500 Subject: [PATCH 01/11] [ADD] payroll analysis --- hr_payroll_analysis/__init__.py | 27 ++ hr_payroll_analysis/__openerp__.py | 60 +++++ hr_payroll_analysis/hr_payslip.py | 79 ++++++ .../hr_payslip_analysis_line.py | 67 +++++ hr_payroll_analysis/hr_salary_rule.py | 83 +++++++ hr_payroll_analysis/hr_salary_rule_view.xml | 17 ++ hr_payroll_analysis/i18n/fr.po | 202 +++++++++++++++ .../i18n/hr_payroll_analysis.pot | 199 +++++++++++++++ .../security/ir.model.access.csv | 2 + hr_payroll_analysis/tests/__init__.py | 26 ++ .../tests/test_payroll_analysis.py | 233 ++++++++++++++++++ hr_payroll_analysis/wizard/__init__.py | 22 ++ .../wizard/payroll_analysis.py | 188 ++++++++++++++ .../wizard/payroll_analysis_view.xml | 94 +++++++ 14 files changed, 1299 insertions(+) create mode 100644 hr_payroll_analysis/__init__.py create mode 100644 hr_payroll_analysis/__openerp__.py create mode 100644 hr_payroll_analysis/hr_payslip.py create mode 100644 hr_payroll_analysis/hr_payslip_analysis_line.py create mode 100644 hr_payroll_analysis/hr_salary_rule.py create mode 100644 hr_payroll_analysis/hr_salary_rule_view.xml create mode 100644 hr_payroll_analysis/i18n/fr.po create mode 100644 hr_payroll_analysis/i18n/hr_payroll_analysis.pot create mode 100644 hr_payroll_analysis/security/ir.model.access.csv create mode 100644 hr_payroll_analysis/tests/__init__.py create mode 100644 hr_payroll_analysis/tests/test_payroll_analysis.py create mode 100644 hr_payroll_analysis/wizard/__init__.py create mode 100644 hr_payroll_analysis/wizard/payroll_analysis.py create mode 100644 hr_payroll_analysis/wizard/payroll_analysis_view.xml diff --git a/hr_payroll_analysis/__init__.py b/hr_payroll_analysis/__init__.py new file mode 100644 index 00000000000..5fe6047b74f --- /dev/null +++ b/hr_payroll_analysis/__init__.py @@ -0,0 +1,27 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from . import ( + hr_payslip, + hr_salary_rule, + hr_payslip_analysis_line, + wizard, +) diff --git a/hr_payroll_analysis/__openerp__.py b/hr_payroll_analysis/__openerp__.py new file mode 100644 index 00000000000..a4684f51d9e --- /dev/null +++ b/hr_payroll_analysis/__openerp__.py @@ -0,0 +1,60 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +{ + 'name': 'Payroll Analysis', + 'version': '1.0', + 'license': 'AGPL-3', + 'category': 'Generic Modules/Human Resources', + 'description': """ +Payroll Analysis +================ +This module adds a report over amounts of payslips line related to a +a salary rule. It allows to group amounts by date, companies, salary rules +and employees. + +This module replaces the use of contribution registers already implemented +in Odoo, which is meant to generate pdf reports. The purpose of this module +is to create dynamic reports. + +To include salary rules in the report, in the salary rule form view, +check the field "Include in Payroll Analysis". + +To view the report go to Reporting -> Human Ressources -> Payroll Analysis, +then fill the wizard. + +Contributors +------------ +* David Dufresne +""", + 'author': 'Savoir-faire Linux', + 'website': 'https://www.savoirfairelinux.com/', + 'depends': [ + 'hr_payroll', + ], + 'data': [ + 'wizard/payroll_analysis_view.xml', + 'hr_salary_rule_view.xml', + 'security/ir.model.access.csv', + ], + 'test': [], + 'demo': [], + 'installable': True, +} diff --git a/hr_payroll_analysis/hr_payslip.py b/hr_payroll_analysis/hr_payslip.py new file mode 100644 index 00000000000..e30f449af93 --- /dev/null +++ b/hr_payroll_analysis/hr_payslip.py @@ -0,0 +1,79 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.osv import orm, fields + + +class hr_payslip(orm.Model): + _inherit = 'hr.payslip' + _columns = { + 'analysis_line_ids': fields.one2many( + 'hr.payslip.analysis.line', + 'payslip_id', + 'Analysis Lines', + ), + } + + def process_sheet(self, cr, uid, ids, context=None): + """ + Create the analysis lines when the payslip is confirmed + """ + super(hr_payslip, self).process_sheet(cr, uid, ids, context=context) + + self.compute_analysis_lines(cr, uid, ids, context=context) + + def compute_analysis_lines(self, cr, uid, ids, context=None): + + analysis_line_obj = self.pool['hr.payslip.analysis.line'] + + for payslip in self.browse(cr, uid, ids, context=context): + # Make sure no analysis line has already been computed + for line in payslip.analysis_line_ids: + line.unlink() + + required_lines = [ + line for line in payslip.details_by_salary_rule_category + if line.salary_rule_id.include_in_payroll_analysis + ] + + is_refund = payslip.credit_note + + for line in required_lines: + analysis_line_obj.create( + cr, uid, { + 'company_id': payslip.company_id.id, + 'employee_id': payslip.employee_id.id, + 'salary_rule_id': line.salary_rule_id.id, + 'payslip_line_id': line.id, + 'payslip_id': payslip.id, + 'date': payslip.date_from, + 'amount': is_refund and -line.total or line.total, + }, context=context) + + def cancel_sheet(self, cr, uid, ids, context=None): + """ + Make sure no analytic lines exist when a payslip is cancelled + """ + for payslip in self.browse(cr, uid, ids, context=context): + for line in payslip.analysis_line_ids: + line.unlink() + + super(hr_payslip, self).cancel_sheet(cr, uid, ids, context=context) diff --git a/hr_payroll_analysis/hr_payslip_analysis_line.py b/hr_payroll_analysis/hr_payslip_analysis_line.py new file mode 100644 index 00000000000..6d753fee31c --- /dev/null +++ b/hr_payroll_analysis/hr_payslip_analysis_line.py @@ -0,0 +1,67 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +from openerp.osv import orm, fields + + +class hr_payslip_analysis_line(orm.Model): + _name = 'hr.payslip.analysis.line' + + _columns = { + 'payslip_id': fields.many2one( + 'hr.payslip', + 'Payslip', + required=True, + ondelete="cascade", + ), + 'payslip_line_id': fields.many2one( + 'hr.payslip.line', + 'Payslip Line', + required=True, + ondelete="cascade", + ), + 'salary_rule_id': fields.many2one( + 'hr.salary.rule', + 'Salary Rule', + required=True, + select=True, + ), + 'company_id': fields.many2one( + 'res.company', + 'Company', + required=True, + select=True, + ), + 'employee_id': fields.many2one( + 'hr.employee', + 'Employee', + required=True, + select=True, + ), + 'date': fields.date( + 'Date', + required=True, + ), + 'amount': fields.float( + 'Amount', + required=True, + ), + } diff --git a/hr_payroll_analysis/hr_salary_rule.py b/hr_payroll_analysis/hr_salary_rule.py new file mode 100644 index 00000000000..c9e3e619364 --- /dev/null +++ b/hr_payroll_analysis/hr_salary_rule.py @@ -0,0 +1,83 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.osv import orm, fields + + +class hr_salary_rule(orm.Model): + _inherit = 'hr.salary.rule' + + _columns = { + 'include_in_payroll_analysis': fields.boolean( + 'Include in Payroll Analysis', + help="If True, every payslip line related to this salary " + "rule will appear in the payroll analysis report." + ), + } + + def write(self, cr, uid, ids, vals, context=None): + res = super(hr_salary_rule, self).write( + cr, uid, ids, vals, context=context) + + if 'include_in_payroll_analysis' in vals: + self.refresh_analysis_lines(cr, uid, ids, context=context) + + return res + + def refresh_analysis_lines(self, cr, uid, ids, context=None): + """This method is used to refresh the analysis lines + when a salary rule's include_in_payroll_analysis field is changed + """ + analysis_line_obj = self.pool['hr.payslip.analysis.line'] + payslip_line_obj = self.pool['hr.payslip.line'] + + for rule in self.browse(cr, uid, ids, context=context): + # Remove existing analysis lines + line_ids = analysis_line_obj.search( + cr, uid, [('salary_rule_id', '=', rule.id)], + context=context) + + print line_ids + + analysis_line_obj.unlink(cr, uid, line_ids, context=context) + + if rule.include_in_payroll_analysis: + # Create analysis lines + payslip_line_ids = payslip_line_obj.search( + cr, uid, [ + ('salary_rule_id', '=', rule.id), + ('slip_id.state', 'not in', ['draft', 'cancel']), + ], context=context) + + for line in payslip_line_obj.browse( + cr, uid, payslip_line_ids, context=context): + payslip = line.slip_id + analysis_line_obj.create( + cr, uid, { + 'company_id': payslip.company_id.id, + 'employee_id': payslip.employee_id.id, + 'salary_rule_id': line.salary_rule_id.id, + 'payslip_line_id': line.id, + 'payslip_id': payslip.id, + 'date': payslip.date_from, + 'amount': payslip.credit_note + and -line.total or line.total, + }, context=context) diff --git a/hr_payroll_analysis/hr_salary_rule_view.xml b/hr_payroll_analysis/hr_salary_rule_view.xml new file mode 100644 index 00000000000..fdc1061529a --- /dev/null +++ b/hr_payroll_analysis/hr_salary_rule_view.xml @@ -0,0 +1,17 @@ + + + + + + hr.salary.rule.form + hr.salary.rule + + + + + + + + + + diff --git a/hr_payroll_analysis/i18n/fr.po b/hr_payroll_analysis/i18n/fr.po new file mode 100644 index 00000000000..84e0b1ee8da --- /dev/null +++ b/hr_payroll_analysis/i18n/fr.po @@ -0,0 +1,202 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * hr_payroll_analysis +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 7.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-02-12 14:29+0000\n" +"PO-Revision-Date: 2015-02-12 09:45-0500\n" +"Last-Translator: David Dufresne \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: \n" +"X-Generator: Poedit 1.5.4\n" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +msgid "Search Payslip Lines" +msgstr "Chercher des lignes de paie" + +#. module: hr_payroll_analysis +#: field:hr.salary.rule,include_in_payroll_analysis:0 +msgid "Include in Payroll Analysis" +msgstr "Inclure dans l'analyse de la paie" + +#. module: hr_payroll_analysis +#: view:hr.payroll.analysis:0 +msgid "Generate the Report" +msgstr "Générer le rapport" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,type:0 +msgid "By Company" +msgstr "Par société" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +msgid "Group By..." +msgstr "Grouper par..." + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,period:0 +msgid "Every Year" +msgstr "Toutes les années" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,period:0 +msgid "Previous Year" +msgstr "L'année précédente" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +#: field:hr.payslip.analysis.line,employee_id:0 +msgid "Employee" +msgstr "Employé" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,type:0 +msgid "By Salary Rule" +msgstr "Par règle de salaire" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,type:0 +msgid "By Employee" +msgstr "Par employé" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 field:hr.payslip.analysis.line,company_id:0 +msgid "Company" +msgstr "Société" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,salary_rule_ids:0 +msgid "Salary Rules" +msgstr "Règle de salaire" + +#. module: hr_payroll_analysis +#: model:ir.model,name:hr_payroll_analysis.model_hr_salary_rule +msgid "hr.salary.rule" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payslip.analysis.line,date:0 +msgid "Date" +msgstr "Date" + +#. module: hr_payroll_analysis +#: model:ir.model,name:hr_payroll_analysis.model_hr_payslip +msgid "Pay Slip" +msgstr "Bulletin de paie" + +#. module: hr_payroll_analysis +#: field:hr.payslip.analysis.line,payslip_line_id:0 +msgid "Payslip Line" +msgstr "Ligne de bulletin de paie" + +#. module: hr_payroll_analysis +#: help:hr.salary.rule,include_in_payroll_analysis:0 +msgid "" +"If True, every payslip line related to this salary rule will appear in the " +"payroll analysis report." +msgstr "" +"Si vrai, les lignes de bulletin de paie liées à cette règle apparaîtront " +"dans le rapport d'analyse de la paie." + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,end_date:0 +msgid "End Date" +msgstr "Date de fin" + +#. module: hr_payroll_analysis +#: code:addons/hr_payroll_analysis/wizard/payroll_analysis.py:181 +#: view:hr.payroll.analysis:0 +#: model:ir.actions.act_window,name:hr_payroll_analysis.action_payroll_analysis_config +#: model:ir.ui.menu,name:hr_payroll_analysis.menu_action_payroll_analysis +#, python-format +msgid "Payroll Analysis" +msgstr "Analyse de la paie" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,employee_ids:0 +msgid "Employees" +msgstr "Employés" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,company_ids:0 +msgid "Companies" +msgstr "Sociétés" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,type:0 +msgid "Analysis Type" +msgstr "Angle d'analyse" + +#. module: hr_payroll_analysis +#: field:hr.payslip.analysis.line,amount:0 +msgid "Amount" +msgstr "Montant" + +#. module: hr_payroll_analysis +#: view:hr.payroll.analysis:0 +msgid "Model" +msgstr "Modèle" + +#. module: hr_payroll_analysis +#: field:hr.payslip.analysis.line,payslip_id:0 +msgid "Payslip" +msgstr "Bulletin de paie" + +#. module: hr_payroll_analysis +#: field:hr.payslip,analysis_line_ids:0 +msgid "Analysis Lines" +msgstr "Lignes d'analyse" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,period:0 +msgid "Current Year" +msgstr "L'année courante" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,period:0 +msgid "Analysis Period" +msgstr "Période d'analyse" + +#. module: hr_payroll_analysis +#: view:hr.payroll.analysis:0 +msgid "or" +msgstr "ou" + +#. module: hr_payroll_analysis +#: model:ir.model,name:hr_payroll_analysis.model_hr_payslip_analysis_line +msgid "hr.payslip.analysis.line" +msgstr "" + +#. module: hr_payroll_analysis +#: model:ir.model,name:hr_payroll_analysis.model_hr_payroll_analysis +msgid "Payroll Analysis Wizard" +msgstr "Assistant pour l'analyse de la paie" + +#. module: hr_payroll_analysis +#: view:hr.payroll.analysis:0 +msgid "Cancel" +msgstr "Annuler" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,start_date:0 +msgid "Start Date" +msgstr "Date de début" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +#: field:hr.payslip.analysis.line,salary_rule_id:0 +msgid "Salary Rule" +msgstr "Règle de salaire" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +msgid "Payroll Analysis Lines" +msgstr "Lignes d'analyse de la paie" diff --git a/hr_payroll_analysis/i18n/hr_payroll_analysis.pot b/hr_payroll_analysis/i18n/hr_payroll_analysis.pot new file mode 100644 index 00000000000..9e02364fe92 --- /dev/null +++ b/hr_payroll_analysis/i18n/hr_payroll_analysis.pot @@ -0,0 +1,199 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * hr_payroll_analysis +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 7.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-02-12 14:29+0000\n" +"PO-Revision-Date: 2015-02-12 14:29+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +msgid "Search Payslip Lines" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.salary.rule,include_in_payroll_analysis:0 +msgid "Include in Payroll Analysis" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payroll.analysis:0 +msgid "Generate the Report" +msgstr "" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,type:0 +msgid "By Company" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +msgid "Group By..." +msgstr "" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,period:0 +msgid "Every Year" +msgstr "" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,period:0 +msgid "Previous Year" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +#: field:hr.payslip.analysis.line,employee_id:0 +msgid "Employee" +msgstr "" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,type:0 +msgid "By Salary Rule" +msgstr "" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,type:0 +msgid "By Employee" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +#: field:hr.payslip.analysis.line,company_id:0 +msgid "Company" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,salary_rule_ids:0 +msgid "Salary Rules" +msgstr "" + +#. module: hr_payroll_analysis +#: model:ir.model,name:hr_payroll_analysis.model_hr_salary_rule +msgid "hr.salary.rule" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payslip.analysis.line,date:0 +msgid "Date" +msgstr "" + +#. module: hr_payroll_analysis +#: model:ir.model,name:hr_payroll_analysis.model_hr_payslip +msgid "Pay Slip" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payslip.analysis.line,payslip_line_id:0 +msgid "Payslip Line" +msgstr "" + +#. module: hr_payroll_analysis +#: help:hr.salary.rule,include_in_payroll_analysis:0 +msgid "If True, every payslip line related to this salary rule will appear in the payroll analysis report." +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,end_date:0 +msgid "End Date" +msgstr "" + +#. module: hr_payroll_analysis +#: code:addons/hr_payroll_analysis/wizard/payroll_analysis.py:181 +#: view:hr.payroll.analysis:0 +#: model:ir.actions.act_window,name:hr_payroll_analysis.action_payroll_analysis_config +#: model:ir.ui.menu,name:hr_payroll_analysis.menu_action_payroll_analysis +#, python-format +msgid "Payroll Analysis" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,employee_ids:0 +msgid "Employees" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,company_ids:0 +msgid "Companies" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,type:0 +msgid "Analysis Type" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payslip.analysis.line,amount:0 +msgid "Amount" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payroll.analysis:0 +msgid "Model" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payslip.analysis.line,payslip_id:0 +msgid "Payslip" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payslip,analysis_line_ids:0 +msgid "Analysis Lines" +msgstr "" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,period:0 +msgid "Current Year" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,period:0 +msgid "Analysis Period" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payroll.analysis:0 +msgid "or" +msgstr "" + +#. module: hr_payroll_analysis +#: model:ir.model,name:hr_payroll_analysis.model_hr_payslip_analysis_line +msgid "hr.payslip.analysis.line" +msgstr "" + +#. module: hr_payroll_analysis +#: model:ir.model,name:hr_payroll_analysis.model_hr_payroll_analysis +msgid "Payroll Analysis Wizard" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payroll.analysis:0 +msgid "Cancel" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,start_date:0 +msgid "Start Date" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +#: field:hr.payslip.analysis.line,salary_rule_id:0 +msgid "Salary Rule" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +msgid "Payroll Analysis Lines" +msgstr "" + diff --git a/hr_payroll_analysis/security/ir.model.access.csv b/hr_payroll_analysis/security/ir.model.access.csv new file mode 100644 index 00000000000..ffa492e6e41 --- /dev/null +++ b/hr_payroll_analysis/security/ir.model.access.csv @@ -0,0 +1,2 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" +"access_hr_payslip_analysis_line","hr.payslip.analysis.line","model_hr_payslip_analysis_line",base.group_hr_manager,1,1,1,1 \ No newline at end of file diff --git a/hr_payroll_analysis/tests/__init__.py b/hr_payroll_analysis/tests/__init__.py new file mode 100644 index 00000000000..73b63fcba1d --- /dev/null +++ b/hr_payroll_analysis/tests/__init__.py @@ -0,0 +1,26 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from . import test_payroll_analysis + +checks = [ + test_payroll_analysis, +] diff --git a/hr_payroll_analysis/tests/test_payroll_analysis.py b/hr_payroll_analysis/tests/test_payroll_analysis.py new file mode 100644 index 00000000000..21c714583f0 --- /dev/null +++ b/hr_payroll_analysis/tests/test_payroll_analysis.py @@ -0,0 +1,233 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.tests import common + + +class test_payroll_analysis(common.TransactionCase): + def get_activity_id(self, job_id): + job = self.job_model.browse( + self.cr, self.uid, job_id, context=self.context) + return job.activity_ids[0].id + + def setUp(self): + super(test_payroll_analysis, self).setUp() + self.user_model = self.registry("res.users") + self.payslip_model = self.registry("hr.payslip") + self.contract_model = self.registry("hr.contract") + self.rule_model = self.registry("hr.salary.rule") + self.rule_category_model = self.registry("hr.salary.rule.category") + self.structure_model = self.registry("hr.payroll.structure") + self.employee_model = self.registry('hr.employee') + self.analysis_line_model = self.registry('hr.payslip.analysis.line') + + self.context = self.user_model.context_get(self.cr, self.uid) + + cr, uid, context = self.cr, self.uid, self.context + + # Create an employee + self.employee_id = self.employee_model.create( + cr, uid, { + 'name': 'Employee 1', + }, context=context) + + # Get any existing category + self.category_id = self.rule_category_model.search( + cr, uid, [], context=context)[0] + + # Create salary rules + self.rule_id = self.rule_model.create( + cr, uid, { + 'name': 'Test 1', + 'sequence': 1, + 'code': 'TEST_1', + 'category_id': self.category_id, + 'appears_on_payslip': True, + 'active': True, + 'amount_select': 'fix', + 'amount_fix': 100, + 'include_in_payroll_analysis': True, + }, context=context + ) + self.rule_2_id = self.rule_model.create( + cr, uid, { + 'name': 'Test 2', + 'sequence': 2, + 'code': 'TEST_2', + 'category_id': self.category_id, + 'appears_on_payslip': True, + 'active': True, + 'amount_select': 'fix', + 'amount_fix': 200, + 'include_in_payroll_analysis': False, + }, context=context + ) + + # Create a structure + self.structure_id = self.structure_model.create( + cr, uid, { + 'name': 'TEST', + 'parent_id': False, + 'code': 'TEST', + 'rule_ids': [(6, 0, [self.rule_id, self.rule_2_id])] + }, context=context + ) + + # Create a contract for the employee + self.contract_id = self.contract_model.create( + cr, uid, { + 'employee_id': self.employee_id, + 'name': 'Contract 1', + 'wage': 50000, + 'struct_id': self.structure_id, + }, context=context + ) + + # Create a payslip + self.payslip_ids = [ + self.payslip_model.create( + self.cr, self.uid, + { + 'employee_id': self.employee_id, + 'contract_id': self.contract_id, + 'date_from': slip[0], + 'date_to': slip[1], + 'struct_id': self.structure_id, + }, context=context) + for slip in [ + ('2014-01-01', '2014-01-31'), + ('2014-02-01', '2014-02-28'), + ] + ] + + self.payslip_model.compute_sheet( + cr, uid, self.payslip_ids, context=context) + + def tearDown(self): + cr, uid, context = self.cr, self.uid, self.context + + self.payslip_model.write( + cr, uid, self.payslip_ids, {'state': 'draft'}, context=context) + + self.payslip_model.unlink( + cr, uid, self.payslip_ids, context=context) + + self.contract_model.unlink( + cr, uid, [self.contract_id], context=context) + + self.employee_model.unlink( + cr, uid, [self.employee_id], context=context) + + self.structure_model.unlink( + cr, uid, [self.structure_id], context=context) + + self.rule_model.unlink( + cr, uid, [self.rule_id, self.rule_2_id], context=context) + + super(test_payroll_analysis, self).tearDown() + + def test_payslip_analysis_line_generated(self): + cr, uid, context = self.cr, self.uid, self.context + + self.payslip_model.process_sheet( + cr, uid, self.payslip_ids, context=context) + + # Check that the analysis lines were created + line_ids = self.analysis_line_model.search( + cr, uid, [('payslip_id', 'in', self.payslip_ids)], + context=context) + + lines = self.analysis_line_model.browse( + cr, uid, line_ids, context=context) + + self.assertEqual(len(lines), 2) + + for line in lines: + self.assertEqual(line.amount, 100) + + # Process the payslips a second time + # Check that there is still one analysis line + # per payslip + self.payslip_model.process_sheet( + cr, uid, self.payslip_ids, context=context) + + line_ids = self.analysis_line_model.search( + cr, uid, [('payslip_id', 'in', self.payslip_ids)], + context=context) + + self.assertEqual(len(line_ids), 2) + + # Cancel a payslip and check that there is only one + # analysis line left + self.payslip_model.cancel_sheet( + cr, uid, [self.payslip_ids[0]], context=context) + + line_ids = self.analysis_line_model.search( + cr, uid, [('payslip_id', 'in', self.payslip_ids)], + context=context) + + lines = self.analysis_line_model.browse( + cr, uid, line_ids, context=context) + + self.assertEqual(len(lines), 1) + self.assertEqual(lines[0].payslip_id.id, self.payslip_ids[1]) + + def test_salary_rule_refresh(self): + cr, uid, context = self.cr, self.uid, self.context + + self.payslip_model.process_sheet( + cr, uid, self.payslip_ids, context=context) + + # Check that the analysis lines were created + line_ids = self.analysis_line_model.search( + cr, uid, [('payslip_id', 'in', self.payslip_ids)], + context=context) + + lines = self.analysis_line_model.browse( + cr, uid, line_ids, context=context) + + self.assertEqual(len(lines), 2) + + for line in lines: + self.assertEqual(line.amount, 100) + + # Include the second salary rule in the report + self.rule_model.write( + cr, uid, [self.rule_2_id], + {'include_in_payroll_analysis': True}, context=context) + + # Exclude the first salary rule from the report + self.rule_model.write( + cr, uid, [self.rule_id], + {'include_in_payroll_analysis': False}, context=context) + + # Check that the proper lines are now computed + line_ids = self.analysis_line_model.search( + cr, uid, [('payslip_id', 'in', self.payslip_ids)], + context=context) + + lines = self.analysis_line_model.browse( + cr, uid, line_ids, context=context) + + self.assertEqual(len(lines), 2) + + for line in lines: + self.assertEqual(line.amount, 200) diff --git a/hr_payroll_analysis/wizard/__init__.py b/hr_payroll_analysis/wizard/__init__.py new file mode 100644 index 00000000000..73231cb54b7 --- /dev/null +++ b/hr_payroll_analysis/wizard/__init__.py @@ -0,0 +1,22 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2014 Odoo Canada. All Rights Reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from . import payroll_analysis diff --git a/hr_payroll_analysis/wizard/payroll_analysis.py b/hr_payroll_analysis/wizard/payroll_analysis.py new file mode 100644 index 00000000000..cc687313e16 --- /dev/null +++ b/hr_payroll_analysis/wizard/payroll_analysis.py @@ -0,0 +1,188 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2014 Odoo Canada. All Rights Reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import pytz +from openerp.osv import orm, fields +from datetime import datetime, date +from openerp.tools import DEFAULT_SERVER_DATE_FORMAT +from openerp.tools.translate import _ + + +def get_current_year(context): + if not context: + context = {} + tz = context.get('tz', False) + tz = tz and pytz.timezone(tz) or pytz.utc + return datetime.now(tz).year + + +class payroll_analysis(orm.TransientModel): + """ + Wizard to generate payroll analysis report + """ + _name = 'hr.payroll.analysis' + _description = 'Payroll Analysis Wizard' + + _columns = { + 'type': fields.selection( + [ + ('employee', 'By Employee'), + ('salary_rule', 'By Salary Rule'), + ('company', 'By Company'), + ], + type="char", + required=True, + string="Analysis Type", + ), + 'period': fields.selection( + [ + ('current_year', 'Current Year'), + ('previous_year', 'Previous Year'), + ('every_year', 'Every Year'), + ], + string='Analysis Period', + type='string', + ), + 'start_date': fields.datetime('Start Date'), + 'end_date': fields.datetime('End Date'), + 'company_ids': fields.many2many( + 'res.company', + 'payroll_analysis_company_rel', + 'payroll_analysis_id', + 'company_id', + 'Companies', + ), + 'employee_ids': fields.many2many( + 'hr.employee', + 'payroll_analysis_employee_rel', + 'payroll_analysis_id', + 'employee_id', + 'Employees', + ), + 'salary_rule_ids': fields.many2many( + 'hr.salary.rule', + 'payroll_analysis_salary_rule_rel', + 'payroll_analysis_id', + 'salary_rule_id', + 'Salary Rules', + ), + } + + _defaults = { + 'start_date': lambda self, cr, uid, context: ( + date(get_current_year(context), 1, 1).strftime( + DEFAULT_SERVER_DATE_FORMAT)), + 'end_date': lambda self, cr, uid, context: ( + date(get_current_year(context), 12, 31).strftime( + DEFAULT_SERVER_DATE_FORMAT)), + 'period': 'current_year', + 'type': 'salary_rule', + } + + def onchange_period(self, cr, uid, ids, period, context=None): + if not period: + return {} + + if period == 'every_year': + return {'value': { + 'start_date': False, + 'end_date': False, + }} + + year = get_current_year(context) + + if period == 'previous_year': + year -= 1 + + start_date = date(year, 1, 1).strftime(DEFAULT_SERVER_DATE_FORMAT) + end_date = date(year, 12, 31).strftime(DEFAULT_SERVER_DATE_FORMAT) + + return {'value': { + 'start_date': start_date, + 'end_date': end_date, + }} + + def payroll_analysis_open_window(self, cr, uid, ids, context=None): + """ + This method returns an action that displays profitability lines + requested in the wizard + """ + if context is None: + context = {} + + wizard = self.browse(cr, uid, ids, context=context)[0] + + domain_filters = [] + + if wizard.salary_rule_ids: + domain_filters.append(('salary_rule_id', 'in', [ + rule.id for rule in wizard.salary_rule_ids])) + + if wizard.employee_ids and wizard.type == 'employee': + domain_filters.append(('employee_id', 'in', [ + employee.id for employee in wizard.employee_ids])) + + if wizard.company_ids and wizard.type == 'company': + domain_filters.append(('company_id', 'in', [ + company.id for company in wizard.company_ids])) + + if wizard.end_date: + domain_filters.append(('date', '<=', wizard.end_date)) + + if wizard.start_date: + domain_filters.append(('date', '>=', wizard.start_date)) + + analysis_line_ids = self.pool['hr.payslip.analysis.line'].search( + cr, uid, domain_filters, context=context) + + view_ref = self.pool['ir.model.data'].get_object_reference( + cr, uid, 'hr_payroll_analysis', + 'view_payslip_analysis_line_tree') + + view_context = {} + + if wizard.type == 'company': + view_context = { + 'search_default_group_company_id': 1, + 'search_default_group_salary_rule_id': 1, + } + elif wizard.type == 'employee': + view_context = { + 'search_default_group_employee_id': 1, + 'search_default_group_salary_rule_id': 1, + } + elif wizard.type == 'salary_rule': + view_context = { + 'search_default_group_salary_rule_id': 1, + } + + view_id = view_ref and view_ref[1] or False + + return { + 'type': 'ir.actions.act_window', + 'name': _('Payroll Analysis'), + 'res_model': 'hr.payslip.analysis.line', + 'view_type': 'list', + 'view_mode': 'list', + 'view_id': view_id, + 'domain': [('id', 'in', analysis_line_ids)], + 'context': view_context, + } diff --git a/hr_payroll_analysis/wizard/payroll_analysis_view.xml b/hr_payroll_analysis/wizard/payroll_analysis_view.xml new file mode 100644 index 00000000000..d4a366e3abc --- /dev/null +++ b/hr_payroll_analysis/wizard/payroll_analysis_view.xml @@ -0,0 +1,94 @@ + + + + + + + hr.payslip.analysis.line.tree + hr.payslip.analysis.line + + + + + + + + + + + + + + hr.payslip.analysis.line.filter + hr.payslip.analysis.line + + + + + + + + + + + + + + + + + + hr.payroll.analysis.form + hr.payroll.analysis + +
+ + + + + + + + + +
+
+
+
+
+ + + + Payroll Analysis + ir.actions.act_window + hr.payroll.analysis + form + tree,form + + new + + + + + +
+
From fa304204c3a8363e95dff1733d0e3f7012d4cab5 Mon Sep 17 00:00:00 2001 From: dufresnedavid Date: Thu, 12 Feb 2015 10:17:22 -0500 Subject: [PATCH 02/11] Exclude payslip lines with null amount --- hr_payroll_analysis/hr_payslip.py | 1 + hr_payroll_analysis/hr_salary_rule.py | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hr_payroll_analysis/hr_payslip.py b/hr_payroll_analysis/hr_payslip.py index e30f449af93..954febf519f 100644 --- a/hr_payroll_analysis/hr_payslip.py +++ b/hr_payroll_analysis/hr_payslip.py @@ -52,6 +52,7 @@ def compute_analysis_lines(self, cr, uid, ids, context=None): required_lines = [ line for line in payslip.details_by_salary_rule_category if line.salary_rule_id.include_in_payroll_analysis + and line.total ] is_refund = payslip.credit_note diff --git a/hr_payroll_analysis/hr_salary_rule.py b/hr_payroll_analysis/hr_salary_rule.py index c9e3e619364..f2274046206 100644 --- a/hr_payroll_analysis/hr_salary_rule.py +++ b/hr_payroll_analysis/hr_salary_rule.py @@ -55,8 +55,6 @@ def refresh_analysis_lines(self, cr, uid, ids, context=None): cr, uid, [('salary_rule_id', '=', rule.id)], context=context) - print line_ids - analysis_line_obj.unlink(cr, uid, line_ids, context=context) if rule.include_in_payroll_analysis: @@ -65,6 +63,7 @@ def refresh_analysis_lines(self, cr, uid, ids, context=None): cr, uid, [ ('salary_rule_id', '=', rule.id), ('slip_id.state', 'not in', ['draft', 'cancel']), + ('total', '!=', 0), ], context=context) for line in payslip_line_obj.browse( From 2d354e08d4a729411ec9fbcdeddca5ac635ace4d Mon Sep 17 00:00:00 2001 From: dufresnedavid Date: Thu, 12 Feb 2015 18:10:08 -0500 Subject: [PATCH 03/11] Add README.rst --- hr_payroll_analysis/README.rst | 61 ++++++++++++++++++++++++++++++ hr_payroll_analysis/__openerp__.py | 10 ----- 2 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 hr_payroll_analysis/README.rst diff --git a/hr_payroll_analysis/README.rst b/hr_payroll_analysis/README.rst new file mode 100644 index 00000000000..b81768f4da4 --- /dev/null +++ b/hr_payroll_analysis/README.rst @@ -0,0 +1,61 @@ +Payroll Analysis +================ + +This module adds a report over amounts of payslips line related to a +a salary rule. It allows to group amounts by date, companies, salary rules +and employees. + + +Installation +============ + +Nothing to do except install the module + + +Configuration +============= + +Go to: Human Resources -> Configuration -> Payroll -> Salary Rules +Select a salary rule you wish to add to the report. +In the form view, check the 'Include in Payroll Analysis' box. + + +Usage +===== + +Go to: Reporting -> Human Ressources -> Payroll Analysis, +Fill the wizard and click 'Generate the Report' + + +Known issues / Roadmap +====================== + +None + + +Credits +======= + +Contributors +------------ + +.. image:: http://sflx.ca/logo + :alt: Savoir-faire Linux + :target: http://sflx.ca + +* David Dufresne +* Maxime Chambreuil +* Pierre Lamarche + +Maintainer +---------- + +.. image:: http://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: http://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. + +To contribute to this module, please visit http://odoo-community.org. \ No newline at end of file diff --git a/hr_payroll_analysis/__openerp__.py b/hr_payroll_analysis/__openerp__.py index a4684f51d9e..eb2a9216a75 100644 --- a/hr_payroll_analysis/__openerp__.py +++ b/hr_payroll_analysis/__openerp__.py @@ -30,16 +30,6 @@ a salary rule. It allows to group amounts by date, companies, salary rules and employees. -This module replaces the use of contribution registers already implemented -in Odoo, which is meant to generate pdf reports. The purpose of this module -is to create dynamic reports. - -To include salary rules in the report, in the salary rule form view, -check the field "Include in Payroll Analysis". - -To view the report go to Reporting -> Human Ressources -> Payroll Analysis, -then fill the wizard. - Contributors ------------ * David Dufresne From ffa820a476534f1e6a115628f9f4f22ec8e25f52 Mon Sep 17 00:00:00 2001 From: dufresnedavid Date: Fri, 13 Feb 2015 09:34:02 -0500 Subject: [PATCH 04/11] Simplify redondant methods --- hr_payroll_analysis/hr_payslip.py | 17 +++--- .../hr_payslip_analysis_line.py | 1 - .../tests/test_payroll_analysis.py | 57 +++---------------- 3 files changed, 19 insertions(+), 56 deletions(-) diff --git a/hr_payroll_analysis/hr_payslip.py b/hr_payroll_analysis/hr_payslip.py index 954febf519f..7c355481906 100644 --- a/hr_payroll_analysis/hr_payslip.py +++ b/hr_payroll_analysis/hr_payslip.py @@ -38,16 +38,22 @@ def process_sheet(self, cr, uid, ids, context=None): """ super(hr_payslip, self).process_sheet(cr, uid, ids, context=context) + self.remove_analysis_lines(cr, uid, ids, context=context) self.compute_analysis_lines(cr, uid, ids, context=context) + def remove_analysis_lines(self, cr, uid, ids, context=None): + """ + Make sure no analysis line has already been computed + """ + for payslip in self.browse(cr, uid, ids, context=context): + for line in payslip.analysis_line_ids: + line.unlink() + def compute_analysis_lines(self, cr, uid, ids, context=None): analysis_line_obj = self.pool['hr.payslip.analysis.line'] for payslip in self.browse(cr, uid, ids, context=context): - # Make sure no analysis line has already been computed - for line in payslip.analysis_line_ids: - line.unlink() required_lines = [ line for line in payslip.details_by_salary_rule_category @@ -73,8 +79,5 @@ def cancel_sheet(self, cr, uid, ids, context=None): """ Make sure no analytic lines exist when a payslip is cancelled """ - for payslip in self.browse(cr, uid, ids, context=context): - for line in payslip.analysis_line_ids: - line.unlink() - + self.remove_analysis_lines(cr, uid, ids, context=context) super(hr_payslip, self).cancel_sheet(cr, uid, ids, context=context) diff --git a/hr_payroll_analysis/hr_payslip_analysis_line.py b/hr_payroll_analysis/hr_payslip_analysis_line.py index 6d753fee31c..4699c8529c9 100644 --- a/hr_payroll_analysis/hr_payslip_analysis_line.py +++ b/hr_payroll_analysis/hr_payslip_analysis_line.py @@ -18,7 +18,6 @@ # ############################################################################## - from openerp.osv import orm, fields diff --git a/hr_payroll_analysis/tests/test_payroll_analysis.py b/hr_payroll_analysis/tests/test_payroll_analysis.py index 21c714583f0..b3c9b319a4d 100644 --- a/hr_payroll_analysis/tests/test_payroll_analysis.py +++ b/hr_payroll_analysis/tests/test_payroll_analysis.py @@ -121,30 +121,7 @@ def setUp(self): self.payslip_model.compute_sheet( cr, uid, self.payslip_ids, context=context) - def tearDown(self): - cr, uid, context = self.cr, self.uid, self.context - - self.payslip_model.write( - cr, uid, self.payslip_ids, {'state': 'draft'}, context=context) - - self.payslip_model.unlink( - cr, uid, self.payslip_ids, context=context) - - self.contract_model.unlink( - cr, uid, [self.contract_id], context=context) - - self.employee_model.unlink( - cr, uid, [self.employee_id], context=context) - - self.structure_model.unlink( - cr, uid, [self.structure_id], context=context) - - self.rule_model.unlink( - cr, uid, [self.rule_id, self.rule_2_id], context=context) - - super(test_payroll_analysis, self).tearDown() - - def test_payslip_analysis_line_generated(self): + def process_sheets(self): cr, uid, context = self.cr, self.uid, self.context self.payslip_model.process_sheet( @@ -163,17 +140,15 @@ def test_payslip_analysis_line_generated(self): for line in lines: self.assertEqual(line.amount, 100) - # Process the payslips a second time - # Check that there is still one analysis line - # per payslip - self.payslip_model.process_sheet( - cr, uid, self.payslip_ids, context=context) + def test_payslip_analysis_line_generated(self): + cr, uid, context = self.cr, self.uid, self.context - line_ids = self.analysis_line_model.search( - cr, uid, [('payslip_id', 'in', self.payslip_ids)], - context=context) + self.process_sheets() - self.assertEqual(len(line_ids), 2) + # Process the payslips a second time + # Check that there is the same number of analysis lines + # generated + self.process_sheets() # Cancel a payslip and check that there is only one # analysis line left @@ -193,21 +168,7 @@ def test_payslip_analysis_line_generated(self): def test_salary_rule_refresh(self): cr, uid, context = self.cr, self.uid, self.context - self.payslip_model.process_sheet( - cr, uid, self.payslip_ids, context=context) - - # Check that the analysis lines were created - line_ids = self.analysis_line_model.search( - cr, uid, [('payslip_id', 'in', self.payslip_ids)], - context=context) - - lines = self.analysis_line_model.browse( - cr, uid, line_ids, context=context) - - self.assertEqual(len(lines), 2) - - for line in lines: - self.assertEqual(line.amount, 100) + self.process_sheets() # Include the second salary rule in the report self.rule_model.write( From 7a911167e3828dd8beda62201ec7673639134675 Mon Sep 17 00:00:00 2001 From: Alexandre Fayolle Date: Mon, 2 Mar 2015 17:24:52 +0100 Subject: [PATCH 05/11] Add OCA as author of OCA addons In order to get visibility on https://www.odoo.com/apps the OCA board has decided to add the OCA as author of all the addons maintained as part of the association. --- hr_payroll_analysis/__openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hr_payroll_analysis/__openerp__.py b/hr_payroll_analysis/__openerp__.py index eb2a9216a75..0429155270f 100644 --- a/hr_payroll_analysis/__openerp__.py +++ b/hr_payroll_analysis/__openerp__.py @@ -34,7 +34,7 @@ ------------ * David Dufresne """, - 'author': 'Savoir-faire Linux', + 'author': "Savoir-faire Linux,Odoo Community Association (OCA)", 'website': 'https://www.savoirfairelinux.com/', 'depends': [ 'hr_payroll', From deb9163cb8ab5b46d753df0cfb0e18a6dd265a6e Mon Sep 17 00:00:00 2001 From: dufresnedavid Date: Thu, 26 Feb 2015 20:18:16 -0500 Subject: [PATCH 06/11] Fix PEP8 W503 --- hr_payroll_analysis/hr_payslip.py | 4 ++-- hr_payroll_analysis/hr_salary_rule.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hr_payroll_analysis/hr_payslip.py b/hr_payroll_analysis/hr_payslip.py index 7c355481906..7f15dab5518 100644 --- a/hr_payroll_analysis/hr_payslip.py +++ b/hr_payroll_analysis/hr_payslip.py @@ -57,8 +57,8 @@ def compute_analysis_lines(self, cr, uid, ids, context=None): required_lines = [ line for line in payslip.details_by_salary_rule_category - if line.salary_rule_id.include_in_payroll_analysis - and line.total + if line.salary_rule_id.include_in_payroll_analysis and + line.total ] is_refund = payslip.credit_note diff --git a/hr_payroll_analysis/hr_salary_rule.py b/hr_payroll_analysis/hr_salary_rule.py index f2274046206..c58395b1e29 100644 --- a/hr_payroll_analysis/hr_salary_rule.py +++ b/hr_payroll_analysis/hr_salary_rule.py @@ -77,6 +77,6 @@ def refresh_analysis_lines(self, cr, uid, ids, context=None): 'payslip_line_id': line.id, 'payslip_id': payslip.id, 'date': payslip.date_from, - 'amount': payslip.credit_note - and -line.total or line.total, + 'amount': payslip.credit_note and -line.total or + line.total, }, context=context) From 636ec9c64a22bf2773d364f84a289c254e845dd9 Mon Sep 17 00:00:00 2001 From: Salton Date: Tue, 6 Oct 2015 05:49:08 +0000 Subject: [PATCH 07/11] [PORT] hr_payroll_analysis to 8.0 --- hr_payroll_analysis/README.rst | 3 +- hr_payroll_analysis/__init__.py | 28 +-- hr_payroll_analysis/__openerp__.py | 40 +--- hr_payroll_analysis/hr_payslip.py | 83 -------- .../hr_payslip_analysis_line.py | 66 ------ hr_payroll_analysis/hr_salary_rule.py | 82 ------- hr_payroll_analysis/i18n/de.po | 201 ++++++++++++++++++ hr_payroll_analysis/i18n/es.po | 201 ++++++++++++++++++ hr_payroll_analysis/i18n/fr.po | 67 +++--- hr_payroll_analysis/models/__init__.py | 6 + hr_payroll_analysis/models/hr_payslip.py | 62 ++++++ .../models/hr_payslip_analysis_line.py | 19 ++ hr_payroll_analysis/models/hr_salary_rule.py | 56 +++++ .../{ => views}/hr_salary_rule_view.xml | 0 hr_payroll_analysis/wizard/__init__.py | 22 +- .../wizard/payroll_analysis.py | 175 ++++++--------- .../wizard/payroll_analysis_view.xml | 4 +- 17 files changed, 653 insertions(+), 462 deletions(-) delete mode 100644 hr_payroll_analysis/hr_payslip.py delete mode 100644 hr_payroll_analysis/hr_payslip_analysis_line.py delete mode 100644 hr_payroll_analysis/hr_salary_rule.py create mode 100644 hr_payroll_analysis/i18n/de.po create mode 100644 hr_payroll_analysis/i18n/es.po create mode 100644 hr_payroll_analysis/models/__init__.py create mode 100644 hr_payroll_analysis/models/hr_payslip.py create mode 100644 hr_payroll_analysis/models/hr_payslip_analysis_line.py create mode 100644 hr_payroll_analysis/models/hr_salary_rule.py rename hr_payroll_analysis/{ => views}/hr_salary_rule_view.xml (100%) diff --git a/hr_payroll_analysis/README.rst b/hr_payroll_analysis/README.rst index b81768f4da4..859a40e6251 100644 --- a/hr_payroll_analysis/README.rst +++ b/hr_payroll_analysis/README.rst @@ -23,7 +23,7 @@ In the form view, check the 'Include in Payroll Analysis' box. Usage ===== -Go to: Reporting -> Human Ressources -> Payroll Analysis, +Go to: Reporting -> Human Resources -> Payroll Analysis, Fill the wizard and click 'Generate the Report' @@ -46,6 +46,7 @@ Contributors * David Dufresne * Maxime Chambreuil * Pierre Lamarche +* Salton Massally Maintainer ---------- diff --git a/hr_payroll_analysis/__init__.py b/hr_payroll_analysis/__init__.py index 5fe6047b74f..d5693d0f6e9 100644 --- a/hr_payroll_analysis/__init__.py +++ b/hr_payroll_analysis/__init__.py @@ -1,27 +1,3 @@ # -*- coding:utf-8 -*- -############################################################################## -# -# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from . import ( - hr_payslip, - hr_salary_rule, - hr_payslip_analysis_line, - wizard, -) +from . import models +from . import wizard \ No newline at end of file diff --git a/hr_payroll_analysis/__openerp__.py b/hr_payroll_analysis/__openerp__.py index 0429155270f..e484fe73dbe 100644 --- a/hr_payroll_analysis/__openerp__.py +++ b/hr_payroll_analysis/__openerp__.py @@ -1,50 +1,22 @@ # -*- coding:utf-8 -*- -############################################################################## -# -# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - { 'name': 'Payroll Analysis', 'version': '1.0', 'license': 'AGPL-3', 'category': 'Generic Modules/Human Resources', - 'description': """ -Payroll Analysis -================ -This module adds a report over amounts of payslips line related to a -a salary rule. It allows to group amounts by date, companies, salary rules -and employees. - -Contributors ------------- -* David Dufresne -""", - 'author': "Savoir-faire Linux,Odoo Community Association (OCA)", + 'summary': "Adds a report over amounts of payslips line related to a " + "a salary rule.", + 'author': "Savoir-faire Linux, " + "Salton Massally (iDT Labs) " + "Odoo Community Association (OCA)", 'website': 'https://www.savoirfairelinux.com/', 'depends': [ 'hr_payroll', ], 'data': [ 'wizard/payroll_analysis_view.xml', - 'hr_salary_rule_view.xml', + 'views/hr_salary_rule_view.xml', 'security/ir.model.access.csv', ], - 'test': [], - 'demo': [], 'installable': True, } diff --git a/hr_payroll_analysis/hr_payslip.py b/hr_payroll_analysis/hr_payslip.py deleted file mode 100644 index 7f15dab5518..00000000000 --- a/hr_payroll_analysis/hr_payslip.py +++ /dev/null @@ -1,83 +0,0 @@ -# -*- coding:utf-8 -*- -############################################################################## -# -# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp.osv import orm, fields - - -class hr_payslip(orm.Model): - _inherit = 'hr.payslip' - _columns = { - 'analysis_line_ids': fields.one2many( - 'hr.payslip.analysis.line', - 'payslip_id', - 'Analysis Lines', - ), - } - - def process_sheet(self, cr, uid, ids, context=None): - """ - Create the analysis lines when the payslip is confirmed - """ - super(hr_payslip, self).process_sheet(cr, uid, ids, context=context) - - self.remove_analysis_lines(cr, uid, ids, context=context) - self.compute_analysis_lines(cr, uid, ids, context=context) - - def remove_analysis_lines(self, cr, uid, ids, context=None): - """ - Make sure no analysis line has already been computed - """ - for payslip in self.browse(cr, uid, ids, context=context): - for line in payslip.analysis_line_ids: - line.unlink() - - def compute_analysis_lines(self, cr, uid, ids, context=None): - - analysis_line_obj = self.pool['hr.payslip.analysis.line'] - - for payslip in self.browse(cr, uid, ids, context=context): - - required_lines = [ - line for line in payslip.details_by_salary_rule_category - if line.salary_rule_id.include_in_payroll_analysis and - line.total - ] - - is_refund = payslip.credit_note - - for line in required_lines: - analysis_line_obj.create( - cr, uid, { - 'company_id': payslip.company_id.id, - 'employee_id': payslip.employee_id.id, - 'salary_rule_id': line.salary_rule_id.id, - 'payslip_line_id': line.id, - 'payslip_id': payslip.id, - 'date': payslip.date_from, - 'amount': is_refund and -line.total or line.total, - }, context=context) - - def cancel_sheet(self, cr, uid, ids, context=None): - """ - Make sure no analytic lines exist when a payslip is cancelled - """ - self.remove_analysis_lines(cr, uid, ids, context=context) - super(hr_payslip, self).cancel_sheet(cr, uid, ids, context=context) diff --git a/hr_payroll_analysis/hr_payslip_analysis_line.py b/hr_payroll_analysis/hr_payslip_analysis_line.py deleted file mode 100644 index 4699c8529c9..00000000000 --- a/hr_payroll_analysis/hr_payslip_analysis_line.py +++ /dev/null @@ -1,66 +0,0 @@ -# -*- coding:utf-8 -*- -############################################################################## -# -# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp.osv import orm, fields - - -class hr_payslip_analysis_line(orm.Model): - _name = 'hr.payslip.analysis.line' - - _columns = { - 'payslip_id': fields.many2one( - 'hr.payslip', - 'Payslip', - required=True, - ondelete="cascade", - ), - 'payslip_line_id': fields.many2one( - 'hr.payslip.line', - 'Payslip Line', - required=True, - ondelete="cascade", - ), - 'salary_rule_id': fields.many2one( - 'hr.salary.rule', - 'Salary Rule', - required=True, - select=True, - ), - 'company_id': fields.many2one( - 'res.company', - 'Company', - required=True, - select=True, - ), - 'employee_id': fields.many2one( - 'hr.employee', - 'Employee', - required=True, - select=True, - ), - 'date': fields.date( - 'Date', - required=True, - ), - 'amount': fields.float( - 'Amount', - required=True, - ), - } diff --git a/hr_payroll_analysis/hr_salary_rule.py b/hr_payroll_analysis/hr_salary_rule.py deleted file mode 100644 index c58395b1e29..00000000000 --- a/hr_payroll_analysis/hr_salary_rule.py +++ /dev/null @@ -1,82 +0,0 @@ -# -*- coding:utf-8 -*- -############################################################################## -# -# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp.osv import orm, fields - - -class hr_salary_rule(orm.Model): - _inherit = 'hr.salary.rule' - - _columns = { - 'include_in_payroll_analysis': fields.boolean( - 'Include in Payroll Analysis', - help="If True, every payslip line related to this salary " - "rule will appear in the payroll analysis report." - ), - } - - def write(self, cr, uid, ids, vals, context=None): - res = super(hr_salary_rule, self).write( - cr, uid, ids, vals, context=context) - - if 'include_in_payroll_analysis' in vals: - self.refresh_analysis_lines(cr, uid, ids, context=context) - - return res - - def refresh_analysis_lines(self, cr, uid, ids, context=None): - """This method is used to refresh the analysis lines - when a salary rule's include_in_payroll_analysis field is changed - """ - analysis_line_obj = self.pool['hr.payslip.analysis.line'] - payslip_line_obj = self.pool['hr.payslip.line'] - - for rule in self.browse(cr, uid, ids, context=context): - # Remove existing analysis lines - line_ids = analysis_line_obj.search( - cr, uid, [('salary_rule_id', '=', rule.id)], - context=context) - - analysis_line_obj.unlink(cr, uid, line_ids, context=context) - - if rule.include_in_payroll_analysis: - # Create analysis lines - payslip_line_ids = payslip_line_obj.search( - cr, uid, [ - ('salary_rule_id', '=', rule.id), - ('slip_id.state', 'not in', ['draft', 'cancel']), - ('total', '!=', 0), - ], context=context) - - for line in payslip_line_obj.browse( - cr, uid, payslip_line_ids, context=context): - payslip = line.slip_id - analysis_line_obj.create( - cr, uid, { - 'company_id': payslip.company_id.id, - 'employee_id': payslip.employee_id.id, - 'salary_rule_id': line.salary_rule_id.id, - 'payslip_line_id': line.id, - 'payslip_id': payslip.id, - 'date': payslip.date_from, - 'amount': payslip.credit_note and -line.total or - line.total, - }, context=context) diff --git a/hr_payroll_analysis/i18n/de.po b/hr_payroll_analysis/i18n/de.po new file mode 100644 index 00000000000..ff1b2043d17 --- /dev/null +++ b/hr_payroll_analysis/i18n/de.po @@ -0,0 +1,201 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * hr_payroll_analysis +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: hr (7.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-07-27 23:36+0000\n" +"PO-Revision-Date: 2015-07-27 23:39+0000\n" +"Last-Translator: <>\n" +"Language-Team: German (http://www.transifex.com/oca/OCA-hr-7-0/language/de/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: de\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: hr_payroll_analysis +#: field:hr.salary.rule,include_in_payroll_analysis:0 +msgid "Include in Payroll Analysis" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payroll.analysis:0 +msgid "Generate the Report" +msgstr "" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,type:0 +msgid "By Company" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +msgid "Group By..." +msgstr "" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,period:0 +msgid "Every Year" +msgstr "" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,period:0 +msgid "Previous Year" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +#: field:hr.payslip.analysis.line,employee_id:0 +msgid "Employee" +msgstr "Angestellter" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,type:0 +msgid "By Salary Rule" +msgstr "" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,type:0 +msgid "By Employee" +msgstr "" + +#. module: hr_payroll_analysis +#: help:hr.salary.rule,include_in_payroll_analysis:0 +msgid "" +"If True, every payslip line related to this salary rule will appear in the " +"payroll analysis report." +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 field:hr.payslip.analysis.line,company_id:0 +msgid "Company" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,salary_rule_ids:0 +msgid "Salary Rules" +msgstr "" + +#. module: hr_payroll_analysis +#: model:ir.model,name:hr_payroll_analysis.model_hr_salary_rule +msgid "hr.salary.rule" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 field:hr.payslip.analysis.line,date:0 +msgid "Date" +msgstr "" + +#. module: hr_payroll_analysis +#: model:ir.model,name:hr_payroll_analysis.model_hr_payslip +msgid "Pay Slip" +msgstr "Lohnzettel" + +#. module: hr_payroll_analysis +#: field:hr.payslip.analysis.line,payslip_line_id:0 +msgid "Payslip Line" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,end_date:0 +msgid "End Date" +msgstr "Enddatum" + +#. module: hr_payroll_analysis +#: code:addons/hr_payroll_analysis/wizard/payroll_analysis.py:181 +#: view:hr.payroll.analysis:0 +#: model:ir.actions.act_window,name:hr_payroll_analysis.action_payroll_analysis_config +#: model:ir.ui.menu,name:hr_payroll_analysis.menu_action_payroll_analysis +#, python-format +msgid "Payroll Analysis" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,employee_ids:0 +msgid "Employees" +msgstr "Angestellte" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,company_ids:0 +msgid "Companies" +msgstr "Unternehmen" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,type:0 +msgid "Analysis Type" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +msgid "Search Payslip Lines" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payslip.analysis.line,amount:0 +msgid "Amount" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payroll.analysis:0 +msgid "Model" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payslip.analysis.line,payslip_id:0 +msgid "Payslip" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payslip,analysis_line_ids:0 +msgid "Analysis Lines" +msgstr "" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,period:0 +msgid "Current Year" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +msgid "Payroll Analysis Lines" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,period:0 +msgid "Analysis Period" +msgstr "" + +#. module: hr_payroll_analysis +#: model:ir.model,name:hr_payroll_analysis.model_hr_payslip_analysis_line +msgid "hr.payslip.analysis.line" +msgstr "" + +#. module: hr_payroll_analysis +#: model:ir.model,name:hr_payroll_analysis.model_hr_payroll_analysis +msgid "Payroll Analysis Wizard" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payroll.analysis:0 +msgid "Cancel" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,start_date:0 +msgid "Start Date" +msgstr "Anfangsdatum" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +#: field:hr.payslip.analysis.line,salary_rule_id:0 +msgid "Salary Rule" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payroll.analysis:0 +msgid "or" +msgstr "" diff --git a/hr_payroll_analysis/i18n/es.po b/hr_payroll_analysis/i18n/es.po new file mode 100644 index 00000000000..610da064cc7 --- /dev/null +++ b/hr_payroll_analysis/i18n/es.po @@ -0,0 +1,201 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * hr_payroll_analysis +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: hr (7.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-07-27 23:36+0000\n" +"PO-Revision-Date: 2015-07-27 23:39+0000\n" +"Last-Translator: <>\n" +"Language-Team: Spanish (http://www.transifex.com/oca/OCA-hr-7-0/language/es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: hr_payroll_analysis +#: field:hr.salary.rule,include_in_payroll_analysis:0 +msgid "Include in Payroll Analysis" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payroll.analysis:0 +msgid "Generate the Report" +msgstr "" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,type:0 +msgid "By Company" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +msgid "Group By..." +msgstr "" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,period:0 +msgid "Every Year" +msgstr "" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,period:0 +msgid "Previous Year" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +#: field:hr.payslip.analysis.line,employee_id:0 +msgid "Employee" +msgstr "Empleado" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,type:0 +msgid "By Salary Rule" +msgstr "" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,type:0 +msgid "By Employee" +msgstr "" + +#. module: hr_payroll_analysis +#: help:hr.salary.rule,include_in_payroll_analysis:0 +msgid "" +"If True, every payslip line related to this salary rule will appear in the " +"payroll analysis report." +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 field:hr.payslip.analysis.line,company_id:0 +msgid "Company" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,salary_rule_ids:0 +msgid "Salary Rules" +msgstr "" + +#. module: hr_payroll_analysis +#: model:ir.model,name:hr_payroll_analysis.model_hr_salary_rule +msgid "hr.salary.rule" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 field:hr.payslip.analysis.line,date:0 +msgid "Date" +msgstr "" + +#. module: hr_payroll_analysis +#: model:ir.model,name:hr_payroll_analysis.model_hr_payslip +msgid "Pay Slip" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payslip.analysis.line,payslip_line_id:0 +msgid "Payslip Line" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,end_date:0 +msgid "End Date" +msgstr "" + +#. module: hr_payroll_analysis +#: code:addons/hr_payroll_analysis/wizard/payroll_analysis.py:181 +#: view:hr.payroll.analysis:0 +#: model:ir.actions.act_window,name:hr_payroll_analysis.action_payroll_analysis_config +#: model:ir.ui.menu,name:hr_payroll_analysis.menu_action_payroll_analysis +#, python-format +msgid "Payroll Analysis" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,employee_ids:0 +msgid "Employees" +msgstr "Empleados" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,company_ids:0 +msgid "Companies" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,type:0 +msgid "Analysis Type" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +msgid "Search Payslip Lines" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payslip.analysis.line,amount:0 +msgid "Amount" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payroll.analysis:0 +msgid "Model" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payslip.analysis.line,payslip_id:0 +msgid "Payslip" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payslip,analysis_line_ids:0 +msgid "Analysis Lines" +msgstr "" + +#. module: hr_payroll_analysis +#: selection:hr.payroll.analysis,period:0 +msgid "Current Year" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +msgid "Payroll Analysis Lines" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,period:0 +msgid "Analysis Period" +msgstr "" + +#. module: hr_payroll_analysis +#: model:ir.model,name:hr_payroll_analysis.model_hr_payslip_analysis_line +msgid "hr.payslip.analysis.line" +msgstr "" + +#. module: hr_payroll_analysis +#: model:ir.model,name:hr_payroll_analysis.model_hr_payroll_analysis +msgid "Payroll Analysis Wizard" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payroll.analysis:0 +msgid "Cancel" +msgstr "" + +#. module: hr_payroll_analysis +#: field:hr.payroll.analysis,start_date:0 +msgid "Start Date" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +#: field:hr.payslip.analysis.line,salary_rule_id:0 +msgid "Salary Rule" +msgstr "" + +#. module: hr_payroll_analysis +#: view:hr.payroll.analysis:0 +msgid "or" +msgstr "" diff --git a/hr_payroll_analysis/i18n/fr.po b/hr_payroll_analysis/i18n/fr.po index 84e0b1ee8da..58b8f46c375 100644 --- a/hr_payroll_analysis/i18n/fr.po +++ b/hr_payroll_analysis/i18n/fr.po @@ -1,25 +1,21 @@ # Translation of OpenERP Server. # This file contains the translation of the following modules: -# * hr_payroll_analysis -# +# * hr_payroll_analysis +# +# Translators: msgid "" msgstr "" -"Project-Id-Version: OpenERP Server 7.0\n" +"Project-Id-Version: hr (7.0)\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-12 14:29+0000\n" -"PO-Revision-Date: 2015-02-12 09:45-0500\n" -"Last-Translator: David Dufresne \n" -"Language-Team: \n" +"POT-Creation-Date: 2015-07-27 23:36+0000\n" +"PO-Revision-Date: 2015-07-27 23:39+0000\n" +"Last-Translator: OCA Transbot \n" +"Language-Team: French (http://www.transifex.com/oca/OCA-hr-7-0/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: \n" -"X-Generator: Poedit 1.5.4\n" - -#. module: hr_payroll_analysis -#: view:hr.payslip.analysis.line:0 -msgid "Search Payslip Lines" -msgstr "Chercher des lignes de paie" +"Content-Transfer-Encoding: \n" +"Language: fr\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" #. module: hr_payroll_analysis #: field:hr.salary.rule,include_in_payroll_analysis:0 @@ -67,6 +63,13 @@ msgstr "Par règle de salaire" msgid "By Employee" msgstr "Par employé" +#. module: hr_payroll_analysis +#: help:hr.salary.rule,include_in_payroll_analysis:0 +msgid "" +"If True, every payslip line related to this salary rule will appear in the " +"payroll analysis report." +msgstr "Si vrai, les lignes de bulletin de paie liées à cette règle apparaîtront dans le rapport d'analyse de la paie." + #. module: hr_payroll_analysis #: view:hr.payslip.analysis.line:0 field:hr.payslip.analysis.line,company_id:0 msgid "Company" @@ -80,10 +83,10 @@ msgstr "Règle de salaire" #. module: hr_payroll_analysis #: model:ir.model,name:hr_payroll_analysis.model_hr_salary_rule msgid "hr.salary.rule" -msgstr "" +msgstr "hr.salary.rule" #. module: hr_payroll_analysis -#: field:hr.payslip.analysis.line,date:0 +#: view:hr.payslip.analysis.line:0 field:hr.payslip.analysis.line,date:0 msgid "Date" msgstr "Date" @@ -97,15 +100,6 @@ msgstr "Bulletin de paie" msgid "Payslip Line" msgstr "Ligne de bulletin de paie" -#. module: hr_payroll_analysis -#: help:hr.salary.rule,include_in_payroll_analysis:0 -msgid "" -"If True, every payslip line related to this salary rule will appear in the " -"payroll analysis report." -msgstr "" -"Si vrai, les lignes de bulletin de paie liées à cette règle apparaîtront " -"dans le rapport d'analyse de la paie." - #. module: hr_payroll_analysis #: field:hr.payroll.analysis,end_date:0 msgid "End Date" @@ -135,6 +129,11 @@ msgstr "Sociétés" msgid "Analysis Type" msgstr "Angle d'analyse" +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +msgid "Search Payslip Lines" +msgstr "Chercher des lignes de paie" + #. module: hr_payroll_analysis #: field:hr.payslip.analysis.line,amount:0 msgid "Amount" @@ -160,16 +159,16 @@ msgstr "Lignes d'analyse" msgid "Current Year" msgstr "L'année courante" +#. module: hr_payroll_analysis +#: view:hr.payslip.analysis.line:0 +msgid "Payroll Analysis Lines" +msgstr "Lignes d'analyse de la paie" + #. module: hr_payroll_analysis #: field:hr.payroll.analysis,period:0 msgid "Analysis Period" msgstr "Période d'analyse" -#. module: hr_payroll_analysis -#: view:hr.payroll.analysis:0 -msgid "or" -msgstr "ou" - #. module: hr_payroll_analysis #: model:ir.model,name:hr_payroll_analysis.model_hr_payslip_analysis_line msgid "hr.payslip.analysis.line" @@ -197,6 +196,6 @@ msgid "Salary Rule" msgstr "Règle de salaire" #. module: hr_payroll_analysis -#: view:hr.payslip.analysis.line:0 -msgid "Payroll Analysis Lines" -msgstr "Lignes d'analyse de la paie" +#: view:hr.payroll.analysis:0 +msgid "or" +msgstr "ou" diff --git a/hr_payroll_analysis/models/__init__.py b/hr_payroll_analysis/models/__init__.py new file mode 100644 index 00000000000..9c935decea7 --- /dev/null +++ b/hr_payroll_analysis/models/__init__.py @@ -0,0 +1,6 @@ +# -*- coding:utf-8 -*- +from . import ( + hr_payslip, + hr_salary_rule, + hr_payslip_analysis_line, +) diff --git a/hr_payroll_analysis/models/hr_payslip.py b/hr_payroll_analysis/models/hr_payslip.py new file mode 100644 index 00000000000..b29eee66cc6 --- /dev/null +++ b/hr_payroll_analysis/models/hr_payslip.py @@ -0,0 +1,62 @@ +# -*- coding:utf-8 -*- +from openerp import models, fields, api + + +class HrPayslip(models.Model): + _inherit = 'hr.payslip' + + analysis_line_ids = fields.One2many('hr.payslip.analysis.line', + 'payslip_id', 'Analysis Lines') + + @api.multi + def process_sheet(self): + """ + Create the analysis lines when the payslip is confirmed + """ + super(HrPayslip, self).process_sheet() + self.remove_analysis_lines() + self.compute_analysis_lines() + + @api.multi + def remove_analysis_lines(self): + """ + Make sure no analysis line has already been computed + """ + for payslip in self: + for line in payslip.analysis_line_ids: + line.unlink() + + @api.multi + def compute_analysis_lines(self): + + analysis_line_obj = self.env['hr.payslip.analysis.line'] + + for payslip in self: + + required_lines = [ + line for line in payslip.details_by_salary_rule_category + if line.salary_rule_id.include_in_payroll_analysis and + line.total + ] + + is_refund = payslip.credit_note + + for line in required_lines: + analysis_line_obj.create( + { + 'company_id': payslip.company_id.id, + 'employee_id': payslip.employee_id.id, + 'salary_rule_id': line.salary_rule_id.id, + 'payslip_line_id': line.id, + 'payslip_id': payslip.id, + 'date': payslip.date_from, + 'amount': is_refund and -line.total or line.total, + }) + + @api.multi + def cancel_sheet(self): + """ + Make sure no analytic lines exist when a payslip is cancelled + """ + self.remove_analysis_lines() + super(HrPayslip, self).cancel_sheet() diff --git a/hr_payroll_analysis/models/hr_payslip_analysis_line.py b/hr_payroll_analysis/models/hr_payslip_analysis_line.py new file mode 100644 index 00000000000..3ab5e2c8f28 --- /dev/null +++ b/hr_payroll_analysis/models/hr_payslip_analysis_line.py @@ -0,0 +1,19 @@ +# -*- coding:utf-8 -*- +from openerp import models, fields, api + + +class HrPayslipAnalysisLine(models.Model): + _name = 'hr.payslip.analysis.line' + + payslip_id = fields.Many2one('hr.payslip', 'Payslip', required=True, + ondelete="cascade",) + payslip_line_id = fields.Many2one('hr.payslip.line', 'Payslip Line', + required=True, ondelete="cascade") + salary_rule_id = fields.Many2one('hr.salary.rule', 'Salary Rule', + required=True, index=True) + company_id = fields.Many2one('res.company', 'Company', required=True, + index=True) + employee_id = fields.Many2one('hr.employee', 'Employee', required=True, + index=True) + date = fields.Date('Date', required=True) + amount= fields.Float('Amount', required=True,) diff --git a/hr_payroll_analysis/models/hr_salary_rule.py b/hr_payroll_analysis/models/hr_salary_rule.py new file mode 100644 index 00000000000..378f47c4c21 --- /dev/null +++ b/hr_payroll_analysis/models/hr_salary_rule.py @@ -0,0 +1,56 @@ +# -*- coding:utf-8 -*- +from openerp import models, fields, api + + +class HrSalaryRule(models.Model): + _inherit = 'hr.salary.rule' + + include_in_payroll_analysis = fields.Boolean( + 'Include in Payroll Analysis', + help="If True, every payslip line related to this salary " + "rule will appear in the payroll analysis report." + ) + + @api.multi + def write(self, vals): + res = super(HrSalaryRule, self).write(vals) + if 'include_in_payroll_analysis' in vals: + self.refresh_analysis_lines() + return res + + @api.multi + def refresh_analysis_lines(self): + """This method is used to refresh the analysis lines + when a salary rule's include_in_payroll_analysis field is changed + """ + analysis_line_obj = self.env['hr.payslip.analysis.line'] + payslip_line_obj = self.env['hr.payslip.line'] + + for rule in self: + # Remove existing analysis lines + lines = analysis_line_obj.search( + [('salary_rule_id', '=', rule.id)]) + lines.unlink() + + if rule.include_in_payroll_analysis: + # Create analysis lines + payslip_lines = payslip_line_obj.search( + [ + ('salary_rule_id', '=', rule.id), + ('slip_id.state', 'not in', ['draft', 'cancel']), + ('total', '!=', 0), + ]) + + for line in payslip_lines: + payslip = line.slip_id + analysis_line_obj.create( + { + 'company_id': payslip.company_id.id, + 'employee_id': payslip.employee_id.id, + 'salary_rule_id': line.salary_rule_id.id, + 'payslip_line_id': line.id, + 'payslip_id': payslip.id, + 'date': payslip.date_from, + 'amount': payslip.credit_note and -line.total or + line.total, + }) diff --git a/hr_payroll_analysis/hr_salary_rule_view.xml b/hr_payroll_analysis/views/hr_salary_rule_view.xml similarity index 100% rename from hr_payroll_analysis/hr_salary_rule_view.xml rename to hr_payroll_analysis/views/hr_salary_rule_view.xml diff --git a/hr_payroll_analysis/wizard/__init__.py b/hr_payroll_analysis/wizard/__init__.py index 73231cb54b7..d64964e4e36 100644 --- a/hr_payroll_analysis/wizard/__init__.py +++ b/hr_payroll_analysis/wizard/__init__.py @@ -1,22 +1,2 @@ # -*- coding:utf-8 -*- -############################################################################## -# -# Copyright (C) 2014 Odoo Canada. All Rights Reserved. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from . import payroll_analysis +from . import payroll_analysis \ No newline at end of file diff --git a/hr_payroll_analysis/wizard/payroll_analysis.py b/hr_payroll_analysis/wizard/payroll_analysis.py index cc687313e16..f28b39455d9 100644 --- a/hr_payroll_analysis/wizard/payroll_analysis.py +++ b/hr_payroll_analysis/wizard/payroll_analysis.py @@ -1,29 +1,9 @@ # -*- coding:utf-8 -*- -############################################################################## -# -# Copyright (C) 2014 Odoo Canada. All Rights Reserved. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - import pytz -from openerp.osv import orm, fields from datetime import datetime, date + +from openerp import models, fields, api, _ from openerp.tools import DEFAULT_SERVER_DATE_FORMAT -from openerp.tools.translate import _ def get_current_year(context): @@ -34,101 +14,70 @@ def get_current_year(context): return datetime.now(tz).year -class payroll_analysis(orm.TransientModel): +class PayrollAnalysis(models.TransientModel): """ Wizard to generate payroll analysis report """ _name = 'hr.payroll.analysis' _description = 'Payroll Analysis Wizard' - _columns = { - 'type': fields.selection( - [ - ('employee', 'By Employee'), - ('salary_rule', 'By Salary Rule'), - ('company', 'By Company'), - ], - type="char", - required=True, - string="Analysis Type", - ), - 'period': fields.selection( - [ - ('current_year', 'Current Year'), - ('previous_year', 'Previous Year'), - ('every_year', 'Every Year'), - ], - string='Analysis Period', - type='string', - ), - 'start_date': fields.datetime('Start Date'), - 'end_date': fields.datetime('End Date'), - 'company_ids': fields.many2many( - 'res.company', - 'payroll_analysis_company_rel', - 'payroll_analysis_id', - 'company_id', - 'Companies', - ), - 'employee_ids': fields.many2many( - 'hr.employee', - 'payroll_analysis_employee_rel', - 'payroll_analysis_id', - 'employee_id', - 'Employees', - ), - 'salary_rule_ids': fields.many2many( - 'hr.salary.rule', - 'payroll_analysis_salary_rule_rel', - 'payroll_analysis_id', - 'salary_rule_id', - 'Salary Rules', - ), - } - - _defaults = { - 'start_date': lambda self, cr, uid, context: ( - date(get_current_year(context), 1, 1).strftime( - DEFAULT_SERVER_DATE_FORMAT)), - 'end_date': lambda self, cr, uid, context: ( - date(get_current_year(context), 12, 31).strftime( - DEFAULT_SERVER_DATE_FORMAT)), - 'period': 'current_year', - 'type': 'salary_rule', - } - - def onchange_period(self, cr, uid, ids, period, context=None): - if not period: - return {} - - if period == 'every_year': - return {'value': { - 'start_date': False, - 'end_date': False, - }} - - year = get_current_year(context) - - if period == 'previous_year': - year -= 1 - - start_date = date(year, 1, 1).strftime(DEFAULT_SERVER_DATE_FORMAT) - end_date = date(year, 12, 31).strftime(DEFAULT_SERVER_DATE_FORMAT) - - return {'value': { - 'start_date': start_date, - 'end_date': end_date, - }} - - def payroll_analysis_open_window(self, cr, uid, ids, context=None): + type = fields.Selection( + [ + ('employee', 'By Employee'), + ('salary_rule', 'By Salary Rule'), + ('company', 'By Company'), + ], required=True, string="Analysis Type", default='salary_rule') + period = fields.Selection( + [ + ('current_year', 'Current Year'), + ('previous_year', 'Previous Year'), + ('every_year', 'Every Year'), + ], string='Analysis Period', default='current_year') + start_date = fields.Datetime('Start Date', + default=lambda self: ( + date(get_current_year(self.env.context), 1, 1).strftime( + DEFAULT_SERVER_DATE_FORMAT))) + end_date = fields.Datetime('End Date', + default=lambda self: ( + date(get_current_year(self.env.context), 12, 31).strftime( + DEFAULT_SERVER_DATE_FORMAT))) + company_ids = fields.Many2many('res.company', + 'payroll_analysis_company_rel', 'payroll_analysis_id', + 'company_id', 'Companies',) + employee_ids = fields.Many2many('hr.employee', + 'payroll_analysis_employee_rel', 'payroll_analysis_id', + 'employee_id', 'Employees',) + salary_rule_ids = fields.Many2many('hr.salary.rule', + 'payroll_analysis_salary_rule_rel', 'payroll_analysis_id', + 'salary_rule_id','Salary Rules',) + + @api.onchange('period') + @api.one + def onchange_period(self): + if self.period: + if self.period == 'every_year': + self.start_date = False + self.end_date = False + + year = get_current_year(self.env.context) + + if self.period == 'previous_year': + year -= 1 + + start_date = date(year, 1, 1).strftime(DEFAULT_SERVER_DATE_FORMAT) + end_date = date(year, 12, 31).strftime(DEFAULT_SERVER_DATE_FORMAT) + + self.start_date = start_date + self.end_date = end_date + + @api.multi + def payroll_analysis_open_window(self): """ This method returns an action that displays profitability lines requested in the wizard """ - if context is None: - context = {} - - wizard = self.browse(cr, uid, ids, context=context)[0] + self.ensure_one() + wizard = self[0] domain_filters = [] @@ -150,12 +99,12 @@ def payroll_analysis_open_window(self, cr, uid, ids, context=None): if wizard.start_date: domain_filters.append(('date', '>=', wizard.start_date)) - analysis_line_ids = self.pool['hr.payslip.analysis.line'].search( - cr, uid, domain_filters, context=context) + analysis_lines = self.env['hr.payslip.analysis.line'].search( + domain_filters) + analysis_line_ids = analysis_lines.mapped('id') - view_ref = self.pool['ir.model.data'].get_object_reference( - cr, uid, 'hr_payroll_analysis', - 'view_payslip_analysis_line_tree') + view_ref = \ + self.env.ref('hr_payroll_analysis.view_payslip_analysis_line_tree') view_context = {} @@ -174,7 +123,7 @@ def payroll_analysis_open_window(self, cr, uid, ids, context=None): 'search_default_group_salary_rule_id': 1, } - view_id = view_ref and view_ref[1] or False + view_id = view_ref and view_ref.id or False return { 'type': 'ir.actions.act_window', diff --git a/hr_payroll_analysis/wizard/payroll_analysis_view.xml b/hr_payroll_analysis/wizard/payroll_analysis_view.xml index d4a366e3abc..62e5a3dface 100644 --- a/hr_payroll_analysis/wizard/payroll_analysis_view.xml +++ b/hr_payroll_analysis/wizard/payroll_analysis_view.xml @@ -49,7 +49,7 @@ hr.payroll.analysis.form hr.payroll.analysis -
+ - + From d0d0b2811078f4baf25a38cbe1789be52066a868 Mon Sep 17 00:00:00 2001 From: Salton Date: Tue, 6 Oct 2015 20:00:38 +0000 Subject: [PATCH 08/11] [FIX] code improvements and porting tests --- hr_payroll_analysis/models/hr_payslip.py | 21 ++- .../models/hr_payslip_analysis_line.py | 50 ++++-- hr_payroll_analysis/tests/__init__.py | 4 - .../tests/test_payroll_analysis.py | 149 ++++++------------ .../wizard/payroll_analysis.py | 42 +++-- .../wizard/payroll_analysis_view.xml | 6 +- 6 files changed, 118 insertions(+), 154 deletions(-) diff --git a/hr_payroll_analysis/models/hr_payslip.py b/hr_payroll_analysis/models/hr_payslip.py index b29eee66cc6..f284866b205 100644 --- a/hr_payroll_analysis/models/hr_payslip.py +++ b/hr_payroll_analysis/models/hr_payslip.py @@ -5,8 +5,11 @@ class HrPayslip(models.Model): _inherit = 'hr.payslip' - analysis_line_ids = fields.One2many('hr.payslip.analysis.line', - 'payslip_id', 'Analysis Lines') + analysis_line_ids = fields.One2many( + 'hr.payslip.analysis.line', + 'payslip_id', + 'Analysis Lines' + ) @api.multi def process_sheet(self): @@ -22,9 +25,7 @@ def remove_analysis_lines(self): """ Make sure no analysis line has already been computed """ - for payslip in self: - for line in payslip.analysis_line_ids: - line.unlink() + self.mapped('analysis_line_ids').unlink() @api.multi def compute_analysis_lines(self): @@ -32,12 +33,10 @@ def compute_analysis_lines(self): analysis_line_obj = self.env['hr.payslip.analysis.line'] for payslip in self: - - required_lines = [ - line for line in payslip.details_by_salary_rule_category - if line.salary_rule_id.include_in_payroll_analysis and - line.total - ] + required_lines = payslip.details_by_salary_rule_category\ + .filtered( + lambda line: line.salary_rule_id.include_in_payroll_analysis \ + and line.total) is_refund = payslip.credit_note diff --git a/hr_payroll_analysis/models/hr_payslip_analysis_line.py b/hr_payroll_analysis/models/hr_payslip_analysis_line.py index 3ab5e2c8f28..1f082a581ef 100644 --- a/hr_payroll_analysis/models/hr_payslip_analysis_line.py +++ b/hr_payroll_analysis/models/hr_payslip_analysis_line.py @@ -5,15 +5,41 @@ class HrPayslipAnalysisLine(models.Model): _name = 'hr.payslip.analysis.line' - payslip_id = fields.Many2one('hr.payslip', 'Payslip', required=True, - ondelete="cascade",) - payslip_line_id = fields.Many2one('hr.payslip.line', 'Payslip Line', - required=True, ondelete="cascade") - salary_rule_id = fields.Many2one('hr.salary.rule', 'Salary Rule', - required=True, index=True) - company_id = fields.Many2one('res.company', 'Company', required=True, - index=True) - employee_id = fields.Many2one('hr.employee', 'Employee', required=True, - index=True) - date = fields.Date('Date', required=True) - amount= fields.Float('Amount', required=True,) + payslip_id = fields.Many2one( + 'hr.payslip', + 'Payslip', + required=True, + ondelete="cascade", + ) + payslip_line_id = fields.Many2one( + 'hr.payslip.line', + 'Payslip Line', + required=True, + ondelete="cascade" + ) + salary_rule_id = fields.Many2one( + 'hr.salary.rule', + 'Salary Rule', + required=True, + index=True + ) + company_id = fields.Many2one( + 'res.company', + 'Company', + required=True, + index=True + ) + employee_id = fields.Many2one( + 'hr.employee', + 'Employee', + required=True, + index=True + ) + date = fields.Date( + 'Date', + required=True + ) + amount= fields.Float( + 'Amount', + required=True, + ) diff --git a/hr_payroll_analysis/tests/__init__.py b/hr_payroll_analysis/tests/__init__.py index 73b63fcba1d..42b2ca54470 100644 --- a/hr_payroll_analysis/tests/__init__.py +++ b/hr_payroll_analysis/tests/__init__.py @@ -20,7 +20,3 @@ ############################################################################## from . import test_payroll_analysis - -checks = [ - test_payroll_analysis, -] diff --git a/hr_payroll_analysis/tests/test_payroll_analysis.py b/hr_payroll_analysis/tests/test_payroll_analysis.py index b3c9b319a4d..9441a08b049 100644 --- a/hr_payroll_analysis/tests/test_payroll_analysis.py +++ b/hr_payroll_analysis/tests/test_payroll_analysis.py @@ -1,139 +1,105 @@ # -*- coding:utf-8 -*- -############################################################################## -# -# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - from openerp.tests import common class test_payroll_analysis(common.TransactionCase): def get_activity_id(self, job_id): - job = self.job_model.browse( - self.cr, self.uid, job_id, context=self.context) + job = self.job_model.browse(job_id) return job.activity_ids[0].id def setUp(self): super(test_payroll_analysis, self).setUp() - self.user_model = self.registry("res.users") - self.payslip_model = self.registry("hr.payslip") - self.contract_model = self.registry("hr.contract") - self.rule_model = self.registry("hr.salary.rule") - self.rule_category_model = self.registry("hr.salary.rule.category") - self.structure_model = self.registry("hr.payroll.structure") - self.employee_model = self.registry('hr.employee') - self.analysis_line_model = self.registry('hr.payslip.analysis.line') - - self.context = self.user_model.context_get(self.cr, self.uid) - - cr, uid, context = self.cr, self.uid, self.context + self.user_model = self.env["res.users"] + self.payslip_model = self.env["hr.payslip"] + self.contract_model = self.env["hr.contract"] + self.rule_model = self.env["hr.salary.rule"] + self.rule_category_model = self.env["hr.salary.rule.category"] + self.structure_model = self.env["hr.payroll.structure"] + self.employee_model = self.env['hr.employee'] + self.analysis_line_model = self.env['hr.payslip.analysis.line'] # Create an employee - self.employee_id = self.employee_model.create( - cr, uid, { + self.employee = self.employee_model.create({ 'name': 'Employee 1', - }, context=context) + }) # Get any existing category - self.category_id = self.rule_category_model.search( - cr, uid, [], context=context)[0] + self.category = self.rule_category_model.search([])[0] # Create salary rules - self.rule_id = self.rule_model.create( - cr, uid, { + self.rule = self.rule_model.create( + { 'name': 'Test 1', 'sequence': 1, 'code': 'TEST_1', - 'category_id': self.category_id, + 'category_id': self.category.id, 'appears_on_payslip': True, 'active': True, 'amount_select': 'fix', 'amount_fix': 100, 'include_in_payroll_analysis': True, - }, context=context + } ) - self.rule_2_id = self.rule_model.create( - cr, uid, { + self.rule_2 = self.rule_model.create( + { 'name': 'Test 2', 'sequence': 2, 'code': 'TEST_2', - 'category_id': self.category_id, + 'category_id': self.category.id, 'appears_on_payslip': True, 'active': True, 'amount_select': 'fix', 'amount_fix': 200, 'include_in_payroll_analysis': False, - }, context=context + } ) # Create a structure - self.structure_id = self.structure_model.create( - cr, uid, { + self.structure = self.structure_model.create( + { 'name': 'TEST', 'parent_id': False, 'code': 'TEST', - 'rule_ids': [(6, 0, [self.rule_id, self.rule_2_id])] - }, context=context + 'rule_ids': [(6, 0, [self.rule.id, self.rule_2.id])] + } ) # Create a contract for the employee - self.contract_id = self.contract_model.create( - cr, uid, { - 'employee_id': self.employee_id, + self.contract = self.contract_model.create( + { + 'employee_id': self.employee.id, 'name': 'Contract 1', 'wage': 50000, - 'struct_id': self.structure_id, - }, context=context + 'struct_id': self.structure.id, + } ) # Create a payslip - self.payslip_ids = [ + slips = [ self.payslip_model.create( - self.cr, self.uid, { - 'employee_id': self.employee_id, - 'contract_id': self.contract_id, + 'employee_id': self.employee.id, + 'contract_id': self.contract.id, 'date_from': slip[0], 'date_to': slip[1], - 'struct_id': self.structure_id, - }, context=context) + 'struct_id': self.structure.id, + }) for slip in [ ('2014-01-01', '2014-01-31'), ('2014-02-01', '2014-02-28'), ] ] - - self.payslip_model.compute_sheet( - cr, uid, self.payslip_ids, context=context) + slip_ids = [slip.id for slip in slips] + self.payslips = self.payslip_model.browse(slip_ids) + self.payslips.compute_sheet() def process_sheets(self): - cr, uid, context = self.cr, self.uid, self.context - - self.payslip_model.process_sheet( - cr, uid, self.payslip_ids, context=context) + self.payslips.process_sheet() # Check that the analysis lines were created - line_ids = self.analysis_line_model.search( - cr, uid, [('payslip_id', 'in', self.payslip_ids)], - context=context) - - lines = self.analysis_line_model.browse( - cr, uid, line_ids, context=context) + lines = self.analysis_line_model.search( + [('payslip_id', 'in', self.payslips.ids)], + ) self.assertEqual(len(lines), 2) @@ -141,8 +107,6 @@ def process_sheets(self): self.assertEqual(line.amount, 100) def test_payslip_analysis_line_generated(self): - cr, uid, context = self.cr, self.uid, self.context - self.process_sheets() # Process the payslips a second time @@ -152,41 +116,26 @@ def test_payslip_analysis_line_generated(self): # Cancel a payslip and check that there is only one # analysis line left - self.payslip_model.cancel_sheet( - cr, uid, [self.payslip_ids[0]], context=context) - - line_ids = self.analysis_line_model.search( - cr, uid, [('payslip_id', 'in', self.payslip_ids)], - context=context) + self.payslips[0].cancel_sheet() - lines = self.analysis_line_model.browse( - cr, uid, line_ids, context=context) + lines = self.analysis_line_model.search( + [('payslip_id', 'in', self.payslips.ids)]) self.assertEqual(len(lines), 1) - self.assertEqual(lines[0].payslip_id.id, self.payslip_ids[1]) + self.assertEqual(lines[0].payslip_id.id, self.payslips.ids[1]) def test_salary_rule_refresh(self): - cr, uid, context = self.cr, self.uid, self.context - self.process_sheets() # Include the second salary rule in the report - self.rule_model.write( - cr, uid, [self.rule_2_id], - {'include_in_payroll_analysis': True}, context=context) + self.rule_2.write({'include_in_payroll_analysis': True}) # Exclude the first salary rule from the report - self.rule_model.write( - cr, uid, [self.rule_id], - {'include_in_payroll_analysis': False}, context=context) + self.rule.write({'include_in_payroll_analysis': False}) # Check that the proper lines are now computed - line_ids = self.analysis_line_model.search( - cr, uid, [('payslip_id', 'in', self.payslip_ids)], - context=context) - - lines = self.analysis_line_model.browse( - cr, uid, line_ids, context=context) + lines = self.analysis_line_model.search( + [('payslip_id', 'in', self.payslips.ids)]) self.assertEqual(len(lines), 2) diff --git a/hr_payroll_analysis/wizard/payroll_analysis.py b/hr_payroll_analysis/wizard/payroll_analysis.py index f28b39455d9..b78af57f193 100644 --- a/hr_payroll_analysis/wizard/payroll_analysis.py +++ b/hr_payroll_analysis/wizard/payroll_analysis.py @@ -21,7 +21,7 @@ class PayrollAnalysis(models.TransientModel): _name = 'hr.payroll.analysis' _description = 'Payroll Analysis Wizard' - type = fields.Selection( + method = fields.Selection( [ ('employee', 'By Employee'), ('salary_rule', 'By Salary Rule'), @@ -77,48 +77,42 @@ def payroll_analysis_open_window(self): requested in the wizard """ self.ensure_one() - wizard = self[0] - domain_filters = [] - if wizard.salary_rule_ids: - domain_filters.append(('salary_rule_id', 'in', [ - rule.id for rule in wizard.salary_rule_ids])) + if self.salary_rule_ids: + domain_filters.append(('salary_rule_id', 'in', + self.salary_rule_ids.ids)) - if wizard.employee_ids and wizard.type == 'employee': - domain_filters.append(('employee_id', 'in', [ - employee.id for employee in wizard.employee_ids])) + if self.employee_ids and self.method == 'employee': + domain_filters.append(('employee_id', 'in', self.employee_ids.ids)) - if wizard.company_ids and wizard.type == 'company': - domain_filters.append(('company_id', 'in', [ - company.id for company in wizard.company_ids])) + if self.company_ids and self.method == 'company': + domain_filters.append(('company_id', 'in', self.company_ids.ids)) - if wizard.end_date: - domain_filters.append(('date', '<=', wizard.end_date)) + if self.end_date: + domain_filters.append(('date', '<=', self.end_date)) - if wizard.start_date: - domain_filters.append(('date', '>=', wizard.start_date)) + if self.start_date: + domain_filters.append(('date', '>=', self.start_date)) - analysis_lines = self.env['hr.payslip.analysis.line'].search( - domain_filters) - analysis_line_ids = analysis_lines.mapped('id') + analysis_lines = self.env['hr.payslip.analysis.line'].search(domain_filters) + analysis_line_ids = analysis_lines.ids - view_ref = \ - self.env.ref('hr_payroll_analysis.view_payslip_analysis_line_tree') + view_ref = self.env.ref('hr_payroll_analysis.view_payslip_analysis_line_tree') view_context = {} - if wizard.type == 'company': + if self.method == 'company': view_context = { 'search_default_group_company_id': 1, 'search_default_group_salary_rule_id': 1, } - elif wizard.type == 'employee': + elif self.method == 'employee': view_context = { 'search_default_group_employee_id': 1, 'search_default_group_salary_rule_id': 1, } - elif wizard.type == 'salary_rule': + elif self.method == 'salary_rule': view_context = { 'search_default_group_salary_rule_id': 1, } diff --git a/hr_payroll_analysis/wizard/payroll_analysis_view.xml b/hr_payroll_analysis/wizard/payroll_analysis_view.xml index 62e5a3dface..3324f65aa2f 100644 --- a/hr_payroll_analysis/wizard/payroll_analysis_view.xml +++ b/hr_payroll_analysis/wizard/payroll_analysis_view.xml @@ -51,12 +51,12 @@ - + Date: Sat, 10 Oct 2015 15:01:43 +0000 Subject: [PATCH 09/11] restore AGPL license headers --- hr_payroll_analysis/__init__.py | 18 ++++++++++++++++++ hr_payroll_analysis/__openerp__.py | 18 ++++++++++++++++++ hr_payroll_analysis/models/__init__.py | 18 ++++++++++++++++++ hr_payroll_analysis/models/hr_payslip.py | 18 ++++++++++++++++++ .../models/hr_payslip_analysis_line.py | 18 ++++++++++++++++++ hr_payroll_analysis/models/hr_salary_rule.py | 18 ++++++++++++++++++ .../tests/test_payroll_analysis.py | 18 ++++++++++++++++++ hr_payroll_analysis/wizard/__init__.py | 18 ++++++++++++++++++ hr_payroll_analysis/wizard/payroll_analysis.py | 18 ++++++++++++++++++ 9 files changed, 162 insertions(+) diff --git a/hr_payroll_analysis/__init__.py b/hr_payroll_analysis/__init__.py index d5693d0f6e9..ba7c54d9eef 100644 --- a/hr_payroll_analysis/__init__.py +++ b/hr_payroll_analysis/__init__.py @@ -1,3 +1,21 @@ # -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## from . import models from . import wizard \ No newline at end of file diff --git a/hr_payroll_analysis/__openerp__.py b/hr_payroll_analysis/__openerp__.py index e484fe73dbe..abe2b3f0c90 100644 --- a/hr_payroll_analysis/__openerp__.py +++ b/hr_payroll_analysis/__openerp__.py @@ -1,4 +1,22 @@ # -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## { 'name': 'Payroll Analysis', 'version': '1.0', diff --git a/hr_payroll_analysis/models/__init__.py b/hr_payroll_analysis/models/__init__.py index 9c935decea7..37d72e2209c 100644 --- a/hr_payroll_analysis/models/__init__.py +++ b/hr_payroll_analysis/models/__init__.py @@ -1,4 +1,22 @@ # -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## from . import ( hr_payslip, hr_salary_rule, diff --git a/hr_payroll_analysis/models/hr_payslip.py b/hr_payroll_analysis/models/hr_payslip.py index f284866b205..4817e53239a 100644 --- a/hr_payroll_analysis/models/hr_payslip.py +++ b/hr_payroll_analysis/models/hr_payslip.py @@ -1,4 +1,22 @@ # -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## from openerp import models, fields, api diff --git a/hr_payroll_analysis/models/hr_payslip_analysis_line.py b/hr_payroll_analysis/models/hr_payslip_analysis_line.py index 1f082a581ef..b92fec9ec6a 100644 --- a/hr_payroll_analysis/models/hr_payslip_analysis_line.py +++ b/hr_payroll_analysis/models/hr_payslip_analysis_line.py @@ -1,4 +1,22 @@ # -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## from openerp import models, fields, api diff --git a/hr_payroll_analysis/models/hr_salary_rule.py b/hr_payroll_analysis/models/hr_salary_rule.py index 378f47c4c21..fc4c852fe97 100644 --- a/hr_payroll_analysis/models/hr_salary_rule.py +++ b/hr_payroll_analysis/models/hr_salary_rule.py @@ -1,4 +1,22 @@ # -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## from openerp import models, fields, api diff --git a/hr_payroll_analysis/tests/test_payroll_analysis.py b/hr_payroll_analysis/tests/test_payroll_analysis.py index 9441a08b049..854272776bf 100644 --- a/hr_payroll_analysis/tests/test_payroll_analysis.py +++ b/hr_payroll_analysis/tests/test_payroll_analysis.py @@ -1,4 +1,22 @@ # -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## from openerp.tests import common diff --git a/hr_payroll_analysis/wizard/__init__.py b/hr_payroll_analysis/wizard/__init__.py index d64964e4e36..46427b5de1b 100644 --- a/hr_payroll_analysis/wizard/__init__.py +++ b/hr_payroll_analysis/wizard/__init__.py @@ -1,2 +1,20 @@ # -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## from . import payroll_analysis \ No newline at end of file diff --git a/hr_payroll_analysis/wizard/payroll_analysis.py b/hr_payroll_analysis/wizard/payroll_analysis.py index b78af57f193..f5ad71374f7 100644 --- a/hr_payroll_analysis/wizard/payroll_analysis.py +++ b/hr_payroll_analysis/wizard/payroll_analysis.py @@ -1,4 +1,22 @@ # -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## import pytz from datetime import datetime, date From 26a1fbd863fee9a7ee53d046ea83fb5076e2af02 Mon Sep 17 00:00:00 2001 From: Salton Date: Sat, 10 Oct 2015 15:25:50 +0000 Subject: [PATCH 10/11] fix pep8 warnings --- hr_payroll_analysis/__init__.py | 2 +- hr_payroll_analysis/models/hr_payslip.py | 21 +++--- .../models/hr_payslip_analysis_line.py | 66 ++++++++--------- hr_payroll_analysis/models/hr_salary_rule.py | 4 +- .../tests/test_payroll_analysis.py | 12 ++-- hr_payroll_analysis/wizard/__init__.py | 2 +- .../wizard/payroll_analysis.py | 70 +++++++++++++------ 7 files changed, 100 insertions(+), 77 deletions(-) diff --git a/hr_payroll_analysis/__init__.py b/hr_payroll_analysis/__init__.py index ba7c54d9eef..3ea935e6505 100644 --- a/hr_payroll_analysis/__init__.py +++ b/hr_payroll_analysis/__init__.py @@ -18,4 +18,4 @@ # ############################################################################## from . import models -from . import wizard \ No newline at end of file +from . import wizard diff --git a/hr_payroll_analysis/models/hr_payslip.py b/hr_payroll_analysis/models/hr_payslip.py index 4817e53239a..131e4e93c95 100644 --- a/hr_payroll_analysis/models/hr_payslip.py +++ b/hr_payroll_analysis/models/hr_payslip.py @@ -22,12 +22,12 @@ class HrPayslip(models.Model): _inherit = 'hr.payslip' - + analysis_line_ids = fields.One2many( - 'hr.payslip.analysis.line', - 'payslip_id', - 'Analysis Lines' - ) + 'hr.payslip.analysis.line', + 'payslip_id', + 'Analysis Lines' + ) @api.multi def process_sheet(self): @@ -37,23 +37,22 @@ def process_sheet(self): super(HrPayslip, self).process_sheet() self.remove_analysis_lines() self.compute_analysis_lines() - + @api.multi def remove_analysis_lines(self): """ Make sure no analysis line has already been computed """ self.mapped('analysis_line_ids').unlink() - + @api.multi def compute_analysis_lines(self): analysis_line_obj = self.env['hr.payslip.analysis.line'] for payslip in self: - required_lines = payslip.details_by_salary_rule_category\ - .filtered( - lambda line: line.salary_rule_id.include_in_payroll_analysis \ + required_lines = payslip.details_by_salary_rule_category.filtered( + lambda line: line.salary_rule_id.include_in_payroll_analysis and line.total) is_refund = payslip.credit_note @@ -69,7 +68,7 @@ def compute_analysis_lines(self): 'date': payslip.date_from, 'amount': is_refund and -line.total or line.total, }) - + @api.multi def cancel_sheet(self): """ diff --git a/hr_payroll_analysis/models/hr_payslip_analysis_line.py b/hr_payroll_analysis/models/hr_payslip_analysis_line.py index b92fec9ec6a..5f509226e67 100644 --- a/hr_payroll_analysis/models/hr_payslip_analysis_line.py +++ b/hr_payroll_analysis/models/hr_payslip_analysis_line.py @@ -17,47 +17,47 @@ # along with this program. If not, see . # ############################################################################## -from openerp import models, fields, api +from openerp import models, fields class HrPayslipAnalysisLine(models.Model): _name = 'hr.payslip.analysis.line' payslip_id = fields.Many2one( - 'hr.payslip', - 'Payslip', - required=True, - ondelete="cascade", - ) + 'hr.payslip', + 'Payslip', + required=True, + ondelete="cascade", + ) payslip_line_id = fields.Many2one( - 'hr.payslip.line', - 'Payslip Line', - required=True, - ondelete="cascade" - ) + 'hr.payslip.line', + 'Payslip Line', + required=True, + ondelete="cascade" + ) salary_rule_id = fields.Many2one( - 'hr.salary.rule', - 'Salary Rule', - required=True, - index=True - ) + 'hr.salary.rule', + 'Salary Rule', + required=True, + index=True + ) company_id = fields.Many2one( - 'res.company', - 'Company', - required=True, - index=True - ) + 'res.company', + 'Company', + required=True, + index=True + ) employee_id = fields.Many2one( - 'hr.employee', - 'Employee', - required=True, - index=True - ) + 'hr.employee', + 'Employee', + required=True, + index=True + ) date = fields.Date( - 'Date', - required=True - ) - amount= fields.Float( - 'Amount', - required=True, - ) + 'Date', + required=True + ) + amount = fields.Float( + 'Amount', + required=True, + ) diff --git a/hr_payroll_analysis/models/hr_salary_rule.py b/hr_payroll_analysis/models/hr_salary_rule.py index fc4c852fe97..170c9382e97 100644 --- a/hr_payroll_analysis/models/hr_salary_rule.py +++ b/hr_payroll_analysis/models/hr_salary_rule.py @@ -26,7 +26,7 @@ class HrSalaryRule(models.Model): include_in_payroll_analysis = fields.Boolean( 'Include in Payroll Analysis', help="If True, every payslip line related to this salary " - "rule will appear in the payroll analysis report." + "rule will appear in the payroll analysis report." ) @api.multi @@ -47,7 +47,7 @@ def refresh_analysis_lines(self): for rule in self: # Remove existing analysis lines lines = analysis_line_obj.search( - [('salary_rule_id', '=', rule.id)]) + [('salary_rule_id', '=', rule.id)]) lines.unlink() if rule.include_in_payroll_analysis: diff --git a/hr_payroll_analysis/tests/test_payroll_analysis.py b/hr_payroll_analysis/tests/test_payroll_analysis.py index 854272776bf..23d57333ef0 100644 --- a/hr_payroll_analysis/tests/test_payroll_analysis.py +++ b/hr_payroll_analysis/tests/test_payroll_analysis.py @@ -20,13 +20,13 @@ from openerp.tests import common -class test_payroll_analysis(common.TransactionCase): +class TestPayrollAnalysis(common.TransactionCase): def get_activity_id(self, job_id): job = self.job_model.browse(job_id) return job.activity_ids[0].id def setUp(self): - super(test_payroll_analysis, self).setUp() + super(TestPayrollAnalysis, self).setUp() self.user_model = self.env["res.users"] self.payslip_model = self.env["hr.payslip"] self.contract_model = self.env["hr.contract"] @@ -38,8 +38,8 @@ def setUp(self): # Create an employee self.employee = self.employee_model.create({ - 'name': 'Employee 1', - }) + 'name': 'Employee 1', + }) # Get any existing category self.category = self.rule_category_model.search([])[0] @@ -137,7 +137,7 @@ def test_payslip_analysis_line_generated(self): self.payslips[0].cancel_sheet() lines = self.analysis_line_model.search( - [('payslip_id', 'in', self.payslips.ids)]) + [('payslip_id', 'in', self.payslips.ids)]) self.assertEqual(len(lines), 1) self.assertEqual(lines[0].payslip_id.id, self.payslips.ids[1]) @@ -153,7 +153,7 @@ def test_salary_rule_refresh(self): # Check that the proper lines are now computed lines = self.analysis_line_model.search( - [('payslip_id', 'in', self.payslips.ids)]) + [('payslip_id', 'in', self.payslips.ids)]) self.assertEqual(len(lines), 2) diff --git a/hr_payroll_analysis/wizard/__init__.py b/hr_payroll_analysis/wizard/__init__.py index 46427b5de1b..a8e35d93d73 100644 --- a/hr_payroll_analysis/wizard/__init__.py +++ b/hr_payroll_analysis/wizard/__init__.py @@ -17,4 +17,4 @@ # along with this program. If not, see . # ############################################################################## -from . import payroll_analysis \ No newline at end of file +from . import payroll_analysis diff --git a/hr_payroll_analysis/wizard/payroll_analysis.py b/hr_payroll_analysis/wizard/payroll_analysis.py index f5ad71374f7..167110435b8 100644 --- a/hr_payroll_analysis/wizard/payroll_analysis.py +++ b/hr_payroll_analysis/wizard/payroll_analysis.py @@ -44,30 +44,52 @@ class PayrollAnalysis(models.TransientModel): ('employee', 'By Employee'), ('salary_rule', 'By Salary Rule'), ('company', 'By Company'), - ], required=True, string="Analysis Type", default='salary_rule') + ], + required=True, + string="Analysis Type", + default='salary_rule' + ) period = fields.Selection( [ ('current_year', 'Current Year'), ('previous_year', 'Previous Year'), ('every_year', 'Every Year'), - ], string='Analysis Period', default='current_year') - start_date = fields.Datetime('Start Date', + ], + string='Analysis Period', + default='current_year' + ) + start_date = fields.Datetime( + 'Start Date', default=lambda self: ( date(get_current_year(self.env.context), 1, 1).strftime( - DEFAULT_SERVER_DATE_FORMAT))) - end_date = fields.Datetime('End Date', + DEFAULT_SERVER_DATE_FORMAT)) + ) + end_date = fields.Datetime( + 'End Date', default=lambda self: ( date(get_current_year(self.env.context), 12, 31).strftime( - DEFAULT_SERVER_DATE_FORMAT))) - company_ids = fields.Many2many('res.company', - 'payroll_analysis_company_rel', 'payroll_analysis_id', - 'company_id', 'Companies',) - employee_ids = fields.Many2many('hr.employee', - 'payroll_analysis_employee_rel', 'payroll_analysis_id', - 'employee_id', 'Employees',) - salary_rule_ids = fields.Many2many('hr.salary.rule', - 'payroll_analysis_salary_rule_rel', 'payroll_analysis_id', - 'salary_rule_id','Salary Rules',) + DEFAULT_SERVER_DATE_FORMAT)) + ) + company_ids = fields.Many2many( + 'res.company', + 'payroll_analysis_company_rel', + 'payroll_analysis_id', + 'company_id', 'Companies', + ) + employee_ids = fields.Many2many( + 'hr.employee', + 'payroll_analysis_employee_rel', + 'payroll_analysis_id', + 'employee_id', + 'Employees' + ) + salary_rule_ids = fields.Many2many( + 'hr.salary.rule', + 'payroll_analysis_salary_rule_rel', + 'payroll_analysis_id', + 'salary_rule_id', + 'Salary Rules' + ) @api.onchange('period') @api.one @@ -76,18 +98,18 @@ def onchange_period(self): if self.period == 'every_year': self.start_date = False self.end_date = False - + year = get_current_year(self.env.context) - + if self.period == 'previous_year': year -= 1 - + start_date = date(year, 1, 1).strftime(DEFAULT_SERVER_DATE_FORMAT) end_date = date(year, 12, 31).strftime(DEFAULT_SERVER_DATE_FORMAT) - + self.start_date = start_date self.end_date = end_date - + @api.multi def payroll_analysis_open_window(self): """ @@ -98,7 +120,7 @@ def payroll_analysis_open_window(self): domain_filters = [] if self.salary_rule_ids: - domain_filters.append(('salary_rule_id', 'in', + domain_filters.append(('salary_rule_id', 'in', self.salary_rule_ids.ids)) if self.employee_ids and self.method == 'employee': @@ -113,10 +135,12 @@ def payroll_analysis_open_window(self): if self.start_date: domain_filters.append(('date', '>=', self.start_date)) - analysis_lines = self.env['hr.payslip.analysis.line'].search(domain_filters) + analysis_lines = self.env['hr.payslip.analysis.line'].search( + domain_filters) analysis_line_ids = analysis_lines.ids - view_ref = self.env.ref('hr_payroll_analysis.view_payslip_analysis_line_tree') + view_ref = self.env.ref( + 'hr_payroll_analysis.view_payslip_analysis_line_tree') view_context = {} From e594d2ab2fab3ce6c69ef069a9b07928a4f7e1a7 Mon Sep 17 00:00:00 2001 From: Salton Date: Wed, 14 Oct 2015 09:26:31 +0000 Subject: [PATCH 11/11] [FIX] hr_payroll_analysis misleading comment --- hr_payroll_analysis/wizard/payroll_analysis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hr_payroll_analysis/wizard/payroll_analysis.py b/hr_payroll_analysis/wizard/payroll_analysis.py index 167110435b8..1db731818ca 100644 --- a/hr_payroll_analysis/wizard/payroll_analysis.py +++ b/hr_payroll_analysis/wizard/payroll_analysis.py @@ -113,7 +113,7 @@ def onchange_period(self): @api.multi def payroll_analysis_open_window(self): """ - This method returns an action that displays profitability lines + This method returns an action that displays analysis lines requested in the wizard """ self.ensure_one()