diff --git a/hr_leave_accruals/README.rst b/hr_leave_accruals/README.rst new file mode 100644 index 00000000000..53a3218a661 --- /dev/null +++ b/hr_leave_accruals/README.rst @@ -0,0 +1,70 @@ +Leave Accruals +============== + +This module adds leave accruals on employees and a mechanism to compute these +automaticaly. + +The amounts for a leave type can be accruded +in cash, in hours or both. + + +Installation +============ + +Nothing to do except install the module + + +Configuration +============= + + - Go to: Human Ressources -> Configuration -> Leaves Types + - Select a leave type over which you wish to accrued amounts. + - In the form view, go to the "Leave Accruals" tab. + - Select payslip lines over which the leave type will be accruded. + - If a salary rule gives a positive amount and you need to decrease the leave accrual from this amount, + you need to set the field "Substract Amount" True. + +The leave allocation system may be used to increase the hours accruded for a leave type. +For this, the field "Increase Accruals on Allocations" on the leave type must be True. +An example of use for this feature is for sick leaves. + + +Usage +===== + +Compute your payslips and the amounts are automatically accruded in the related employee leave accrual. +In the employee form, there is a tab "Leave Accruals", which shows amounts accruded per leave type. + + +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_leave_accruals/__init__.py b/hr_leave_accruals/__init__.py new file mode 100644 index 00000000000..838096ed5d9 --- /dev/null +++ b/hr_leave_accruals/__init__.py @@ -0,0 +1,30 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2014 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_leave_accrual, + hr_leave_accrual_line, + hr_holidays, + hr_holidays_status, + hr_holidays_status_accrual_line, + hr_payslip, + hr_employee, + res_company, +) diff --git a/hr_leave_accruals/__openerp__.py b/hr_leave_accruals/__openerp__.py new file mode 100644 index 00000000000..c511e062c40 --- /dev/null +++ b/hr_leave_accruals/__openerp__.py @@ -0,0 +1,52 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2014 - 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': 'Leave Accruals', + 'version': '1.0', + 'license': 'AGPL-3', + 'category': 'Generic Modules/Human Resources', + 'description': """ +Leave Accruals +============== +This module adds leave accruals on employees and a mechanism to compute these +automaticaly. + +Contributors +------------ +* David Dufresne +* Pierre Lamarche +""", + 'author': 'Savoir-faire Linux', + 'website': 'https://www.savoirfairelinux.com/', + 'depends': [ + 'hr_payroll', + ], + 'data': [ + 'security/ir.model.access.csv', + 'view/hr_employee_view.xml', + 'view/hr_leave_accrual_view.xml', + 'view/hr_holidays_status_view.xml', + 'view/res_company_view.xml', + ], + 'test': ['test/hr_leave_accruals_test.yml'], + 'demo': [], + 'installable': True, +} diff --git a/hr_leave_accruals/hr_employee.py b/hr_leave_accruals/hr_employee.py new file mode 100644 index 00000000000..daf06252cdc --- /dev/null +++ b/hr_leave_accruals/hr_employee.py @@ -0,0 +1,68 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2014 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_employee(orm.Model): + _name = 'hr.employee' + _inherit = 'hr.employee' + _columns = { + 'leave_accrual_ids': fields.one2many( + 'hr.leave.accrual', + 'employee_id', + 'Leave Accruals', + ), + } + + def get_leave_accrual_id( + self, cr, uid, employee_id, accrual_code=False, + leave_type_id=False, context=None + ): + """ + Get a leave accrual of an employee that matches a leave_code + :return: the id of a leave accrual + """ + employee = self.browse(cr, uid, employee_id, context=context) + + accrual_id = False + + for accrual in employee.leave_accrual_ids: + if accrual_code and accrual.code == accrual_code \ + or leave_type_id == accrual.leave_type_id.id: + accrual_id = accrual.id + break + + # If the employee doesn't have the accrual of the given type, + # create it + if not accrual_id: + if accrual_code: + leave_type_id = self.pool['hr.holidays.status'].search( + cr, uid, [('accrual_code', '=', accrual_code)], + context=context)[0] + + accrual_id = self.pool['hr.leave.accrual'].create( + cr, uid, { + 'employee_id': employee_id, + 'leave_type_id': leave_type_id, + }, context=context) + + return accrual_id diff --git a/hr_leave_accruals/hr_holidays.py b/hr_leave_accruals/hr_holidays.py new file mode 100644 index 00000000000..66c82f74179 --- /dev/null +++ b/hr_leave_accruals/hr_holidays.py @@ -0,0 +1,88 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2014 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 +from openerp.tools import DEFAULT_SERVER_DATE_FORMAT +from datetime import datetime + + +class hr_holidays(orm.Model): + _inherit = 'hr.holidays' + + _columns = { + 'accrual_line_id': fields.one2many( + 'hr.leave.accrual.line', + 'allocation_id', + string="Leave Accrual Line", + ), + } + + def holidays_validate(self, cr, uid, ids, context=None): + """ + After an allocation of holidays is validated, + add hours to the related leave accrual of the employee + """ + res = super(hr_holidays, self).holidays_validate( + cr, uid, ids, context=context) + + for leave in self.browse(cr, uid, ids, context=context): + if leave.type == 'add' and leave.holiday_type == 'employee' \ + and leave.holiday_status_id.increase_accrual_on_allocation: + + employee = leave.employee_id + leave_type_id = leave.holiday_status_id.id + + accrual_id = self.pool['hr.employee'].get_leave_accrual_id( + cr, uid, employee.id, leave_type_id=leave_type_id, + context=context) + + number_of_hours = leave.number_of_days_temp * \ + employee.company_id.holidays_hours_per_day + + for line in leave.accrual_line_id: + line.unlink() + + leave.write({ + 'accrual_line_id': [(0, 0, { + 'source': 'allocation', + 'amount': number_of_hours, + 'accrual_id': accrual_id, + 'date': datetime.now().strftime( + DEFAULT_SERVER_DATE_FORMAT), + 'description': leave.name, + 'amount_type': 'hours', + })]}) + + return res + + def holidays_refuse(self, cr, uid, ids, context=None): + """ + After an allocation of holidays is refused, + remove the leave accrual line related + """ + res = super(hr_holidays, self).holidays_refuse( + cr, uid, ids, context=context) + + for leave in self.browse(cr, uid, ids, context=context): + for line in leave.accrual_line_id: + line.unlink() + + return res diff --git a/hr_leave_accruals/hr_holidays_status.py b/hr_leave_accruals/hr_holidays_status.py new file mode 100644 index 00000000000..65703a7e17e --- /dev/null +++ b/hr_leave_accruals/hr_holidays_status.py @@ -0,0 +1,42 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2014 - 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_holidays_status(orm.Model): + _inherit = 'hr.holidays.status' + + _columns = { + 'accrual_code': fields.char( + 'Accrual Code', + ), + 'increase_accrual_on_allocation': fields.boolean( + 'Increase Accruals on Allocations', + help="Add hours to the related leave accruals when allocating " + "leaves to employees." + ), + 'accrual_line_ids': fields.one2many( + 'hr.holidays.status.accrual.line', + 'leave_type_id', + 'Accrual Lines', + ), + } diff --git a/hr_leave_accruals/hr_holidays_status_accrual_line.py b/hr_leave_accruals/hr_holidays_status_accrual_line.py new file mode 100644 index 00000000000..f1acb0a43e3 --- /dev/null +++ b/hr_leave_accruals/hr_holidays_status_accrual_line.py @@ -0,0 +1,65 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2014 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 +from openerp.tools.translate import _ + + +def get_amount_types(self, cr, uid, context=None): + return [ + ('cash', _('Cash')), + ('hours', _('Hours')), + ] + + +class hr_holidays_status_accrual_line(orm.Model): + """ + The lines that will be added to an employee's leave accrual + when a payslip is computed + + If substract field is True, the amount related to the salary rule + will be substracted from the accrual instead of added to it. + """ + _name = 'hr.holidays.status.accrual.line' + _description = 'Holidays Status Accrual Line' + _columns = { + 'leave_type_id': fields.many2one( + 'hr.holidays.status', + 'Leave Type', + required=True, + ), + 'salary_rule_id': fields.many2one( + 'hr.salary.rule', + 'Salary Rule', + ), + 'substract': fields.boolean( + 'Substract Amount', + ), + 'amount_type': fields.selection( + get_amount_types, + string="Amount Type", + ), + } + + _defaults = { + 'substract': False, + 'amount_type': 'cash', + } diff --git a/hr_leave_accruals/hr_leave_accrual.py b/hr_leave_accruals/hr_leave_accrual.py new file mode 100644 index 00000000000..dfa813edde5 --- /dev/null +++ b/hr_leave_accruals/hr_leave_accrual.py @@ -0,0 +1,132 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2014 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_leave_accrual(orm.Model): + """ + A leave accrual of an employee + """ + _name = 'hr.leave.accrual' + _description = 'Employee Leave Accrual' + + def _get_approved_lines( + self, cr, uid, ids, context=None + ): + """ + Get lines of leave accruals entered mannually plus those + related to an approved payslip + + return: a dict that contains a list of accrual line objects + for each accrual id + """ + result = {} + if not ids: + return result + + if isinstance(ids, (int, long)): + ids = [ids] + + accruals = self.browse(cr, uid, ids, context=context) + + return { + accrual.id: [ + line for line in accrual.line_ids + # Lines entered manually or from approved payslip + if not line.payslip_id or line.state in ['done'] + ] + for accrual in accruals + } + + def _sum_lines( + self, cr, uid, ids, field_names, arg=None, context=None + ): + """ + Get the actual total of the leave acruals refered by ids + """ + approved_lines = self._get_approved_lines( + cr, uid, ids, context=context + ) + + res = {} + + for accrual_id in approved_lines: + total_hours = 0 + total_cash = 0 + lines = approved_lines[accrual_id] + + for line in lines: + if line.is_refund: + if line.amount_type == 'cash': + total_cash -= line.amount + elif line.amount_type == 'hours': + total_hours -= line.amount + else: + if line.amount_type == 'cash': + total_cash += line.amount + elif line.amount_type == 'hours': + total_hours += line.amount + + res[accrual_id] = { + 'total_cash': total_cash, + 'total_hours': total_hours, + } + + return res + + _columns = { + 'leave_type_id': fields.many2one( + 'hr.holidays.status', + string='Leave Type', + ondelete='cascade', + ), + 'code': fields.related( + 'leave_type_id', + 'accrual_code', + type="char", + ), + 'employee_id': fields.many2one( + 'hr.employee', + 'Employee', + required=True, + ondelete='cascade', + ), + 'line_ids': fields.one2many( + 'hr.leave.accrual.line', + 'accrual_id', + string='Accrual Lines', + ), + 'total_cash': fields.function( + _sum_lines, + method=True, + type="float", + string='Cash Accruded', + multi=True, + ), + 'total_hours': fields.function( + _sum_lines, + method=True, + type="float", + multi=True, + string='Hours Accruded', + ), + } diff --git a/hr_leave_accruals/hr_leave_accrual_line.py b/hr_leave_accruals/hr_leave_accrual_line.py new file mode 100644 index 00000000000..915b73d30e4 --- /dev/null +++ b/hr_leave_accruals/hr_leave_accrual_line.py @@ -0,0 +1,105 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2014 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 +from .hr_holidays_status_accrual_line import get_amount_types + + +class hr_leave_accrual_line(orm.Model): + """ + There are two types of leave accrual lines for now. + - Those entered manually + - Those related to a payslip + + If it is related to a payslip, the payslip needs to be approved + for the line to be included in the accrual's total. + """ + _name = 'hr.leave.accrual.line' + _description = 'Leave Accrual Line' + _columns = { + # Mandatory fields + 'accrual_id': fields.many2one( + 'hr.leave.accrual', + 'Leave Accrual', + ondelete='cascade', + required=True, + ), + 'amount': fields.float( + 'Amount', + required=True, + ), + 'source': fields.selection( + [ + ('payslip', 'Payslip Line'), + ('allocation', 'Allocation'), + ('manual', 'Entered Manually'), + ], + type='char', + string="Source", + required=True, + ), + 'amount_type': fields.selection( + get_amount_types, + string="Amount Type", + ), + + # Fields required when line is an allocation + 'allocation_id': fields.many2one( + 'hr.holidays', + 'Allocation', + ondelete='cascade', + ), + + # Fields required when line is related to a payslip line + 'payslip_id': fields.many2one( + 'hr.payslip', + 'Payslip', + ondelete='cascade', + ), + 'payslip_line_id': fields.many2one( + 'hr.payslip.line', + 'Payslip Line', + ondelete='cascade', + ), + 'state': fields.related( + 'payslip_id', + 'state', + type="char", + string="State" + ), + 'is_refund': fields.boolean( + 'Is Refund', + ), + + # Fields required when the line is entered manually + 'date': fields.date( + 'Date', + ), + 'description': fields.char( + 'Description', + ) + } + _defaults = { + 'payslip_id': False, + 'payslip_line_id': False, + 'source': 'manual', + 'amount_type': 'cash', + } diff --git a/hr_leave_accruals/hr_payslip.py b/hr_leave_accruals/hr_payslip.py new file mode 100644 index 00000000000..561dbda316e --- /dev/null +++ b/hr_leave_accruals/hr_payslip.py @@ -0,0 +1,131 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2014 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): + _name = 'hr.payslip' + _inherit = 'hr.payslip' + _columns = { + 'leave_accrual_line_ids': fields.one2many( + 'hr.leave.accrual.line', + 'payslip_id', + 'Leave Accrual Lines', + ), + } + + def compute_sheet(self, cr, uid, ids, context=None): + super(hr_payslip, self).compute_sheet( + cr, uid, ids, context=context + ) + self.compute_leave_accrual_lines(cr, uid, ids, context=context) + + def compute_leave_accrual_lines(self, cr, uid, ids, context=None): + """ + Update an employee's leave accruals with the amounts computed in the + payslip. + """ + for payslip in self.browse(cr, uid, ids, context=context): + # Get the required leave accruals + salary_rule_ids = [ + line.salary_rule_id.id for line + in payslip.details_by_salary_rule_category] + + line_obj = self.pool['hr.holidays.status.accrual.line'] + + leave_accrual_line_ids = line_obj.search( + cr, uid, [('salary_rule_id', 'in', salary_rule_ids)], + context=context) + + leave_accrual_lines = line_obj.browse( + cr, uid, leave_accrual_line_ids, context=context) + + leave_types_required = { + line.leave_type_id for line in leave_accrual_lines} + + # Check if employee has every required leave accruals + # If it does not exist, create it + accrual_obj = self.pool['hr.leave.accrual'] + for leave_type in leave_types_required: + if not accrual_obj.search(cr, uid, [ + ('employee_id', '=', payslip.employee_id.id), + ('leave_type_id', '=', leave_type.id), + ], context=context): + accrual_obj.create(cr, uid, { + 'employee_id': payslip.employee_id.id, + 'leave_type_id': leave_type.id, + }, context=context) + + # Get the set of codes needed from the the register templates + accruals = payslip.employee_id.leave_accrual_ids + + # Retreive all lines from the leave types + # This allows to know witch payslip lines are used to update the + # leave accrual. + required_rules = [ + line.salary_rule_id.id for line in leave_accrual_lines] + + # Create a dict to access the required payslip lines by rule id. + # This is a matter of performance because we iterate + # only one time over each payslip line + payslip_line_dict = { + line.salary_rule_id.id: line + for line in payslip.details_by_salary_rule_category + if line.salary_rule_id.id in required_rules + } + + # Create a list of new register line records + accrual_lines = [] + for accrual in accruals: + # For each line in the accrual's leave_type, + # Add a line in the accrual related to a payslip line. + for line in accrual.leave_type_id.accrual_line_ids: + salary_rule_id = line.salary_rule_id.id + + if( + # Check if the rule is in the payslip + salary_rule_id in payslip_line_dict + ): + # Get the payslip line related to the template line + payslip_line = payslip_line_dict[salary_rule_id] + + amount = line.substract and payslip_line.amount * -1 \ + or payslip_line.amount + + if payslip_line.amount != 0: + accrual_lines.append((0, 0, { + 'source': 'payslip', + 'payslip_id': payslip.id, + 'payslip_line_id': payslip_line.id, + 'amount': amount, + 'accrual_id': accrual.id, + 'is_refund': payslip.credit_note, + 'amount_type': line.amount_type, + })) + + # Write the resulting records + self.write( + cr, uid, + [payslip.id], + {'leave_accrual_line_ids': accrual_lines}, + context=context + ) diff --git a/hr_leave_accruals/i18n/fr.po b/hr_leave_accruals/i18n/fr.po new file mode 100644 index 00000000000..1f37bef7914 --- /dev/null +++ b/hr_leave_accruals/i18n/fr.po @@ -0,0 +1,215 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * hr_leave_accruals +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 7.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-02-07 15:33+0000\n" +"PO-Revision-Date: 2015-02-07 10:35-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_leave_accruals +#: model:ir.model,name:hr_leave_accruals.model_hr_holidays_status_accrual_line +#, fuzzy +msgid "Holidays Status Accrual Line" +msgstr "Ligne de banque de temps" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual.line,source:0 +msgid "Source" +msgstr "Source" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual.line,state:0 +msgid "State" +msgstr "État" + +#. module: hr_leave_accruals +#: field:hr.holidays,accrual_line_id:0 +#: model:ir.model,name:hr_leave_accruals.model_hr_leave_accrual_line +msgid "Leave Accrual Line" +msgstr "Ligne de banque de temps" + +#. module: hr_leave_accruals +#: field:hr.holidays.status,accrual_line_ids:0 +#: field:hr.leave.accrual,line_ids:0 +msgid "Accrual Lines" +msgstr "Lignes de banque de temps" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual,employee_id:0 +#: model:ir.model,name:hr_leave_accruals.model_hr_employee +msgid "Employee" +msgstr "Employé" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual.line,allocation_id:0 +#: selection:hr.leave.accrual.line,source:0 +msgid "Allocation" +msgstr "Allocation" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual.line,description:0 +msgid "Description" +msgstr "Description" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual,code:0 +msgid "unknown" +msgstr "inconnu" + +#. module: hr_leave_accruals +#: view:hr.holidays.status:0 +msgid "Payslip Lines" +msgstr "Lignes de bulletin de paie" + +#. module: hr_leave_accruals +#: view:res.company:0 +msgid "Holidays" +msgstr "Congés" + +#. module: hr_leave_accruals +#: code:addons/hr_leave_accruals/hr_holidays_status_accrual_line.py:29 +#, python-format +msgid "Hours" +msgstr "Heures" + +#. module: hr_leave_accruals +#: field:hr.holidays.status,accrual_code:0 +msgid "Accrual Code" +msgstr "Code de banque de temps" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual.line,date:0 +msgid "Date" +msgstr "Date" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual,total_cash:0 +msgid "Cash Accruded" +msgstr "Liquidités Accumulées" + +#. module: hr_leave_accruals +#: view:hr.leave.accrual:0 field:hr.leave.accrual.line,accrual_id:0 +msgid "Leave Accrual" +msgstr "Banque de temps" + +#. module: hr_leave_accruals +#: model:ir.model,name:hr_leave_accruals.model_hr_payslip +msgid "Pay Slip" +msgstr "Bulletin de paie" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual.line,payslip_line_id:0 +#: selection:hr.leave.accrual.line,source:0 +msgid "Payslip Line" +msgstr "Ligne de bulletin de paie" + +#. module: hr_leave_accruals +#: selection:hr.leave.accrual.line,source:0 +msgid "Entered Manually" +msgstr "Entrée manuellement" + +#. module: hr_leave_accruals +#: help:hr.holidays.status,increase_accrual_on_allocation:0 +msgid "" +"Add hours to the related leave accruals when allocating leaves to employees." +msgstr "" +"Ajouter des heures aux banques de temps lors des allocations de congés aux " +"employés." + +#. module: hr_leave_accruals +#: model:ir.model,name:hr_leave_accruals.model_res_company +msgid "Companies" +msgstr "Sociétés" + +#. module: hr_leave_accruals +#: code:addons/hr_leave_accruals/hr_holidays_status_accrual_line.py:28 +#, python-format +msgid "Cash" +msgstr "Argent" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual.line,payslip_id:0 +msgid "Payslip" +msgstr "Bulletin de paie" + +#. module: hr_leave_accruals +#: model:ir.model,name:hr_leave_accruals.model_hr_leave_accrual +msgid "Employee Leave Accrual" +msgstr "Banque de temps d'un employé" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual.line,amount:0 +msgid "Amount" +msgstr "Montant" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual,total_hours:0 +msgid "Hours Accruded" +msgstr "Heures Accumulées" + +#. module: hr_leave_accruals +#: field:res.company,holidays_hours_per_day:0 +msgid "Number of Hours per Leave Day" +msgstr "Nombre d'heures par jour de congé" + +#. module: hr_leave_accruals +#: field:hr.holidays.status.accrual.line,substract:0 +msgid "Substract Amount" +msgstr "Soustraire le montant" + +#. module: hr_leave_accruals +#: view:hr.employee:0 field:hr.employee,leave_accrual_ids:0 +#: view:hr.holidays.status:0 +msgid "Leave Accruals" +msgstr "Banque de temps" + +#. module: hr_leave_accruals +#: model:ir.model,name:hr_leave_accruals.model_hr_holidays +msgid "Leave" +msgstr "Congé" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual.line,is_refund:0 +msgid "Is Refund" +msgstr "Avoir" + +#. module: hr_leave_accruals +#: field:hr.holidays.status,increase_accrual_on_allocation:0 +msgid "Increase Accruals on Allocations" +msgstr "Augmenter les banques de temps par allocation" + +#. module: hr_leave_accruals +#: view:hr.leave.accrual:0 field:hr.payslip,leave_accrual_line_ids:0 +msgid "Leave Accrual Lines" +msgstr "Lignes de banque de temps" + +#. module: hr_leave_accruals +#: field:hr.holidays.status.accrual.line,leave_type_id:0 +#: field:hr.leave.accrual,leave_type_id:0 +#: model:ir.model,name:hr_leave_accruals.model_hr_holidays_status +msgid "Leave Type" +msgstr "Type de congé" + +#. module: hr_leave_accruals +#: field:hr.holidays.status.accrual.line,salary_rule_id:0 +msgid "Salary Rule" +msgstr "Règle de salaire" + +#. module: hr_leave_accruals +#: field:hr.holidays.status.accrual.line,amount_type:0 +#: field:hr.leave.accrual.line,amount_type:0 +msgid "Amount Type" +msgstr "Type de montant" + +#~ msgid "Total" +#~ msgstr "Total" diff --git a/hr_leave_accruals/i18n/hr_leave_accruals.pot b/hr_leave_accruals/i18n/hr_leave_accruals.pot new file mode 100644 index 00000000000..b8a261a0e17 --- /dev/null +++ b/hr_leave_accruals/i18n/hr_leave_accruals.pot @@ -0,0 +1,211 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * hr_leave_accruals +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 7.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-02-07 15:33+0000\n" +"PO-Revision-Date: 2015-02-07 15:33+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_leave_accruals +#: model:ir.model,name:hr_leave_accruals.model_hr_holidays_status_accrual_line +msgid "Holidays Status Accrual Line" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual.line,source:0 +msgid "Source" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual.line,state:0 +msgid "State" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.holidays,accrual_line_id:0 +#: model:ir.model,name:hr_leave_accruals.model_hr_leave_accrual_line +msgid "Leave Accrual Line" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.holidays.status,accrual_line_ids:0 +#: field:hr.leave.accrual,line_ids:0 +msgid "Accrual Lines" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual,employee_id:0 +#: model:ir.model,name:hr_leave_accruals.model_hr_employee +msgid "Employee" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual.line,allocation_id:0 +#: selection:hr.leave.accrual.line,source:0 +msgid "Allocation" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual.line,description:0 +msgid "Description" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual,code:0 +msgid "unknown" +msgstr "" + +#. module: hr_leave_accruals +#: view:hr.holidays.status:0 +msgid "Payslip Lines" +msgstr "" + +#. module: hr_leave_accruals +#: view:res.company:0 +msgid "Holidays" +msgstr "" + +#. module: hr_leave_accruals +#: code:addons/hr_leave_accruals/hr_holidays_status_accrual_line.py:29 +#, python-format +msgid "Hours" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.holidays.status,accrual_code:0 +msgid "Accrual Code" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual.line,date:0 +msgid "Date" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual,total_cash:0 +msgid "Cash Accruded" +msgstr "" + +#. module: hr_leave_accruals +#: view:hr.leave.accrual:0 +#: field:hr.leave.accrual.line,accrual_id:0 +msgid "Leave Accrual" +msgstr "" + +#. module: hr_leave_accruals +#: model:ir.model,name:hr_leave_accruals.model_hr_payslip +msgid "Pay Slip" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual.line,payslip_line_id:0 +#: selection:hr.leave.accrual.line,source:0 +msgid "Payslip Line" +msgstr "" + +#. module: hr_leave_accruals +#: selection:hr.leave.accrual.line,source:0 +msgid "Entered Manually" +msgstr "" + +#. module: hr_leave_accruals +#: help:hr.holidays.status,increase_accrual_on_allocation:0 +msgid "Add hours to the related leave accruals when allocating leaves to employees." +msgstr "" + +#. module: hr_leave_accruals +#: model:ir.model,name:hr_leave_accruals.model_res_company +msgid "Companies" +msgstr "" + +#. module: hr_leave_accruals +#: code:addons/hr_leave_accruals/hr_holidays_status_accrual_line.py:28 +#, python-format +msgid "Cash" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual.line,payslip_id:0 +msgid "Payslip" +msgstr "" + +#. module: hr_leave_accruals +#: model:ir.model,name:hr_leave_accruals.model_hr_leave_accrual +msgid "Employee Leave Accrual" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual.line,amount:0 +msgid "Amount" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual,total_hours:0 +msgid "Hours Accruded" +msgstr "" + +#. module: hr_leave_accruals +#: field:res.company,holidays_hours_per_day:0 +msgid "Number of Hours per Leave Day" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.holidays.status.accrual.line,substract:0 +msgid "Substract Amount" +msgstr "" + +#. module: hr_leave_accruals +#: view:hr.employee:0 +#: field:hr.employee,leave_accrual_ids:0 +#: view:hr.holidays.status:0 +msgid "Leave Accruals" +msgstr "" + +#. module: hr_leave_accruals +#: model:ir.model,name:hr_leave_accruals.model_hr_holidays +msgid "Leave" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.leave.accrual.line,is_refund:0 +msgid "Is Refund" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.holidays.status,increase_accrual_on_allocation:0 +msgid "Increase Accruals on Allocations" +msgstr "" + +#. module: hr_leave_accruals +#: view:hr.leave.accrual:0 +#: field:hr.payslip,leave_accrual_line_ids:0 +msgid "Leave Accrual Lines" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.holidays.status.accrual.line,leave_type_id:0 +#: field:hr.leave.accrual,leave_type_id:0 +#: model:ir.model,name:hr_leave_accruals.model_hr_holidays_status +msgid "Leave Type" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.holidays.status.accrual.line,salary_rule_id:0 +msgid "Salary Rule" +msgstr "" + +#. module: hr_leave_accruals +#: field:hr.holidays.status.accrual.line,amount_type:0 +#: field:hr.leave.accrual.line,amount_type:0 +msgid "Amount Type" +msgstr "" + diff --git a/hr_leave_accruals/res_company.py b/hr_leave_accruals/res_company.py new file mode 100644 index 00000000000..3ebd346f36a --- /dev/null +++ b/hr_leave_accruals/res_company.py @@ -0,0 +1,37 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2014 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 fields, orm + + +class res_company(orm.Model): + _inherit = 'res.company' + _columns = { + 'holidays_hours_per_day': fields.float( + 'Number of Hours per Leave Day', + digits=(2, 2), + required=True, + ), + } + + _default = { + 'holidays_hours_per_day': 8.0, + } diff --git a/hr_leave_accruals/security/ir.model.access.csv b/hr_leave_accruals/security/ir.model.access.csv new file mode 100644 index 00000000000..23d3ac2103d --- /dev/null +++ b/hr_leave_accruals/security/ir.model.access.csv @@ -0,0 +1,4 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_hr_leave_accrual,hr.leave.accrual,model_hr_leave_accrual,base.group_hr_manager,1,1,1,1 +access_hr_leave_accrual_line,hr.leave.accrual.line,model_hr_leave_accrual_line,base.group_hr_manager,1,1,1,1 +access_hr_holidays_status_accrual_line,hr.holidays.status.accrual.line,model_hr_holidays_status_accrual_line,base.group_hr_manager,1,1,1,1 \ No newline at end of file diff --git a/hr_leave_accruals/static/src/img/icon.png b/hr_leave_accruals/static/src/img/icon.png new file mode 100644 index 00000000000..297dc71c85c Binary files /dev/null and b/hr_leave_accruals/static/src/img/icon.png differ diff --git a/hr_leave_accruals/test/hr_leave_accruals_test.yml b/hr_leave_accruals/test/hr_leave_accruals_test.yml new file mode 100644 index 00000000000..1b815e849d3 --- /dev/null +++ b/hr_leave_accruals/test/hr_leave_accruals_test.yml @@ -0,0 +1,162 @@ +- + First we create a user +- + !record {model: res.users, id: user_1}: + name: User 1 + login: test + password: test +- + Create an employee +- + !record {model: hr.employee, id: employee_1}: + name: Employee 1 + user_id: user_1 +- + Create a leave type +- + !record {model: hr.holidays.status, id: vacations}: + name: "Vacations" +- + Create a salary rule for vacations earned +- + !record {model: hr.salary.rule, id: vac_added}: + name: Vacations + sequence: 1 + code: "VAC_ADDED" + category_id: hr_payroll.GROSS + amount_select: "fix" + amount_fix: 500 +- + Create a salary rule for vacations taken +- + !record {model: hr.salary.rule, id: vac_taken}: + name: Vacations + sequence: 1 + code: "VAC_TAKEN" + category_id: hr_payroll.GROSS + amount_select: "fix" + amount_fix: 300 +- + Create a leave accrual line for amounts added +- + !record {model: hr.holidays.status.accrual.line, id: vac_line_1}: + leave_type_id: vacations + substract: False + salary_rule_id: vac_added + amount_type: cash +- + Create a leave accrual line for amounts substracted +- + !record {model: hr.holidays.status.accrual.line, id: vac_line_2}: + leave_type_id: vacations + substract: True + salary_rule_id: vac_taken + amount_type: cash +- + Create a leave accrual for the employee +- + !record {model: hr.leave.accrual, id: leave_accrual_1}: + leave_type_id: vacations + employee_id: employee_1 +- + Create a salary structure +- + !record {model: hr.payroll.structure, id: structure_1}: + code: 'VAC' + name: 'Vacation' + parent_id: False + rule_ids: + - vac_added + - vac_taken +- + Create a contract +- + !record {model: hr.contract, id: contract_1}: + name: Contract 1 + employee_id: employee_1 + wage: 50000 + struct_id: structure_1 +- + Create a payslip +- + !record {model: hr.payslip, id: payslip_1}: + employee_id: employee_1 + contract_id: contract_1 + date_from: '2014-01-01' + date_to: '2014-01-31' + struct_id: structure_1 +- + Compute the payslip +- + !python {model: hr.payslip}: | + self.compute_sheet(cr, uid, [ref('payslip_1')]) + self.write(cr, uid, [ref('payslip_1')], {'state': 'done'}) +- + Check if leave accrual lines were generated +- + !python {model: hr.leave.accrual}: | + leave_accrual = self.browse(cr, uid, ref('leave_accrual_1')) + # the total in leave accrual must be 200 + # 500 added - 300 taken + assert(leave_accrual.total_cash == 200) +- + Compute the payslip a second time +- + !python {model: hr.payslip}: | + self.compute_sheet(cr, uid, [ref('payslip_1')]) +- + Check if leave accrual changed +- + !python {model: hr.leave.accrual}: | + leave_accrual = self.browse(cr, uid, ref('leave_accrual_1')) + # Total still equals 200 because the same payslip + # was recomputed + assert(leave_accrual.total_cash == 200) +- + Create a second payslip +- + !record {model: hr.payslip, id: payslip_2}: + employee_id: employee_1 + contract_id: contract_1 + date_from: '2014-02-01' + date_to: '2014-02-28' + struct_id: structure_1 +- + Compute the payslip +- + !python {model: hr.payslip}: | + self.compute_sheet(cr, uid, [ref('payslip_2')]) + self.write(cr, uid, [ref('payslip_2')], {'state': 'done'}) +- + Check if leave accrual lines were generated +- + !python {model: hr.leave.accrual}: | + leave_accrual = self.browse(cr, uid, ref('leave_accrual_1')) + # the total in leave accrual must be 400 + # 500 added - 300 taken + 500 added - 300 taken + assert(leave_accrual.total_cash == 400) + +- + Create a refund payslip +- + !record {model: hr.payslip, id: payslip_3}: + employee_id: employee_1 + contract_id: contract_1 + date_from: '2014-02-01' + date_to: '2014-02-28' + struct_id: structure_1 + credit_note: True +- + Compute the payslip +- + !python {model: hr.payslip}: | + self.compute_sheet(cr, uid, [ref('payslip_3')]) + self.write(cr, uid, [ref('payslip_3')], {'state': 'done'}) +- + Check if leave accrual lines were generated +- + !python {model: hr.leave.accrual}: | + leave_accrual = self.browse(cr, uid, ref('leave_accrual_1')) + # the total in leave accrual must be 200 (400 - 200) + # because the last payslip is refund + assert(leave_accrual.total_cash == 200) diff --git a/hr_leave_accruals/view/hr_employee_view.xml b/hr_leave_accruals/view/hr_employee_view.xml new file mode 100644 index 00000000000..fa93a10b0e0 --- /dev/null +++ b/hr_leave_accruals/view/hr_employee_view.xml @@ -0,0 +1,23 @@ + + + + + hr.employee.form + hr.employee + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hr_leave_accruals/view/hr_holidays_status_view.xml b/hr_leave_accruals/view/hr_holidays_status_view.xml new file mode 100644 index 00000000000..2e15e3b4f8d --- /dev/null +++ b/hr_leave_accruals/view/hr_holidays_status_view.xml @@ -0,0 +1,28 @@ + + + + + hr.holidays.status.form + hr.holidays.status + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hr_leave_accruals/view/hr_leave_accrual_view.xml b/hr_leave_accruals/view/hr_leave_accrual_view.xml new file mode 100644 index 00000000000..61ee2e5cacf --- /dev/null +++ b/hr_leave_accruals/view/hr_leave_accrual_view.xml @@ -0,0 +1,38 @@ + + + + + hr.leave.accrual.form + hr.leave.accrual + +
+ + + + +
+
+
diff --git a/hr_leave_accruals/view/res_company_view.xml b/hr_leave_accruals/view/res_company_view.xml new file mode 100644 index 00000000000..c56cd48a654 --- /dev/null +++ b/hr_leave_accruals/view/res_company_view.xml @@ -0,0 +1,17 @@ + + + + + res.company.form + res.company + + + + + + + + + + + \ No newline at end of file