Merge branch 'ESS-LLP-staffing' into enterprise_sprint
This commit is contained in:
commit
2b16712c83
@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Job Opening', {
|
||||
designation: function(frm) {
|
||||
if(frm.doc.designation && frm.doc.company){
|
||||
frappe.call({
|
||||
"method": "erpnext.hr.doctype.staffing_plan.staffing_plan.get_active_staffing_plan_and_vacancies",
|
||||
args: {
|
||||
company: frm.doc.company,
|
||||
designation: frm.doc.designation,
|
||||
department: frm.doc.department,
|
||||
date: frappe.datetime.now_date() // ToDo - Date in Job Opening?
|
||||
},
|
||||
callback: function (data) {
|
||||
if(data.message){
|
||||
frm.set_value('staffing_plan', data.message[0]);
|
||||
frm.set_value('planned_vacancies', data.message[1]);
|
||||
} else {
|
||||
frm.set_value('staffing_plan', "");
|
||||
frm.set_value('planned_vacancies', 0);
|
||||
frappe.show_alert({
|
||||
indicator: 'orange',
|
||||
message: __('No Staffing Plans found for this Designation')
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else{
|
||||
frm.set_value('staffing_plan', "");
|
||||
frm.set_value('planned_vacancies', 0);
|
||||
}
|
||||
},
|
||||
company: function(frm) {
|
||||
frm.set_value('designation', "");
|
||||
}
|
||||
});
|
@ -41,7 +41,6 @@
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
@ -73,7 +72,6 @@
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
@ -104,7 +102,6 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
@ -134,7 +131,6 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
@ -166,7 +162,6 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
@ -198,7 +193,6 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
@ -224,13 +218,43 @@
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "staffing_plan",
|
||||
"fieldname": "planned_vacancies",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Planned number of Positions",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
@ -260,7 +284,6 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
@ -291,7 +314,6 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
@ -323,7 +345,6 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
@ -354,7 +375,6 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
@ -369,7 +389,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-04-13 18:52:56.109392",
|
||||
"modified": "2018-05-07 14:16:50.300247",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Job Opening",
|
||||
@ -377,6 +397,7 @@
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
@ -396,6 +417,7 @@
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
|
@ -8,6 +8,7 @@ import frappe
|
||||
|
||||
from frappe.website.website_generator import WebsiteGenerator
|
||||
from frappe import _
|
||||
from erpnext.hr.doctype.staffing_plan.staffing_plan import get_current_employee_count, get_active_staffing_plan_and_vacancies
|
||||
|
||||
class JobOpening(WebsiteGenerator):
|
||||
website = frappe._dict(
|
||||
@ -19,6 +20,33 @@ class JobOpening(WebsiteGenerator):
|
||||
def validate(self):
|
||||
if not self.route:
|
||||
self.route = frappe.scrub(self.job_title).replace('_', '-')
|
||||
self.validate_current_vacancies()
|
||||
|
||||
def validate_current_vacancies(self):
|
||||
if not self.staffing_plan:
|
||||
vacancies = get_active_staffing_plan_and_vacancies(self.company,
|
||||
self.designation, self.department)
|
||||
if vacancies:
|
||||
self.staffing_plan = vacancies[0]
|
||||
self.planned_vacancies = vacancies[1]
|
||||
elif not self.planned_vacancies:
|
||||
planned_vacancies = frappe.db.sql("""
|
||||
select vacancies from `tabStaffing Plan Detail`
|
||||
where parent=%s and designation=%s""", (self.staffing_plan, self.designation))
|
||||
self.planned_vacancies = planned_vacancies[0][0] if planned_vacancies else None
|
||||
|
||||
if self.staffing_plan and self.planned_vacancies:
|
||||
staffing_plan_company = frappe.db.get_value("Staffing Plan", self.staffing_plan, "company")
|
||||
lft, rgt = frappe.db.get_value("Company", staffing_plan_company, ["lft", "rgt"])
|
||||
|
||||
current_count = get_current_employee_count(self.designation, staffing_plan_company)
|
||||
current_count+= frappe.db.sql("""select count(*) from `tabJob Opening` \
|
||||
where designation=%s and status='Open'
|
||||
and company in (select name from tabCompany where lft>=%s and rgt<=%s)
|
||||
""", (self.designation, lft, rgt))[0][0]
|
||||
|
||||
if self.planned_vacancies <= current_count:
|
||||
frappe.throw(_("Job Openings for designation {0} and company {1} already opened or hiring completed as per Staffing Plan {2}".format(self.designation, staffing_plan_company, self.staffing_plan)))
|
||||
|
||||
def get_context(self, context):
|
||||
context.parents = [{'route': 'jobs', 'title': _('All Jobs') }]
|
||||
|
@ -2,7 +2,92 @@
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Staffing Plan', {
|
||||
refresh: function(frm) {
|
||||
|
||||
setup: function(frm) {
|
||||
frm.set_query("designation", "staffing_details", function() {
|
||||
let designations = [];
|
||||
$.each(frm.doc.staffing_details, function(index, staff_detail) {
|
||||
if(staff_detail.designation){
|
||||
designations.push(staff_detail.designation)
|
||||
}
|
||||
})
|
||||
// Filter out designations already selected in Staffing Plan Detail
|
||||
return {
|
||||
filters: [
|
||||
['Designation', 'name', 'not in', designations],
|
||||
]
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
frappe.ui.form.on('Staffing Plan Detail', {
|
||||
designation: function(frm, cdt, cdn) {
|
||||
let child = locals[cdt][cdn]
|
||||
if(frm.doc.company && child.designation){
|
||||
frappe.call({
|
||||
"method": "erpnext.hr.doctype.staffing_plan.staffing_plan.get_current_employee_count",
|
||||
args: {
|
||||
designation: child.designation,
|
||||
company: frm.doc.company
|
||||
},
|
||||
callback: function (data) {
|
||||
if(data.message){
|
||||
frappe.model.set_value(cdt, cdn, 'current_count', data.message);
|
||||
}
|
||||
else{ // No employees for this designation
|
||||
frappe.model.set_value(cdt, cdn, 'current_count', 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
number_of_positions: function(frm, cdt, cdn) {
|
||||
set_vacancies(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
current_count: function(frm, cdt, cdn) {
|
||||
set_vacancies(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
estimated_cost_per_position: function(frm, cdt, cdn) {
|
||||
let child = locals[cdt][cdn];
|
||||
set_total_estimated_cost(frm, cdt, cdn);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
var set_vacancies = function(frm, cdt, cdn) {
|
||||
let child = locals[cdt][cdn]
|
||||
if(child.number_of_positions) {
|
||||
frappe.model.set_value(cdt, cdn, 'vacancies', child.number_of_positions - child.current_count);
|
||||
}
|
||||
else{
|
||||
frappe.model.set_value(cdt, cdn, 'vacancies', 0);
|
||||
}
|
||||
set_total_estimated_cost(frm, cdt, cdn);
|
||||
}
|
||||
|
||||
// Note: Estimated Cost is calculated on number of Vacancies
|
||||
var set_total_estimated_cost = function(frm, cdt, cdn) {
|
||||
let child = locals[cdt][cdn]
|
||||
if(child.number_of_positions && child.estimated_cost_per_position) {
|
||||
frappe.model.set_value(cdt, cdn, 'total_estimated_cost', child.vacancies * child.estimated_cost_per_position);
|
||||
}
|
||||
else {
|
||||
frappe.model.set_value(cdt, cdn, 'total_estimated_cost', 0);
|
||||
}
|
||||
set_total_estimated_budget(frm);
|
||||
};
|
||||
|
||||
var set_total_estimated_budget = function(frm) {
|
||||
let estimated_budget = 0.0
|
||||
if(frm.doc.staffing_details) {
|
||||
$.each(frm.doc.staffing_details, function(index, staff_detail) {
|
||||
if(staff_detail.total_estimated_cost){
|
||||
estimated_budget += staff_detail.total_estimated_cost
|
||||
}
|
||||
})
|
||||
frm.set_value('total_estimated_budget', estimated_budget);
|
||||
}
|
||||
}
|
||||
|
@ -268,6 +268,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0.00",
|
||||
"fieldname": "total_estimated_budget",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
@ -284,7 +285,7 @@
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
@ -335,7 +336,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-04-13 18:45:16.729979",
|
||||
"modified": "2018-04-18 19:10:34.394249",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Staffing Plan",
|
||||
|
@ -5,6 +5,62 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe import _
|
||||
from frappe.utils import getdate, nowdate
|
||||
|
||||
class StaffingPlan(Document):
|
||||
pass
|
||||
def validate(self):
|
||||
# Validate Dates
|
||||
if self.from_date and self.to_date and self.from_date > self.to_date:
|
||||
frappe.throw(_("From Date cannot be greater than To Date"))
|
||||
|
||||
# Validate if any submitted Staffing Plan exist for Designations in this plan
|
||||
# and spd.vacancies>0 ?
|
||||
for detail in self.get("staffing_details"):
|
||||
overlap = (frappe.db.sql("""select spd.parent \
|
||||
from `tabStaffing Plan Detail` spd join `tabStaffing Plan` sp on spd.parent=sp.name \
|
||||
where spd.designation='{0}' and sp.docstatus=1 \
|
||||
and sp.to_date >= '{1}' and sp.from_date <='{2}'"""
|
||||
.format(detail.designation, self.from_date, self.to_date)))
|
||||
|
||||
if overlap and overlap [0][0]:
|
||||
frappe.throw(_("Staffing Plan {0} already exist for designation {1}"
|
||||
.format(overlap[0][0], detail.designation)))
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_current_employee_count(designation, company):
|
||||
if not designation:
|
||||
return False
|
||||
|
||||
lft, rgt = frappe.db.get_value("Company", company, ["lft", "rgt"])
|
||||
employee_count = frappe.db.sql("""select count(*) from `tabEmployee`
|
||||
where designation = %s and status='Active'
|
||||
and company in (select name from tabCompany where lft>=%s and rgt<=%s)
|
||||
""", (designation, lft, rgt))[0][0]
|
||||
return employee_count
|
||||
|
||||
def get_active_staffing_plan_and_vacancies(company, designation, department=None, date=getdate(nowdate())):
|
||||
if not company or not designation:
|
||||
frappe.throw(_("Please select Company and Designation"))
|
||||
|
||||
conditions = ""
|
||||
if(department): #Department is an optional field
|
||||
conditions += " and sp.department='{0}'".format(frappe.db.escape(department))
|
||||
|
||||
if(date): #ToDo: Date should be mandatory?
|
||||
conditions += " and '{0}' between sp.from_date and sp.to_date".format(date)
|
||||
|
||||
staffing_plan = frappe.db.sql("""
|
||||
select sp.name, spd.vacancies
|
||||
from `tabStaffing Plan Detail` spd join `tabStaffing Plan` sp on spd.parent=sp.name
|
||||
where company=%s and spd.designation=%s and sp.docstatus=1 {0}
|
||||
""".format(conditions), (company, designation))
|
||||
|
||||
if not staffing_plan:
|
||||
parent_company = frappe.db.get_value("Company", company, "parent_company")
|
||||
if parent_company:
|
||||
staffing_plan = get_active_staffing_plan_and_vacancies(parent_company,
|
||||
designation, department, date)
|
||||
|
||||
# Only a signle staffing plan can be active for a designation on given date
|
||||
return staffing_plan[0] if staffing_plan else None
|
||||
|
@ -75,68 +75,6 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "current_count",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Current Count",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "vacancies",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Vacancies",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@ -190,6 +128,36 @@
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_5",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
@ -198,6 +166,68 @@
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "current_count",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Current Count",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "vacancies",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Vacancies",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
@ -210,7 +240,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-04-13 18:39:52.783341",
|
||||
"modified": "2018-04-15 16:09:12.622186",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Staffing Plan Detail",
|
||||
|
Loading…
Reference in New Issue
Block a user