Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ADD][9.0] hr expense operating unit #30

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions hr_expense_operating_unit/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
.. image:: https://img.shields.io/badge/license-LGPLv3-blue.svg
:target: https://www.gnu.org/licenses/lgpl.html
:alt: License: LGPL-3

===============================
HR Expense with Operating Units
===============================

This module introduces the following features:

* Adds the Operating Unit (OU) to the Expense.

* Security rules are defined to ensure that users can only see the Expense of that Operating Units in which they are allowed access to.

* Adds Operating Unit (OU) to the account moves while generating accounting entries from the expense.

Usage
=====

.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/213/9.0

Bug Tracker
===========

Bugs are tracked on `GitHub Issues
<https://github.com/OCA/operating-unit/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smashing it by providing a detailed and welcomed feedback.

Credits
=======

Images
------

* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.

Contributors
------------

* Eficent Business and IT Consulting Services S.L. <contact@eficent.com>
* Serpent Consulting Services Pvt. Ltd. <support@serpentcs.com>

Maintainer
----------

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://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 https://odoo-community.org.
7 changes: 7 additions & 0 deletions hr_expense_operating_unit/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
# © 2015 Eficent Business and IT Consulting Services S.L. -
# Jordi Ballester Alomar
# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import models
from . import tests
22 changes: 22 additions & 0 deletions hr_expense_operating_unit/__openerp__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# © 2015 Eficent Business and IT Consulting Services S.L. -
# Jordi Ballester Alomar
# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).

{
"name": "HR Expense Operating Unit",
"version": "9.0.1.0.0",
"license": 'LGPL-3',
"author": "Eficent Business and IT Consulting Services S.L., "
"Serpent Consulting Services Pvt. Ltd.,"
"Odoo Community Association (OCA)",
"website": "http://www.eficent.com",
"category": "Generic Modules/Human Resources",
"depends": ["hr_expense", "account_operating_unit"],
"data": [
"views/hr_expense_view.xml",
"security/hr_expense_security.xml"
],
'installable': True,
}
7 changes: 7 additions & 0 deletions hr_expense_operating_unit/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
# © 2015 Eficent Business and IT Consulting Services S.L. -
# Jordi Ballester Alomar
# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).

from . import hr_expense
33 changes: 33 additions & 0 deletions hr_expense_operating_unit/models/hr_expense.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
# © 2015 Eficent Business and IT Consulting Services S.L. -
# Jordi Ballester Alomar
# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).

from openerp import _, api, fields, models
from openerp.exceptions import UserError


class HrExpenseExpense(models.Model):
_inherit = 'hr.expense'

operating_unit_id = fields.Many2one('operating.unit', 'Operating Unit',
default=lambda self:
self.env['res.users'].
operating_unit_default_get(self._uid))

Copy link
Member

@serpentcs-dev1 serpentcs-dev1 Feb 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its better if we add the constraint for company in OU and Expense :

@api.multi
@api.constrains('operating_unit_id', 'company_id')
def _check_company_operating_unit(self):
        for rec in self:
            if rec.company_id and rec.operating_unit_id and \
                    rec.company_id != rec.operating_unit_id.company_id:
                raise Warning(_('The Company in the Expense and in '
                                'the Operating Unit must be the same.'))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, Thank you @darshan-serpent

@api.multi
def action_move_create(self):
res = super(HrExpenseExpense, self).action_move_create()
self.account_move_id.write({'operating_unit_id':
self.operating_unit_id.id})
return res

@api.multi
@api.constrains('operating_unit_id', 'company_id')
def _check_company_operating_unit(self):
for rec in self:
if rec.company_id and rec.operating_unit_id and \
rec.company_id != rec.operating_unit_id.company_id:
raise UserError(_('The Company in the Expense and in '
'the Operating Unit must be the same.'))
21 changes: 21 additions & 0 deletions hr_expense_operating_unit/security/hr_expense_security.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2015 Eficent Business and IT Consulting Services S.L.
Serpent Consulting Services Pvt. Ltd.
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) -->
<openerp>
<data noupdate="0">

<record id="ir_rule_hr_expense_allowed_operating_units"
model="ir.rule">
<field name="model_id" ref="hr_expense.model_hr_expense"/>
<field name="domain_force">['|',('operating_unit_id','=',False),('operating_unit_id','in',[g.id for g in user.operating_unit_ids])]</field>
<field name="name">Expenses from allowed operating units</field>
<field name="global" eval="True"/>
<field eval="1" name="perm_unlink"/>
<field eval="1" name="perm_write"/>
<field eval="1" name="perm_read"/>
<field eval="0" name="perm_create"/>
</record>

</data>
</openerp>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions hr_expense_operating_unit/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
# © 2015 Eficent Business and IT Consulting Services S.L. -
# Jordi Ballester Alomar
# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import test_hr_expense_operating_unit
118 changes: 118 additions & 0 deletions hr_expense_operating_unit/tests/test_hr_expense_operating_unit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# -*- coding: utf-8 -*-
# © 2015 Eficent Business and IT Consulting Services S.L. -
# Jordi Ballester Alomar
# © 2015 Serpent Consulting Services Pvt. Ltd. - Sudhir Arya
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from openerp.tests import common
from openerp.exceptions import AccessError


class TestHrExpenseOperatingUnit(common.TransactionCase):

def setUp(self):
super(TestHrExpenseOperatingUnit, self).setUp()
self.res_users_model = self.env['res.users']
self.hr_expense_model = self.env['hr.expense']
self.hr_employee_model = self.env['hr.employee']

self.company = self.env.ref('base.main_company')
self.partner1 = self.env.ref('base.res_partner_1')
self.partner2 = self.env.ref('base.res_partner_2')

# Expense Product
self.product1 = self.env.ref('hr_expense.air_ticket')

self.grp_hr_user = self.env.ref('base.group_hr_user')
self.grp_accou_mng = self.env.ref('account.group_account_manager')
self.grp_account_invoice =\
self.env.ref('account.group_account_invoice')

# Main Operating Unit
self.ou1 = self.env.ref('operating_unit.main_operating_unit')
# B2C Operating Unit
self.b2c = self.env.ref('operating_unit.b2c_operating_unit')

self.user1 = self._create_user('Test HR User 1', 'user_1', 'demo1',
[self.grp_hr_user, self.grp_accou_mng,
self.grp_account_invoice],
self.company,
[self.ou1, self.b2c])
self.user2 = self._create_user('Test HR User 2', 'user_2', 'demo2',
[self.grp_hr_user, self.grp_accou_mng,
self.grp_account_invoice],
self.company,
[self.b2c])

self.emp = self._create_hr_employee()

self.hr_expense1 = self._create_hr_expense(
self.ou1, self.emp)

self.hr_expense2 = self._create_hr_expense(
self.b2c, self.emp)

self._post_journal_entries(self.hr_expense1)
self._post_journal_entries(self.hr_expense2)

def _create_user(self, name, login, pwd, groups, company, operating_units,
context=None):
"""Creates a user."""
group_ids = [group.id for group in groups]
user = self.res_users_model.create({
'name': name,
'login': login,
'password': pwd,
'email': 'example@yourcompany.com',
'company_id': company.id,
'company_ids': [(4, company.id)],
'operating_unit_ids': [(4, ou.id) for ou in operating_units],
'groups_id': [(6, 0, group_ids)]
})
return user

def _create_hr_employee(self):
"""Creates an Employee."""
emp = self.hr_employee_model.create({
'name': "Test Employee",
'address_home_id': self.partner1.id,
})
return emp

def _create_hr_expense(self, operating_unit, emp):
"""Creates Expense for employee."""
expense = self.hr_expense_model.create({
'name': " Food Expense ",
'product_id': self.product1.id,
'operating_unit_id': operating_unit.id,
'unit_amount': '10.0',
'quantity': '5',
'employee_id': emp.id
})
return expense

def _post_journal_entries(self, expense):
"""Approves the Expense and creates accounting entries."""
expense.submit_expenses()
expense.approve_expenses()
expense.action_move_create()

def test_security(self):
# User 2 is only assigned to Operating Unit B2C, and cannot
# Access Expenses of Main Operating Unit.
record = self.hr_expense_model.sudo(self.user2.id).search(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to expand the test with creation or unlink. Following the fix proposed by @sbidoul

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

[('id', '=', self.hr_expense1.id),
('operating_unit_id', '=', self.ou1.id)])
self.assertEqual(record.ids, [], 'User 2 should not have access to %s'
% self.ou1.name)
with self.assertRaises(AccessError):
self.hr_expense1.sudo(self.user2.id).unlink()
with self.assertRaises(AccessError):
self.hr_expense1.sudo(self.user2.id).write({'name': 'new name'})

# Expense OU should have same OU of its accounting entries
self.assertEqual(self.hr_expense1.operating_unit_id.id,
self.hr_expense1.account_move_id.operating_unit_id.id,
"Expense OU should match with accounting entries OU")
self.assertEqual(self.hr_expense2.operating_unit_id.id,
self.hr_expense2.account_move_id.operating_unit_id.id,
"Expense OU should match with accounting entries OU")
42 changes: 42 additions & 0 deletions hr_expense_operating_unit/views/hr_expense_view.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2015 Eficent Business and IT Consulting Services S.L.
Serpent Consulting Services Pvt. Ltd.
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) -->
<openerp>
<data>

<record id="view_expenses_tree" model="ir.ui.view">
<field name="name">hr.expense.tree</field>
<field name="model">hr.expense</field>
<field name="inherit_id" ref="hr_expense.view_expenses_tree"/>
<field name="arch" type="xml">
<field name="date" position="after">
<field name="operating_unit_id" groups="operating_unit.group_multi_operating_unit"/>
</field>
</field>
</record>

<record id="hr_expense_my_tree" model="ir.ui.view">
<field name="name">my.hr.expense.tree</field>
<field name="model">hr.expense</field>
<field name="inherit_id" ref="hr_expense.hr_expense_my_tree"/>
<field name="arch" type="xml">
<field name="date" position="after">
<field name="operating_unit_id" groups="operating_unit.group_multi_operating_unit"/>
</field>
</field>
</record>

<record id="view_expenses_form" model="ir.ui.view">
<field name="name">hr.expense.form</field>
<field name="model">hr.expense</field>
<field name="inherit_id" ref="hr_expense.hr_expense_form_view"/>
<field name="arch" type="xml">
<field name="department_id" position="after">
<field name="operating_unit_id" groups="operating_unit.group_multi_operating_unit" options="{'no_create': True}"/>
</field>
</field>
</record>

</data>
</openerp>