summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
Diffstat (limited to 'addons')
-rw-r--r--addons/hr_org_chart/static/src/js/hr_org_chart.js162
-rw-r--r--addons/hr_org_chart/static/src/xml/hr_org_chart.xml24
-rw-r--r--addons/hr_org_chart/static/tests/hr_org_chart_tests.js164
-rw-r--r--addons/hr_org_chart/views/hr_templates.xml6
4 files changed, 276 insertions, 80 deletions
diff --git a/addons/hr_org_chart/static/src/js/hr_org_chart.js b/addons/hr_org_chart/static/src/js/hr_org_chart.js
index 60b6f94bc8b..c2c425d2612 100644
--- a/addons/hr_org_chart/static/src/js/hr_org_chart.js
+++ b/addons/hr_org_chart/static/src/js/hr_org_chart.js
@@ -1,76 +1,93 @@
odoo.define('web.OrgChart', function (require) {
"use strict";
-var ajax = require('web.ajax');
+var AbstractField = require('web.AbstractField');
+var concurrency = require('web.concurrency');
var core = require('web.core');
-var form_common = require('web.form_common');
+var field_registry = require('web.field_registry');
var QWeb = core.qweb;
var _t = core._t;
-var FieldOrgChart = form_common.AbstractField.extend({
+var FieldOrgChart = AbstractField.extend({
events: {
- "click .o_employee_redirect": "on_employee_redirect",
- "click .o_employee_sub_redirect": "on_employee_sub_redirect",
+ "click .o_employee_redirect": "_onEmployeeRedirect",
},
-
+ /**
+ * @constructor
+ * @override
+ */
init: function () {
this._super.apply(this, arguments);
+ this.dm = new concurrency.DropMisordered();
},
- start: function () {
- this.reinit();
- return this._super();
- },
-
- reinit: function () {
- this.emp_data = {
- managers: [],
- children: [],
- };
- },
-
- set_value: function (_value) {
- this.reinit();
- this._super(_value);
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * Get the chart data through a rpc call.
+ *
+ * @private
+ * @param {integer} employee_id
+ * @returns {Deferred}
+ */
+ _getOrgData: function (employee_id) {
+ var self = this;
+ return this.dm.add(this._rpc({
+ route: '/hr/get_org_chart',
+ params: {
+ employee_id: employee_id,
+ },
+ })).then(function (data) {
+ self.orgData = data;
+ });
},
-
- render_value: function () {
- if (! this.view.datarecord.id) {
- return this.$el.html(QWeb.render("hr_org_chart", {widget: this}));
+ /**
+ * @override
+ * @private
+ */
+ _render: function () {
+ if (!this.recordData.id) {
+ return this.$el.html(QWeb.render("hr_org_chart", {
+ managers: [],
+ children: [],
+ }));
}
var self = this;
- this.get_org_chart_data(this.view.datarecord.id).then(function () {
- self.$el.html(QWeb.render("hr_org_chart", {widget: self}));
- }).then(function () {
- self.$el.find('[data-toggle="popover"]').each(function () {
+ return this._getOrgData(this.recordData.id).then(function () {
+ self.$el.html(QWeb.render("hr_org_chart", self.orgData));
+ self.$('[data-toggle="popover"]').each(function () {
$(this).popover({
html: true,
- title: function() {
- var $title = $(QWeb.render('hr_orgchart_emp_popover_title', {employee: {
- name: $(this).data('emp-name'),
- id: $(this).data('emp-id'),
- }}));
- $title.on('click', '.o_employee_redirect', function(event) {
- self.on_employee_redirect(event);
- });
+ title: function () {
+ var $title = $(QWeb.render('hr_orgchart_emp_popover_title', {
+ employee: {
+ name: $(this).data('emp-name'),
+ id: $(this).data('emp-id'),
+ },
+ }));
+ $title.on('click',
+ '.o_employee_redirect', _.bind(self._onEmployeeRedirect, self));
return $title;
},
container: 'body',
placement: 'left',
trigger: 'focus',
- content: function() {
- var $content = $(QWeb.render('hr_orgchart_emp_popover_content', {employee: {
- id: $(this).data('emp-id'),
- name: $(this).data('emp-name'),
- direct_sub_count: parseInt($(this).data('emp-dir-subs')),
- indirect_sub_count: parseInt($(this).data('emp-ind-subs')),
- }}));
- $content.on('click', '.o_employee_sub_redirect', function(event) {
- self.on_employee_sub_redirect(event);
- });
+ content: function () {
+ var $content = $(QWeb.render('hr_orgchart_emp_popover_content', {
+ employee: {
+ id: $(this).data('emp-id'),
+ name: $(this).data('emp-name'),
+ direct_sub_count: parseInt($(this).data('emp-dir-subs')),
+ indirect_sub_count: parseInt($(this).data('emp-ind-subs')),
+ },
+ }));
+ $content.on('click',
+ '.o_employee_sub_redirect', _.bind(self._onEmployeeSubRedirect, self));
return $content;
},
template: $(QWeb.render('hr_orgchart_emp_popover', {})),
@@ -79,16 +96,18 @@ var FieldOrgChart = form_common.AbstractField.extend({
});
},
- get_org_chart_data: function (employee_id) {
- var self = this;
- return ajax.jsonRpc('/hr/get_org_chart', 'call', {
- employee_id: employee_id,
- }).then(function (data) {
- self.emp_data = data;
- });
- },
-
- on_employee_redirect: function (event) {
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Redirect to the employee form view.
+ *
+ * @private
+ * @param {MouseEvent} event
+ * @returns {Deferred} action loaded
+ */
+ _onEmployeeRedirect: function (event) {
event.preventDefault();
var employee_id = parseInt($(event.currentTarget).data('employee-id'));
return this.do_action({
@@ -101,8 +120,14 @@ var FieldOrgChart = form_common.AbstractField.extend({
res_id: employee_id,
});
},
-
- on_employee_sub_redirect: function (event) {
+ /**
+ * Redirect to the sub employee form view.
+ *
+ * @private
+ * @param {MouseEvent} event
+ * @returns {Deferred} action loaded
+ */
+ _onEmployeeSubRedirect: function (event) {
event.preventDefault();
var employee_id = parseInt($(event.currentTarget).data('employee-id'));
var employee_name = $(event.currentTarget).data('employee-name');
@@ -112,29 +137,30 @@ var FieldOrgChart = form_common.AbstractField.extend({
if (type === 'total') {
domain = ['&', ['parent_id', 'child_of', employee_id], ['id', '!=', employee_id]];
name = _.str.sprintf(_t("Subordinates of %s"), employee_name);
- }
- else if (type === 'indirect') {
- domain = ['&', '&', ['parent_id', 'child_of', employee_id], ['parent_id', '!=', employee_id], ['id', '!=', employee_id]];
+ } else if (type === 'indirect') {
+ domain = ['&', '&',
+ ['parent_id', 'child_of', employee_id],
+ ['parent_id', '!=', employee_id],
+ ['id', '!=', employee_id]
+ ];
name = _.str.sprintf(_t("Indirect Subordinates of %s"), employee_name);
}
if (employee_id) {
return this.do_action({
name: name,
type: 'ir.actions.act_window',
- view_type: 'tree',
- view_mode: 'kanban,tree,form',
- views: [[false, 'kanban'], [false, 'tree'], [false, 'form']],
+ view_mode: 'kanban,list,form',
+ views: [[false, 'kanban'], [false, 'list'], [false, 'form']],
target: 'current',
res_model: 'hr.employee',
domain: domain,
});
}
},
-
});
-core.form_widget_registry.add('hr_org_chart', FieldOrgChart);
-
+field_registry.add('hr_org_chart', FieldOrgChart);
return FieldOrgChart;
+
});
diff --git a/addons/hr_org_chart/static/src/xml/hr_org_chart.xml b/addons/hr_org_chart/static/src/xml/hr_org_chart.xml
index 661a1edc9d6..6aa027882f0 100644
--- a/addons/hr_org_chart/static/src/xml/hr_org_chart.xml
+++ b/addons/hr_org_chart/static/src/xml/hr_org_chart.xml
@@ -56,20 +56,20 @@
-->
<t t-set="emp_count" t-value="0"/>
- <div t-if='widget.emp_data.managers.length &gt; 0' class="o_org_chart_group_up">
- <t t-if='widget.emp_data.managers_more'>
+ <div t-if='managers.length &gt; 0' class="o_org_chart_group_up">
+ <t t-if='managers_more'>
<div class="o_org_chart_entry o_org_chart_more media">
<div class="media-left">
<a class="well media-object text-center o_employee_redirect"
- t-att-href="widget.emp_data.managers[0].link"
- t-att-data-employee-id="widget.emp_data.managers[0].id">
+ t-att-href="managers[0].link"
+ t-att-data-employee-id="managers[0].id">
<i t-attf-class="fa fa-angle-double-up"/>
</a>
</div>
</div>
</t>
- <t t-foreach="widget.emp_data.managers" t-as="employee">
+ <t t-foreach="managers" t-as="employee">
<t t-set="emp_count" t-value="emp_count + 1"/>
<t t-call="hr_org_chart_employee">
<t t-set="employee_type" t-value="'manager'"/>
@@ -77,12 +77,12 @@
</t>
</div>
- <t t-if="widget.emp_data.children.length || widget.emp_data.managers.length" t-call="hr_org_chart_employee">
+ <t t-if="children.length || managers.length" t-call="hr_org_chart_employee">
<t t-set="employee_type" t-value="'self'"/>
- <t t-set="employee" t-value="widget.emp_data.self"/>
+ <t t-set="employee" t-value="self"/>
</t>
- <t t-if="!widget.emp_data.children.length &amp;&amp; !widget.emp_data.managers.length">
+ <t t-if="!children.length &amp;&amp; !managers.length">
<div class="alert alert-info">
<p><b>No hierarchy position.</b></p>
<p>This employee has no manager or subordinate.</p>
@@ -90,8 +90,8 @@
</div>
</t>
- <div t-if="widget.emp_data.children.length" class="o_org_chart_group_down">
- <t t-foreach="widget.emp_data.children" t-as="employee">
+ <div t-if="children.length" class="o_org_chart_group_down">
+ <t t-foreach="children" t-as="employee">
<t t-set="emp_count" t-value="emp_count + 1"/>
<t t-if="emp_count &lt; 8">
<t t-call="hr_org_chart_employee">
@@ -100,11 +100,11 @@
</t>
</t>
- <t t-if="(widget.emp_data.children.length + widget.emp_data.managers.length) &gt; 7">
+ <t t-if="(children.length + managers.length) &gt; 7">
<div class="o_org_chart_entry o_org_chart_more media">
<div class="media-left">
<a href="#"
- t-att-data-employee-id="widget.emp_data.self.id"
+ t-att-data-employee-id="self.id"
class="well o_org_chart_show_more media-object text-center o_employee_sub_redirect">&#8230;</a>
</div>
</div>
diff --git a/addons/hr_org_chart/static/tests/hr_org_chart_tests.js b/addons/hr_org_chart/static/tests/hr_org_chart_tests.js
new file mode 100644
index 00000000000..a6041e25dcd
--- /dev/null
+++ b/addons/hr_org_chart/static/tests/hr_org_chart_tests.js
@@ -0,0 +1,164 @@
+odoo.define('hr_org_chart.tests', function (require) {
+"use strict";
+
+var FormView = require('web.FormView');
+var testUtils = require("web.test_utils");
+
+var createView = testUtils.createView;
+
+QUnit.module('hr_org_chart', {
+ before: function () {
+ this.data = {
+ hr_employee: {
+ fields: {
+ child_ids: {string: "one2many Subordinates field", type: "one2many", relation: 'hr_employee'},
+ },
+ records: [{
+ id: 1,
+ child_ids: [],
+ }]
+ }
+ };
+ },
+}, function () {
+ QUnit.test("hr org chart: empty render", function (assert) {
+ assert.expect(2);
+
+ var form = createView({
+ View: FormView,
+ model: 'hr_employee',
+ data: this.data,
+ arch:
+ '<form>' +
+ '<field name="child_ids" widget="hr_org_chart"/>' +
+ '</form>',
+ res_id: 1,
+ mockRPC: function (route, args) {
+ if (route === '/hr/get_org_chart') {
+ assert.ok('employee_id' in args, "it should have 'employee_id' as argument");
+ return $.when({
+ children: [],
+ managers: [],
+ managers_more: false,
+ });
+ }
+ return this._super(route, args);
+ }
+ });
+ assert.strictEqual(form.$('[name="child_ids"]').children().length, 1, "the chart should have 1 child");
+ form.destroy();
+ });
+ QUnit.test("hr org chart: basic render", function (assert) {
+ assert.expect(3);
+
+ var form = createView({
+ View: FormView,
+ model: 'hr_employee',
+ data: this.data,
+ arch:
+ '<form>' +
+ '<sheet>' +
+ '<div id="o_employee_container"><div id="o_employee_main">' +
+ '<div id="o_employee_right">' +
+ '<field name="child_ids" widget="hr_org_chart"/>' +
+ '</div>' +
+ '</div></div>' +
+ '</sheet>' +
+ '</form>',
+ res_id: 1,
+ mockRPC: function (route, args) {
+ if (route === '/hr/get_org_chart') {
+ assert.ok('employee_id' in args, "it should have 'employee_id' as argument");
+ return $.when({
+ children: [{
+ direct_sub_count: 0,
+ indirect_sub_count: 0,
+ job_id: 2,
+ job_name: 'Sub-Gooroo',
+ link: 'fake_link',
+ name: 'Michael Hawkins',
+ }],
+ managers: [],
+ managers_more: false,
+ self: {
+ direct_sub_count: 1,
+ id: 1,
+ indirect_sub_count: 1,
+ job_id: 1,
+ job_name: 'Gooroo',
+ link: 'fake_link',
+ name: 'Antoine Langlais',
+ }
+ });
+ }
+ return this._super(route, args);
+ }
+ });
+ assert.strictEqual(form.$('.o_org_chart_entry_sub').length, 1,
+ "the chart should have 1 subordinate");
+ assert.strictEqual(form.$('.o_org_chart_entry_self').length, 1,
+ "the current employee should only be displayed once in the chart");
+ form.destroy();
+ });
+ QUnit.test("hr org chart: basic manager render", function (assert) {
+ assert.expect(4);
+
+ var form = createView({
+ View: FormView,
+ model: 'hr_employee',
+ data: this.data,
+ arch:
+ '<form>' +
+ '<sheet>' +
+ '<div id="o_employee_container"><div id="o_employee_main">' +
+ '<div id="o_employee_right">' +
+ '<field name="child_ids" widget="hr_org_chart"/>' +
+ '</div>' +
+ '</div></div>' +
+ '</sheet>' +
+ '</form>',
+ res_id: 1,
+ mockRPC: function (route, args) {
+ if (route === '/hr/get_org_chart') {
+ assert.ok('employee_id' in args, "should have 'employee_id' as argument");
+ return $.when({
+ children: [{
+ direct_sub_count: 0,
+ indirect_sub_count: 0,
+ job_id: 2,
+ job_name: 'Sub-Gooroo',
+ link: 'fake_link',
+ name: 'Michael Hawkins',
+ }],
+ managers: [{
+ direct_sub_count: 1,
+ id: 1,
+ indirect_sub_count: 2,
+ job_id: 1,
+ job_name: 'Chief Gooroo',
+ link: 'fake_link',
+ name: 'Antoine Langlais',
+ }],
+ managers_more: false,
+ self: {
+ direct_sub_count: 1,
+ id: 1,
+ indirect_sub_count: 1,
+ job_id: 3,
+ job_name: 'Gooroo',
+ link: 'fake_link',
+ name: 'John Smith',
+ }
+ });
+ }
+ return this._super(route, args);
+ }
+ });
+ assert.strictEqual(form.$('.o_org_chart_group_up .o_org_chart_entry_manager').length, 1, "the chart should have 1 manager");
+ assert.strictEqual(form.$('.o_org_chart_group_down .o_org_chart_entry_sub').length, 1, "the chart should have 1 subordinate");
+ assert.strictEqual(form.$('.o_org_chart_entry_self').length, 1, "the chart should have only once the current employee");
+ form.destroy();
+ });
+});
+
+}); \ No newline at end of file
diff --git a/addons/hr_org_chart/views/hr_templates.xml b/addons/hr_org_chart/views/hr_templates.xml
index ae1e3665cfc..fbaf9ac1142 100644
--- a/addons/hr_org_chart/views/hr_templates.xml
+++ b/addons/hr_org_chart/views/hr_templates.xml
@@ -6,4 +6,10 @@
<script type="text/javascript" src="/hr_org_chart/static/src/js/hr_org_chart.js"></script>
</xpath>
</template>
+
+ <template id="qunit_suite" inherit_id="web.qunit_suite">
+ <xpath expr="//script[last()]" position="after">
+ <script type="text/javascript" src="/hr_org_chart/static/tests/hr_org_chart_tests.js"/>
+ </xpath>
+ </template>
</odoo>