diff --git a/hr_expense_operating_unit/README.rst b/hr_expense_operating_unit/README.rst new file mode 100644 index 0000000000..f0e1cf7e64 --- /dev/null +++ b/hr_expense_operating_unit/README.rst @@ -0,0 +1,95 @@ +========================= +HR Expense Operating Unit +========================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:13f1a13af9ebc3b43564bf45cd6662d058459aee3a7a74028e0fc7b36078e0ea + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Foperating--unit-lightgray.png?logo=github + :target: https://github.com/OCA/operating-unit/tree/16.0/hr_expense_operating_unit + :alt: OCA/operating-unit +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/operating-unit-16-0/operating-unit-16-0-hr_expense_operating_unit + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/operating-unit&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +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. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To use this module create the Operating Unit or use a created one: + +#. Once you have an OU, make sure you assign it to the desired User. +#. Create the expense with the OU. +#. The selectable OU are filtered by the users OU's. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* ForgeFlow S.L. +* Serpent Consulting Services Pvt. Ltd. + +Contributors +~~~~~~~~~~~~ + +* Jordi Ballester Alomar +* Serpent Consulting Services Pvt. Ltd. +* Jarsa Sistemas +* Saran Lim. + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +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. + +This module is part of the `OCA/operating-unit `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/hr_expense_operating_unit/__init__.py b/hr_expense_operating_unit/__init__.py new file mode 100644 index 0000000000..44f9fd7c13 --- /dev/null +++ b/hr_expense_operating_unit/__init__.py @@ -0,0 +1,3 @@ +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from . import models diff --git a/hr_expense_operating_unit/__manifest__.py b/hr_expense_operating_unit/__manifest__.py new file mode 100644 index 0000000000..e828f014c6 --- /dev/null +++ b/hr_expense_operating_unit/__manifest__.py @@ -0,0 +1,17 @@ +# Copyright 2016-19 ForgeFlow S.L. +# Copyright 2016-19 Serpent Consulting Services Pvt. Ltd. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +{ + "name": "HR Expense Operating Unit", + "version": "16.0.1.0.0", + "license": "LGPL-3", + "author": "ForgeFlow S.L., " + "Serpent Consulting Services Pvt. Ltd.," + "Odoo Community Association (OCA)", + "website": "https://github.com/OCA/operating-unit", + "category": "Generic Modules/Human Resources", + "depends": ["hr_expense", "account_operating_unit"], + "data": ["views/hr_expense_view.xml", "security/hr_expense_security.xml"], + "installable": True, +} diff --git a/hr_expense_operating_unit/i18n/hr_expense_operating_unit.pot b/hr_expense_operating_unit/i18n/hr_expense_operating_unit.pot new file mode 100644 index 0000000000..d15ba3244d --- /dev/null +++ b/hr_expense_operating_unit/i18n/hr_expense_operating_unit.pot @@ -0,0 +1,70 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_expense_operating_unit +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.0\n" +"Report-Msgid-Bugs-To: \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_expense_operating_unit +#: code:addons/hr_expense_operating_unit/models/hr_expense.py:0 +#, python-format +msgid "" +"Configuration error. The Company in the Expense and in the Operating Unit " +"must be the same." +msgstr "" + +#. module: hr_expense_operating_unit +#: code:addons/hr_expense_operating_unit/models/hr_expense.py:0 +#: code:addons/hr_expense_operating_unit/models/hr_expense.py:0 +#, python-format +msgid "" +"Configuration error. The Operating Unit in the Expense sheet and in the " +"Expense must be the same." +msgstr "" + +#. module: hr_expense_operating_unit +#: code:addons/hr_expense_operating_unit/models/hr_expense.py:0 +#, python-format +msgid "" +"Configuration error. The company in\n" +" the Expense and in the Operating Unit must be the same" +msgstr "" + +#. module: hr_expense_operating_unit +#: model:ir.model,name:hr_expense_operating_unit.model_hr_expense +msgid "Expense" +msgstr "" + +#. module: hr_expense_operating_unit +#: model:ir.model,name:hr_expense_operating_unit.model_hr_expense_sheet +msgid "Expense Report" +msgstr "" + +#. module: hr_expense_operating_unit +#: model:ir.model.fields,field_description:hr_expense_operating_unit.field_hr_expense__operating_unit_id +#: model:ir.model.fields,field_description:hr_expense_operating_unit.field_hr_expense_sheet__operating_unit_id +#: model_terms:ir.ui.view,arch_db:hr_expense_operating_unit.hr_expense_sheet_view_search +#: model_terms:ir.ui.view,arch_db:hr_expense_operating_unit.hr_expense_view_search +msgid "Operating Unit" +msgstr "" + +#. module: hr_expense_operating_unit +#: model:ir.model,name:hr_expense_operating_unit.model_account_payment_register +msgid "Register Payment" +msgstr "" + +#. module: hr_expense_operating_unit +#: code:addons/hr_expense_operating_unit/models/hr_expense.py:0 +#, python-format +msgid "" +"You cannot submit the Expenses having different Operating Units or with no " +"Operating Unit" +msgstr "" diff --git a/hr_expense_operating_unit/models/__init__.py b/hr_expense_operating_unit/models/__init__.py new file mode 100644 index 0000000000..d82b871c92 --- /dev/null +++ b/hr_expense_operating_unit/models/__init__.py @@ -0,0 +1,3 @@ +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from . import hr_expense diff --git a/hr_expense_operating_unit/models/hr_expense.py b/hr_expense_operating_unit/models/hr_expense.py new file mode 100644 index 0000000000..9e5a82fbe2 --- /dev/null +++ b/hr_expense_operating_unit/models/hr_expense.py @@ -0,0 +1,122 @@ +# Copyright 2016-19 ForgeFlow S.L. +# Copyright 2016-19 Serpent Consulting Services Pvt. Ltd. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).). + +from odoo import _, api, fields, models +from odoo.exceptions import UserError, ValidationError + + +class HrExpenseExpense(models.Model): + _inherit = "hr.expense" + + operating_unit_id = fields.Many2one( + comodel_name="operating.unit", + string="Operating Unit", + default=lambda self: self.env["res.users"].operating_unit_default_get(), + ) + + def action_submit_expenses(self): + ctx = self._context.copy() + operating_unit_id = self.mapped("operating_unit_id") + if operating_unit_id and len(operating_unit_id) > 1: + raise UserError( + _( + "Configuration error. The Operating " + "Unit in the Expense sheet and in the " + "Expense must be the same." + ) + ) + ctx.update({"default_operating_unit_id": operating_unit_id.id}) + return super( + HrExpenseExpense, self.with_context(**ctx) + ).action_submit_expenses() + + @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 ValidationError( + _( + "Configuration error. The Company in " + "the Expense and in the Operating " + "Unit must be the same." + ) + ) + + @api.constrains("operating_unit_id", "sheet_id") + def _check_expense_operating_unit(self): + for rec in self: + if ( + rec.sheet_id + and rec.sheet_id.operating_unit_id + and rec.operating_unit_id + and rec.sheet_id.operating_unit_id != rec.operating_unit_id + ): + raise ValidationError( + _( + "Configuration error. The Operating " + "Unit in the Expense sheet and in the " + "Expense must be the same." + ) + ) + + def _get_default_expense_sheet_values(self): + sheet_values = super()._get_default_expense_sheet_values() + ous = self.mapped("operating_unit_id") + if len(ous) != 1 or any(not expense.operating_unit_id for expense in self): + raise ValidationError( + _( + "You cannot submit the Expenses having " + "different Operating Units or with " + "no Operating Unit" + ) + ) + for sheet in sheet_values: + sheet.update({"operating_unit_id": ous.id}) + return sheet_values + + def _prepare_move_line_vals(self): + move_line_values = super()._prepare_move_line_vals() + move_line_values["operating_unit_id"] = self.operating_unit_id.id + return move_line_values + + +class HrExpenseSheet(models.Model): + _inherit = "hr.expense.sheet" + + operating_unit_id = fields.Many2one( + comodel_name="operating.unit", + string="Operating Unit", + default=lambda self: self.env["res.users"].operating_unit_default_get(), + ) + + @api.onchange("operating_unit_id") + def _onchange_operating_unit_id(self): + if self.operating_unit_id: + self.expense_line_ids.update( + {"operating_unit_id": self.operating_unit_id.id} + ) + + @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 ValidationError( + _( + """Configuration error. The company in + the Expense and in the Operating Unit must be the same""" + ) + ) + + def _prepare_move_vals(self): + move_values = super()._prepare_move_vals() + move_values["operating_unit_id"] = self.operating_unit_id.id + return move_values diff --git a/hr_expense_operating_unit/readme/CONTRIBUTORS.rst b/hr_expense_operating_unit/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..7c7c15a460 --- /dev/null +++ b/hr_expense_operating_unit/readme/CONTRIBUTORS.rst @@ -0,0 +1,4 @@ +* Jordi Ballester Alomar +* Serpent Consulting Services Pvt. Ltd. +* Jarsa Sistemas +* Saran Lim. diff --git a/hr_expense_operating_unit/readme/DESCRIPTION.rst b/hr_expense_operating_unit/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..ba571ce112 --- /dev/null +++ b/hr_expense_operating_unit/readme/DESCRIPTION.rst @@ -0,0 +1,7 @@ +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. diff --git a/hr_expense_operating_unit/readme/USAGE.rst b/hr_expense_operating_unit/readme/USAGE.rst new file mode 100644 index 0000000000..6fac1fbb09 --- /dev/null +++ b/hr_expense_operating_unit/readme/USAGE.rst @@ -0,0 +1,5 @@ +To use this module create the Operating Unit or use a created one: + +#. Once you have an OU, make sure you assign it to the desired User. +#. Create the expense with the OU. +#. The selectable OU are filtered by the users OU's. diff --git a/hr_expense_operating_unit/security/hr_expense_security.xml b/hr_expense_operating_unit/security/hr_expense_security.xml new file mode 100644 index 0000000000..d0fce07cb9 --- /dev/null +++ b/hr_expense_operating_unit/security/hr_expense_security.xml @@ -0,0 +1,30 @@ + + + + + + ['|',('operating_unit_id','=',False),('operating_unit_id','in',[g.id for g in user.operating_unit_ids])] + Expenses from allowed operating units + + + + + + + + + ['|',('operating_unit_id','=',False),('operating_unit_id','in',[g.id for g in user.operating_unit_ids])] + Expenses from allowed operating units + + + + + + + diff --git a/hr_expense_operating_unit/static/description/icon.png b/hr_expense_operating_unit/static/description/icon.png new file mode 100644 index 0000000000..3a0328b516 Binary files /dev/null and b/hr_expense_operating_unit/static/description/icon.png differ diff --git a/hr_expense_operating_unit/static/description/index.html b/hr_expense_operating_unit/static/description/index.html new file mode 100644 index 0000000000..c67f890f36 --- /dev/null +++ b/hr_expense_operating_unit/static/description/index.html @@ -0,0 +1,439 @@ + + + + + +HR Expense Operating Unit + + + +
+

HR Expense Operating Unit

+ + +

Beta License: LGPL-3 OCA/operating-unit Translate me on Weblate Try me on Runboat

+

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.
  • +
+

Table of contents

+ +
+

Usage

+

To use this module create the Operating Unit or use a created one:

+
    +
  1. Once you have an OU, make sure you assign it to the desired User.
  2. +
  3. Create the expense with the OU.
  4. +
  5. The selectable OU are filtered by the users OU’s.
  6. +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • ForgeFlow S.L.
  • +
  • Serpent Consulting Services Pvt. Ltd.
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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.

+

This module is part of the OCA/operating-unit project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/hr_expense_operating_unit/tests/__init__.py b/hr_expense_operating_unit/tests/__init__.py new file mode 100644 index 0000000000..16b7340d16 --- /dev/null +++ b/hr_expense_operating_unit/tests/__init__.py @@ -0,0 +1,3 @@ +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from . import test_hr_expense_operating_unit diff --git a/hr_expense_operating_unit/tests/test_hr_expense_operating_unit.py b/hr_expense_operating_unit/tests/test_hr_expense_operating_unit.py new file mode 100644 index 0000000000..b2b422f3b8 --- /dev/null +++ b/hr_expense_operating_unit/tests/test_hr_expense_operating_unit.py @@ -0,0 +1,220 @@ +# Copyright 2016-19 ForgeFlow S.L. +# Copyright 2016-19 Serpent Consulting Services Pvt. Ltd. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from odoo import fields, tools +from odoo.exceptions import ValidationError +from odoo.tests.common import Form, TransactionCase + + +class TestHrExpenseOperatingUnit(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + + cls.res_users_model = cls.env["res.users"] + cls.hr_expense_model = cls.env["hr.expense"] + cls.hr_expense_sheet_model = cls.env["hr.expense.sheet"] + cls.hr_employee_model = cls.env["hr.employee"] + + cls.company = cls.env.ref("base.main_company") + cls.partner1 = cls.env.ref("base.res_partner_1") + cls.partner2 = cls.env.ref("base.res_partner_2") + + # Expense Product + cls.product1 = cls.env.ref("hr_expense.expense_product_mileage") + + cls.grp_hr_user = cls.env.ref("hr.group_hr_user") + cls.grp_accou_mng = cls.env.ref("account.group_account_manager") + cls.grp_account_invoice = cls.env.ref("account.group_account_invoice") + + # Main Operating Unit + cls.ou1 = cls.env.ref("operating_unit.main_operating_unit") + # B2C Operating Unit + cls.b2c = cls.env.ref("operating_unit.b2c_operating_unit") + + cls.user1 = cls._create_user( + "Test HR User 1", + "user_1", + "demo1", + [cls.grp_hr_user, cls.grp_accou_mng, cls.grp_account_invoice], + cls.company, + [cls.ou1, cls.b2c], + ) + cls.user2 = cls._create_user( + "Test HR User 2", + "user_2", + "demo2", + [cls.grp_hr_user, cls.grp_accou_mng, cls.grp_account_invoice], + cls.company, + [cls.b2c], + ) + + cls.emp = cls._create_hr_employee() + + cls.hr_expense1 = cls._create_hr_expense(cls.ou1, cls.emp) + + cls.hr_expense2 = cls._create_hr_expense(cls.b2c, cls.emp) + + @classmethod + def _create_user( + cls, name, login, pwd, groups, company, operating_units, context=None + ): + """Creates a user.""" + group_ids = [group.id for group in groups] + user = cls.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 + + @classmethod + def _create_hr_employee(cls): + """Creates an Employee.""" + emp = cls.hr_employee_model.create( + {"name": "Test Employee", "address_home_id": cls.partner1.id} + ) + return emp + + @classmethod + def _create_hr_expense(cls, operating_unit, emp): + """Creates Expense for employee.""" + hr_expense = cls.hr_expense_model.create( + { + "name": "Traveling Expense", + "product_id": cls.product1.id, + "operating_unit_id": operating_unit.id, + "unit_amount": "10.0", + "quantity": "5", + "employee_id": emp.id, + } + ) + return hr_expense + + def _post_journal_entries(self, expense_sheet): + """Approves the Expense and creates accounting entries.""" + expense_sheet.approve_expense_sheets() + expense_sheet.action_sheet_move_create() + self.assertEqual( + expense_sheet.account_move_id.line_ids[0].operating_unit_id, + expense_sheet.operating_unit_id, + ) + + def _register_payment(self, move_id, amount, ctx=False): + if not ctx: + ctx = { + "active_ids": [move_id.id], + "active_id": move_id.id, + "active_model": "account.move", + } + PaymentWizard = self.env["account.payment.register"] + with Form(PaymentWizard.with_context(**ctx)) as f: + f.payment_date = fields.Date.today() + f.amount = amount + payment_wizard = f.save() + payment_wizard.action_create_payments() + + 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.with_user(self.user2.id).search( + [("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 + ) + # Create the expense sheet + hr_expense_dict1 = self.hr_expense1.action_submit_expenses() + sheet_context = hr_expense_dict1.get("context") + sheet_dict = { + "name": sheet_context.get("default_name", ""), + "employee_id": sheet_context.get("default_employee_id", False), + "company_id": sheet_context.get("default_company_id", False), + "state": sheet_context.get("default_state", ""), + "expense_line_ids": sheet_context.get("default_expense_line_ids", []), + } + self.hr_expense_sheet1 = self.hr_expense_sheet_model.create(sheet_dict) + self._post_journal_entries(self.hr_expense_sheet1) + # Expense OU should have same OU of its accounting entries + self.assertEqual( + self.hr_expense_sheet1.expense_line_ids.operating_unit_id, + self.hr_expense_sheet1.account_move_id.line_ids.mapped("operating_unit_id"), + "Expense OU should match with accounting entries OU", + ) + self._register_payment(self.hr_expense_sheet1.account_move_id, 50.0) + + @tools.mute_logger( + "odoo.addons.hr_expense_operating_unit.tests.test_hr_expense_operating_unit" + ) + def test_constrains_error(self): + hr_expense_dict1 = self.hr_expense1.action_submit_expenses() + sheet_context = hr_expense_dict1.get("context") + sheet_dict = { + "name": sheet_context.get("default_name", ""), + "employee_id": sheet_context.get("default_employee_id", False), + "company_id": sheet_context.get("default_company_id", False), + "state": sheet_context.get("default_state", ""), + "expense_line_ids": sheet_context.get("default_expense_line_ids", []), + } + self.hr_expense_sheet1 = self.hr_expense_sheet_model.create(sheet_dict) + with self.assertRaises(ValidationError): + self.hr_expense_sheet1.expense_line_ids.write( + {"operating_unit_id": self.b2c.id} + ) + + hr_expense_dict2 = self.hr_expense2.action_submit_expenses() + sheet_context = hr_expense_dict2.get("context") + sheet_dict = { + "name": sheet_context.get("default_name", ""), + "employee_id": sheet_context.get("default_employee_id", False), + "company_id": sheet_context.get("default_company_id", False), + "state": sheet_context.get("default_state", ""), + "expense_line_ids": sheet_context.get("default_expense_line_ids", []), + } + with self.assertRaises(ValidationError): + self.hr_expense_sheet2 = self.hr_expense_sheet_model.create(sheet_dict) + + self.hr_expense3 = self.hr_expense_model.create( + { + "name": "Traveling Expense", + "product_id": self.product1.id, + "unit_amount": "10.0", + "quantity": "5", + "operating_unit_id": False, + "employee_id": self.emp.id, + } + ) + + with self.assertRaises(ValidationError): + self.hr_expense3.action_submit_expenses() + + def test_onchange(self): + """Test that onchange works as expected""" + hr_expense_dict1 = self.hr_expense1.action_submit_expenses() + sheet_context = hr_expense_dict1.get("context") + sheet_dict = { + "name": sheet_context.get("default_name", ""), + "employee_id": sheet_context.get("default_employee_id", False), + "company_id": sheet_context.get("default_company_id", False), + "state": sheet_context.get("default_state", ""), + "expense_line_ids": sheet_context.get("default_expense_line_ids", []), + } + sheet = self.hr_expense_sheet_model.create(sheet_dict) + self.assertEqual(sheet.operating_unit_id, self.ou1) + self.assertEqual(sheet.expense_line_ids.operating_unit_id, self.ou1) + sheet.operating_unit_id = self.env["operating.unit"] + sheet.env.flush_all() + self.assertEqual(sheet.expense_line_ids.operating_unit_id, self.ou1) + sheet.expense_line_ids.operating_unit_id = self.env["operating.unit"] + sheet.env.flush_all() + sheet.operating_unit_id = self.b2c + sheet._onchange_operating_unit_id() + self.assertEqual(sheet.expense_line_ids.operating_unit_id, self.b2c) diff --git a/hr_expense_operating_unit/views/hr_expense_view.xml b/hr_expense_operating_unit/views/hr_expense_view.xml new file mode 100644 index 0000000000..0d8811aa2a --- /dev/null +++ b/hr_expense_operating_unit/views/hr_expense_view.xml @@ -0,0 +1,103 @@ + + + + + + hr.expense.tree + hr.expense + + + + + + + + + hr.expense.form + hr.expense + + + + + + + + + hr.expense.view.search + hr.expense + + + + + + + + + + hr.expense.sheet.tree + hr.expense.sheet + + + + + + + + + hr.expense.sheet.form + hr.expense.sheet + + + + + + + + + + + + hr.expense.sheet.view.search + hr.expense.sheet + + + + + + + + diff --git a/setup/hr_expense_operating_unit/odoo/addons/hr_expense_operating_unit b/setup/hr_expense_operating_unit/odoo/addons/hr_expense_operating_unit new file mode 120000 index 0000000000..251f0009a6 --- /dev/null +++ b/setup/hr_expense_operating_unit/odoo/addons/hr_expense_operating_unit @@ -0,0 +1 @@ +../../../../hr_expense_operating_unit \ No newline at end of file diff --git a/setup/hr_expense_operating_unit/setup.py b/setup/hr_expense_operating_unit/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/hr_expense_operating_unit/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)