mirror of
https://github.com/bringout/oca-ocb-hr.git
synced 2026-04-27 07:51:59 +02:00
19.0 vanilla
This commit is contained in:
parent
a1137a1456
commit
e1d89e11e3
2789 changed files with 1093187 additions and 605897 deletions
|
|
@ -0,0 +1,53 @@
|
|||
import { Component, markup } from "@odoo/owl";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
|
||||
import { STATIC_ACTIONS_GROUP_NUMBER } from "@web/search/action_menus/action_menus";
|
||||
|
||||
const cogMenuRegistry = registry.category("cogMenu");
|
||||
|
||||
/**
|
||||
* 'Search Matching Applicants' menu
|
||||
*
|
||||
* This component is used to search matching skills among the all applicants
|
||||
* It's only available in the kanban and list view of the applicants.
|
||||
* @extends Component
|
||||
*/
|
||||
export class SearchJobApplicant extends Component {
|
||||
static template = "hr_recruitment_skills.SearchJobApplicant";
|
||||
static components = { DropdownItem };
|
||||
static props = {};
|
||||
|
||||
setup() {
|
||||
this.action = useService("action");
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Protected
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
async openMatchingJobApplicants() {
|
||||
const { globalContext } = this.env.searchModel;
|
||||
const action = await this.env.services.orm.call(
|
||||
"hr.job",
|
||||
"action_search_matching_applicants",
|
||||
[globalContext.active_id]
|
||||
);
|
||||
action.help = markup(action.help);
|
||||
return this.action.doAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
export const searchJobApplicant = {
|
||||
Component: SearchJobApplicant,
|
||||
groupNumber: STATIC_ACTIONS_GROUP_NUMBER,
|
||||
isDisplayed: ({ config, searchModel }) => {
|
||||
return (
|
||||
searchModel.resModel === "hr.applicant" &&
|
||||
searchModel.globalContext.allow_search_matching_applicants &&
|
||||
config.viewArch.classList.contains('o_search_matching_applicant')
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
cogMenuRegistry.add("search-job-applicants-menu", searchJobApplicant, { sequence: 11 });
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="hr_recruitment_skills.SearchJobApplicant">
|
||||
<DropdownItem onSelected.bind="openMatchingJobApplicants">
|
||||
<i class="fa fa-fw fa-search me-1" aria-hidden="true"></i>Search Matching Applicants
|
||||
</DropdownItem>
|
||||
</t>
|
||||
</templates>
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
import { getCSSVariableValue } from "@html_editor/utils/formatting";
|
||||
import { onWillStart } from "@odoo/owl";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { formatFloat } from "@web/views/fields/formatters";
|
||||
import { GaugeField, gaugeField } from "@web/views/fields/gauge/gauge_field";
|
||||
|
||||
export class SkillMatchGaugeField extends GaugeField {
|
||||
static template = "hr_recruitment.SkillMatchGaugeField";
|
||||
|
||||
setup() {
|
||||
super.setup();
|
||||
|
||||
this.orm = useService("orm");
|
||||
|
||||
onWillStart(async () => {
|
||||
const matching_job_id = this.props.record.evalContext.context.matching_job_id;
|
||||
if (matching_job_id) {
|
||||
const matching_job = await this.orm.read("hr.job", [matching_job_id], ["name"]);
|
||||
this.matching_job_name = matching_job[0].name;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get formattedValue() {
|
||||
return formatFloat(this.props.record.data[this.props.name], {
|
||||
humanReadable: true,
|
||||
decimals: 0,
|
||||
});
|
||||
}
|
||||
|
||||
renderChart() {
|
||||
const gaugeValue = this.props.record.data[this.props.name];
|
||||
let maxValue = this.props.maxValueField
|
||||
? this.props.record.data[this.props.maxValueField]
|
||||
: this.props.maxValue;
|
||||
|
||||
const fgColor =
|
||||
gaugeValue > maxValue
|
||||
? getCSSVariableValue("success", getComputedStyle(document.documentElement))
|
||||
: getCSSVariableValue("primary", getComputedStyle(document.documentElement));
|
||||
maxValue = Math.max(gaugeValue, maxValue);
|
||||
if (gaugeValue === 0 && maxValue === 0) {
|
||||
maxValue = 1;
|
||||
}
|
||||
const config = {
|
||||
type: "doughnut",
|
||||
data: {
|
||||
datasets: [
|
||||
{
|
||||
data: [gaugeValue, maxValue - gaugeValue],
|
||||
backgroundColor: [fgColor, "#dddddd"],
|
||||
label: this.title,
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
circumference: 180,
|
||||
rotation: 270,
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
cutout: "50%",
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: "dataset",
|
||||
},
|
||||
plugins: {
|
||||
title: {
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
displayColors: false,
|
||||
callbacks: {
|
||||
title: (tooltipItem) => false,
|
||||
label: (tooltipItem) =>
|
||||
tooltipItem.dataIndex === 0 &&
|
||||
_t("This score reflects skills and degree match"),
|
||||
},
|
||||
},
|
||||
},
|
||||
aspectRatio: 2,
|
||||
},
|
||||
};
|
||||
this.chart = new Chart(this.canvasRef.el, config);
|
||||
}
|
||||
}
|
||||
|
||||
export const skillMatchGaugeField = {
|
||||
...gaugeField,
|
||||
component: SkillMatchGaugeField,
|
||||
};
|
||||
|
||||
registry.category("fields").add("skill_match_gauge_field", skillMatchGaugeField);
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="hr_recruitment.SkillMatchGaugeField">
|
||||
<div class="oe_gauge position-relative pt-3">
|
||||
<canvas t-ref="canvas"/>
|
||||
<span class="o_gauge_value position-absolute start-0 end-0 bottom-0 text-center fs-2 fw-bolder">
|
||||
<t t-esc="this.formattedValue"/>%
|
||||
</span>
|
||||
</div>
|
||||
<p class="text-center text-uppercase fw-bolder mt-2 mb-0">
|
||||
Job Position Matching
|
||||
</p>
|
||||
<p class="text-center text-uppercase fw-bolder mt-0 mb-2"
|
||||
t-if="this.matching_job_name">
|
||||
<t t-esc="this.matching_job_name"/>
|
||||
</p>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
.o_applicant_skills .skills_header {
|
||||
/* Margin and padding classes are added to .skills_header to work in both HR and Recruitment contexts. */
|
||||
/* However, the combined spacing is too much for either scenario, so one is removed depending on context. */
|
||||
margin: 0 !important;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue