From 3881e98000cdf69f72f5d0c2e190b51b3a7ad06c Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 8 May 2018 18:36:14 +0530 Subject: [PATCH] Staffing plan for group company --- erpnext/hr/doctype/job_opening/job_opening.js | 45 +++++++++---------- erpnext/hr/doctype/job_opening/job_opening.py | 35 ++++++++++----- .../hr/doctype/staffing_plan/staffing_plan.js | 5 ++- .../hr/doctype/staffing_plan/staffing_plan.py | 37 +++++++++------ 4 files changed, 73 insertions(+), 49 deletions(-) diff --git a/erpnext/hr/doctype/job_opening/job_opening.js b/erpnext/hr/doctype/job_opening/job_opening.js index b024310339..960f5b3c65 100644 --- a/erpnext/hr/doctype/job_opening/job_opening.js +++ b/erpnext/hr/doctype/job_opening/job_opening.js @@ -2,38 +2,37 @@ // For license information, please see license.txt frappe.ui.form.on('Job Opening', { - designation: function(frm) { - if(frm.doc.designation && frm.doc.company){ + 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? + 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]); + 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); - 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', ""); - } + else{ + frm.set_value('staffing_plan', ""); + frm.set_value('planned_vacancies', 0); + } + }, + company: function(frm) { + frm.set_value('designation', ""); + } }); diff --git a/erpnext/hr/doctype/job_opening/job_opening.py b/erpnext/hr/doctype/job_opening/job_opening.py index d3d662a743..b579d6f24a 100644 --- a/erpnext/hr/doctype/job_opening/job_opening.py +++ b/erpnext/hr/doctype/job_opening/job_opening.py @@ -20,20 +20,33 @@ class JobOpening(WebsiteGenerator): def validate(self): if not self.route: self.route = frappe.scrub(self.job_title).replace('_', '-') - - if self.staffing_plan: - self.validate_current_vacancies() + self.validate_current_vacancies() def validate_current_vacancies(self): - current_count = get_current_employee_count(self.designation) - current_count+= frappe.db.sql("""select count(*) from `tabJob Opening` \ - where designation = '{0}' and status='Open'""".format(self.designation))[0][0] + 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 - vacancies = get_active_staffing_plan_and_vacancies(self.company, self.designation, self.department)[1] - # set staffing_plan too? - if vacancies and vacancies <= current_count: - frappe.throw(_("Job Openings for designation {0} already opened or hiring \ - completed as per Staffing Plan {1}".format(self.designation, self.staffing_plan))) + 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') }] diff --git a/erpnext/hr/doctype/staffing_plan/staffing_plan.js b/erpnext/hr/doctype/staffing_plan/staffing_plan.js index 17f03e67bf..1c1a720088 100644 --- a/erpnext/hr/doctype/staffing_plan/staffing_plan.js +++ b/erpnext/hr/doctype/staffing_plan/staffing_plan.js @@ -23,11 +23,12 @@ frappe.ui.form.on('Staffing Plan', { frappe.ui.form.on('Staffing Plan Detail', { designation: function(frm, cdt, cdn) { let child = locals[cdt][cdn] - if(child.designation){ + if(frm.doc.company && child.designation){ frappe.call({ "method": "erpnext.hr.doctype.staffing_plan.staffing_plan.get_current_employee_count", args: { - designation: child.designation + designation: child.designation, + company: frm.doc.company }, callback: function (data) { if(data.message){ diff --git a/erpnext/hr/doctype/staffing_plan/staffing_plan.py b/erpnext/hr/doctype/staffing_plan/staffing_plan.py index 588e536b42..37ff5cbc90 100644 --- a/erpnext/hr/doctype/staffing_plan/staffing_plan.py +++ b/erpnext/hr/doctype/staffing_plan/staffing_plan.py @@ -20,36 +20,47 @@ class StaffingPlan(Document): 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))) + 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.throw(_("Staffing Plan {0} already exist for designation {1}" + .format(overlap[0][0], detail.designation))) @frappe.whitelist() -def get_current_employee_count(designation): +def get_current_employee_count(designation, company): if not designation: return False - employee_count = frappe.db.sql("""select count(*) from `tabEmployee` where \ - designation = '{0}' and status='Active'""".format(designation))[0][0] + + 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 -@frappe.whitelist() 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 = "spd.designation='{0}' and sp.docstatus=1 and \ - sp.company='{1}'".format(designation, company) - + conditions = "" if(department): #Department is an optional field - conditions += " and sp.department='{0}'".format(department) + 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 spd.parent, spd.vacancies \ + 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 {0}""".format(conditions)) + 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 False + return staffing_plan[0] if staffing_plan else None