Skip to content
Open
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
61 changes: 61 additions & 0 deletions hr_governance/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
=====================
HR Governance
=====================


Features
========

Introduce a new way to visualize organization in form of a packed circle chart

## Chart

* **Visualize Organizational Hierarchy**: Only 1 root circle that defines the layout, with all other circles as its children, representing sub-hierarchies.
* **Navigation**:
* The chart supports zooming in and out, along with dragging to explore different levels of detail.
* **Searching**:
* Users can perform full-text searches within circle names, employee names, roles, expectations, and authorities to identify responsible roles or circles.
* Autocomplete is also available.

## Form View

* A form view is shown on the side, displaying the current circle. A resizer bar is placed between the chart and the form for easy resizing.
* The UI in the form view adapts to display circle and role details based on the role type.
* Each modification of a circle or role is logged and visible using Odoo’s chatter.
* The hint/placeholder for the ``Raison d'être`` field dynamically updates based on the role type.

Choose a reason for hiding this comment

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

Maybe you could provide an english translation for Raison d'être?
"Excellence together"?


## Models

### On ``governance.circle`` model

* Manages the hierarchy of circles and their subcircles.
* Method ``get_hierarchy_data`` populates data for visualization.
* Method ``create`` is overridden to automatically support role creation.
* When a role is created, structuring roles (if defined) are automatically created as subcircles.
* To optimize performance, the result of ``_get_structuring_templates`` is cached and refreshed whenever a type is added or removed.
* Constraint ``_check_member_ids``: validates that an assigned member to a role should be a part of its parent circle.

### On ``governance.role.type`` model

* ``get_default_type_id`` pre-fills the default type when the user clicks the Create Role button in the form view.

### On ``res.config.settings`` model

* Adds ``governance_check_grayscale`` option to convert all circles to grayscale.
* Adds ``governance_single_assignee_mode`` option to restrict each role to a single assignee.

## UI Components

### At ``src/views``

* ``CirclePackController`` facilitates the coordination between ``CirclePackModel`` and ``CirclePackRenderer``. It subscribes to the **update** event from the model to re-render the renderer whenever a user performs a search.
* ``CirclePackRenderer``: Generates the chart using D3.js, rendering the data passed from the controller.

### At ``src/components``

* ``CirclePackingColorList``: Replaces Odoo native colors for better appearance.
* ``DynamicTextHint``: Supports dynamic text hints based on the value of a field (in the form view, it's the placeholder field).
* In this module, an example of the usage is in the ``governance_circle_view_form``.
* ``FormWrapperController``: Overrides Odoo's native FormController to enable synchronization with the chart.
* Adds two buttons for creating circles and roles.
* ``Many2ManySearchBar``: Supports autocomplete for Many2Many (M2M) fields, treating them as Many2One (M2O) fields for search functionality.
3 changes: 3 additions & 0 deletions hr_governance/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from . import models
from . import wizard
from .hooks import post_init_hook
42 changes: 42 additions & 0 deletions hr_governance/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright 2025 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "HR Governance",
"version": "17.0.1.0.0",
"author": "Camptocamp, Odoo Community Association (OCA)",
"license": "AGPL-3",
"category": "Generic",
"website": "https://github.com/OCA/hr",
"depends": [
"hr",
# oca/server-tools:
"base_m2m_custom_field",
# oca/social:
"mail_activity_default_assignee",
],
"data": [
"data/role_type_data.xml",
"data/ir_config_parameter_data.xml",
"data/mail_activity_type_data.xml",
"data/governance_circle_data.xml",
"security/governance_security.xml",
"security/ir.model.access.csv",
"views/governance_circle_member_views.xml",
"views/governance_role_type_views.xml",
"views/governance_circle_views.xml",
"views/mail_activity_views.xml",
"views/menu_views.xml",
"views/res_config_settings_views.xml",
],
"assets": {
"hr_governance.chart_libs": [
"/hr_governance/static/lib/**/*",
],
"web.assets_backend": [
"hr_governance/static/src/components/**/*",
"hr_governance/static/src/**/*",
],
},
"installable": True,
"post_init_hook": "post_init_hook",
}
9 changes: 9 additions & 0 deletions hr_governance/data/governance_circle_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">

<record id="root" model="governance.circle" context="{'default_is_circle': True}">
<field name="name">Root</field>
<field name="is_root">True</field>
</record>

</odoo>
13 changes: 13 additions & 0 deletions hr_governance/data/ir_config_parameter_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo noupdate="1">
<function
model="ir.config_parameter"
name="set_param"
eval="('hr_governance.only_manager_change_color', '1')"
/>
<function
model="ir.config_parameter"
name="set_param"
eval="('hr_governance.stripe_all_unassigned_roles', '1')"
/>
</odoo>
7 changes: 7 additions & 0 deletions hr_governance/data/mail_activity_type_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="reorganization_proposal" model="mail.activity.type">
<field name="name">Reorganization proposal</field>
<field name="res_model">governance.circle</field>
</record>
</odoo>
32 changes: 32 additions & 0 deletions hr_governance/data/role_type_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">

<record id="memory_gct" model="governance.role.type">
<field name="name">Memory</field>
<field name="type">structure</field>
<field
name="purpose"
>To ensure that registers are properly kept, providing everyone with access to the information required by each role to manage its activities, in particular by transferring all decisions and information shared at meetings to the information system.</field>
</record>

<record id="facilitation_gct" model="governance.role.type">
<field name="name">Facilitation</field>
<field name="type">structure</field>
<field
name="purpose"
>To ensure that meetings are run efficiently and humanely, so as to obtain clear results within the allotted time, in response to the issues raised by circle members: validating projects, modifying structural or regulatory elements, making collective decisions, sharing relevant information, defining objectives and priorities.</field>
</record>

<record id="steering_gct" model="governance.role.type">
<field name="name">Steering</field>
<field name="type">structure</field>
<field name="is_steering_role">True</field>
<field
name="purpose"
>To ensure that the circle's activity meets its raison d'être, its expectations and the objectives set by the encompassing circle, and remains consistent with the company's raison d'être and values.

To take care of its members, ensuring that each one plays a role in line with his or her skills and motivation.</field>
</record>


</odoo>
12 changes: 12 additions & 0 deletions hr_governance/hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright 2025 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).


def set_root_circle_name(env):
"""Changing the name of the root circle by the company name"""
root_circle = env.ref("hr_governance.root")
root_circle.write({"name": env.company.name})


def post_init_hook(env):
set_root_circle_name(env)
10 changes: 10 additions & 0 deletions hr_governance/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from . import governance_authority
from . import governance_circle
from . import governance_circle_member
from . import governance_expectation
from . import governance_role_type
from . import hr_employee
from . import ir_http
from . import ir_ui_view
from . import res_config_settings
from . import res_users
19 changes: 19 additions & 0 deletions hr_governance/models/governance_authority.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2025 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import fields, models


class GovernanceAuthority(models.Model):
_name = "governance.authority"
_description = "Governance Authority"

name = fields.Text(required=True)

_sql_constraints = [
(
"unique_authority",
"unique(name)",
"This Authority already exists",
),
]
Loading
Loading