diff --git a/erpnext/docs/assets/img/human-resources/staffing-plan-detail.png b/erpnext/docs/assets/img/human-resources/staffing-plan-detail.png new file mode 100644 index 0000000000..63532b7a73 Binary files /dev/null and b/erpnext/docs/assets/img/human-resources/staffing-plan-detail.png differ diff --git a/erpnext/docs/assets/img/human-resources/staffing-plan.png b/erpnext/docs/assets/img/human-resources/staffing-plan.png new file mode 100644 index 0000000000..f6550290ee Binary files /dev/null and b/erpnext/docs/assets/img/human-resources/staffing-plan.png differ diff --git a/erpnext/docs/user/manual/en/human-resources/staffing-plan.md b/erpnext/docs/user/manual/en/human-resources/staffing-plan.md new file mode 100644 index 0000000000..d16a1ec0ce --- /dev/null +++ b/erpnext/docs/user/manual/en/human-resources/staffing-plan.md @@ -0,0 +1,18 @@ +# Staffing Plan +Staffing Plan helps you to plan human resource recruitments for your Company. ERPNext allows you to do this at a group company level helping you efficiently plan and budget new hirings for a period. Job Openings can only be created as per the number of vacancies and budget as per the active Staffing Plan. + +> Human Resources > Setup > Staffing Plan > New Staffing Plan + +Staffing Plan + +- **Designation:** The designations for which you are creating the Staffing Plan. +- **Number of Positions:** The number of positions you plan to recruit for between the Staffing Plan from and to dates. +- **Current Count:** This is the number of Employees already hired for the Designation. +- **Vacancies:** The number of vacancies based on the Number of Positions you wish to recruit and the current Employee count. +- **Estimated Cost Per Position:** You can specify the cost to company per position so that hiring officials can stick to the budget. + +Staffing Plan Detail + +**Total Estimated Budget** Once you enter the recruitment plan for all the designations, Staffing Plan will draw up the total estimated budget. diff --git a/erpnext/hr/doctype/job_opening/job_opening.js b/erpnext/hr/doctype/job_opening/job_opening.js index 7b0e447a9e..b303b2451d 100644 --- a/erpnext/hr/doctype/job_opening/job_opening.js +++ b/erpnext/hr/doctype/job_opening/job_opening.js @@ -14,7 +14,7 @@ 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", + "method": "erpnext.hr.doctype.staffing_plan.staffing_plan.get_active_staffing_plan_details", args: { company: frm.doc.company, designation: frm.doc.designation, @@ -23,8 +23,8 @@ frappe.ui.form.on('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('staffing_plan', data.message[0].name); + frm.set_value('planned_vacancies', data.message[0].vacancies); } else { frm.set_value('staffing_plan', ""); frm.set_value('planned_vacancies', 0); diff --git a/erpnext/hr/doctype/job_opening/job_opening.py b/erpnext/hr/doctype/job_opening/job_opening.py index b579d6f24a..cfe6290049 100644 --- a/erpnext/hr/doctype/job_opening/job_opening.py +++ b/erpnext/hr/doctype/job_opening/job_opening.py @@ -8,7 +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 +from erpnext.hr.doctype.staffing_plan.staffing_plan import get_designation_counts, get_active_staffing_plan_details class JobOpening(WebsiteGenerator): website = frappe._dict( @@ -24,11 +24,11 @@ class JobOpening(WebsiteGenerator): def validate_current_vacancies(self): if not self.staffing_plan: - vacancies = get_active_staffing_plan_and_vacancies(self.company, + staffing_plan = get_active_staffing_plan_details(self.company, self.designation, self.department) - if vacancies: - self.staffing_plan = vacancies[0] - self.planned_vacancies = vacancies[1] + if staffing_plan: + self.staffing_plan = staffing_plan[0].name + self.planned_vacancies = staffing_plan[0].vacancies elif not self.planned_vacancies: planned_vacancies = frappe.db.sql(""" select vacancies from `tabStaffing Plan Detail` @@ -39,14 +39,13 @@ class JobOpening(WebsiteGenerator): 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] + designation_counts = get_designation_counts(self.designation, self.company) + current_count = designation_counts['employee_count'] + designation_counts['job_openings'] 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))) + frappe.throw(_("Job Openings for designation {0} already open \ + or hiring completed as per Staffing Plan {1}" + .format(self.designation, 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 ca57d9f19d..4fbc6b3089 100644 --- a/erpnext/hr/doctype/staffing_plan/staffing_plan.js +++ b/erpnext/hr/doctype/staffing_plan/staffing_plan.js @@ -33,17 +33,22 @@ frappe.ui.form.on('Staffing Plan Detail', { 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", + "method": "erpnext.hr.doctype.staffing_plan.staffing_plan.get_designation_counts", args: { designation: child.designation, company: frm.doc.company }, callback: function (data) { if(data.message){ - frappe.model.set_value(cdt, cdn, 'current_count', data.message); + frappe.model.set_value(cdt, cdn, 'current_count', data.message.employee_count); + frappe.model.set_value(cdt, cdn, 'current_openings', data.message.job_openings); + if (child.number_of_positions < (data.message.employee_count + data.message.job_openings)){ + frappe.model.set_value(cdt, cdn, 'number_of_positions', data.message.employee_count + data.message.job_openings); + } } else{ // No employees for this designation frappe.model.set_value(cdt, cdn, 'current_count', 0); + frappe.model.set_value(cdt, cdn, 'current_openings', 0); } } }); @@ -67,19 +72,25 @@ frappe.ui.form.on('Staffing Plan Detail', { 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); + if (child.number_of_positions < (child.current_count + child.current_openings)){ + frappe.throw(__("Number of positions cannot be less then current count of employees")) + } + + if(child.number_of_positions > 0) { + frappe.model.set_value(cdt, cdn, 'vacancies', child.number_of_positions - (child.current_count + child.current_openings)); } 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 +// Validate for > 0 ? var set_total_estimated_cost = function(frm, cdt, cdn) { let child = locals[cdt][cdn] - if(child.number_of_positions && child.estimated_cost_per_position) { + if(child.vacancies > 0 && child.estimated_cost_per_position) { frappe.model.set_value(cdt, cdn, 'total_estimated_cost', child.vacancies * child.estimated_cost_per_position); } else { diff --git a/erpnext/hr/doctype/staffing_plan/staffing_plan.json b/erpnext/hr/doctype/staffing_plan/staffing_plan.json index 229cc05ddd..9576bc306a 100644 --- a/erpnext/hr/doctype/staffing_plan/staffing_plan.json +++ b/erpnext/hr/doctype/staffing_plan/staffing_plan.json @@ -15,6 +15,7 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -47,6 +48,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -79,6 +81,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -109,6 +112,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -132,7 +136,7 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, "translatable": 0, @@ -140,6 +144,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -163,7 +168,7 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, "translatable": 0, @@ -171,6 +176,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -202,6 +208,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -234,6 +241,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -264,6 +272,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -296,6 +305,7 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -336,7 +346,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-04-18 19:10:34.394249", + "modified": "2018-05-28 18:30:27.041395", "modified_by": "Administrator", "module": "HR", "name": "Staffing Plan", diff --git a/erpnext/hr/doctype/staffing_plan/staffing_plan.py b/erpnext/hr/doctype/staffing_plan/staffing_plan.py index 37ff5cbc90..e1a5f8ccb3 100644 --- a/erpnext/hr/doctype/staffing_plan/staffing_plan.py +++ b/erpnext/hr/doctype/staffing_plan/staffing_plan.py @@ -6,7 +6,7 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document from frappe import _ -from frappe.utils import getdate, nowdate +from frappe.utils import getdate, nowdate, cint, flt class StaffingPlan(Document): def validate(self): @@ -14,32 +14,128 @@ class StaffingPlan(Document): 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))) + self.total_estimated_budget = 0 - if overlap and overlap [0][0]: - frappe.throw(_("Staffing Plan {0} already exist for designation {1}" - .format(overlap[0][0], detail.designation))) + for detail in self.get("staffing_details"): + self.validate_overlap(detail) + self.validate_with_subsidiary_plans(detail) + self.validate_with_parent_plan(detail) + + #Set readonly fields + designation_counts = get_designation_counts(detail.designation, self.company) + detail.current_count = designation_counts['employee_count'] + detail.current_openings = designation_counts['job_openings'] + + if detail.number_of_positions < (detail.current_count + detail.current_openings): + frappe.throw(_("Number of positions cannot be less then current count of employees")) + elif detail.number_of_positions > 0: + detail.vacancies = detail.number_of_positions - (detail.current_count + detail.current_openings) + if detail.vacancies > 0 and detail.estimated_cost_per_position: + detail.total_estimated_cost = detail.vacancies * detail.estimated_cost_per_position + else: detail.total_estimated_cost = 0 + else: detail.vacancies = detail.number_of_positions = detail.total_estimated_cost = 0 + self.total_estimated_budget += detail.total_estimated_cost + + def validate_overlap(self, staffing_plan_detail): + # Validate if any submitted Staffing Plan exist for any Designations in this plan + # and spd.vacancies>0 ? + overlap = frappe.db.sql("""select spd.parent + from `tabStaffing Plan Detail` spd join `tabStaffing Plan` sp on spd.parent=sp.name + where spd.designation=%s and sp.docstatus=1 + and sp.to_date >= %s and sp.from_date <= %s and sp.company = %s + """, (staffing_plan_detail.designation, self.from_date, self.to_date, self.company)) + if overlap and overlap [0][0]: + frappe.throw(_("Staffing Plan {0} already exist for designation {1}" + .format(overlap[0][0], staffing_plan_detail.designation))) + + def validate_with_parent_plan(self, staffing_plan_detail): + if not frappe.db.get_value("Company", self.company, "parent_company"): + return # No parent, nothing to validate + + # Get staffing plan applicable for the company (Parent Company) + parent_plan_details = get_active_staffing_plan_details(self.company, staffing_plan_detail.designation) + if not parent_plan_details: + return #no staffing plan for any parent Company in herarchy + + # Fetch parent company which owns the staffing plan. NOTE: Parent could be higher up in the heirarchy + parent_company = frappe.db.get_value("Staffing Plan", parent_plan_details[0].name, "company") + + # Parent plan available, validate with parent, siblings as well as children of staffing plan Company + if staffing_plan_detail.vacancies > cint(parent_plan_details[0].vacancies) or \ + staffing_plan_detail.total_estimated_cost > flt(parent_plan_details[0].total_estimated_cost): + frappe.throw(_("You can only plan for upto {0} vacancies and budget {1} \ + for {2} as per staffing plan {3} for parent company {4}" + .format(cint(parent_plan_details[0].vacancies), + parent_plan_details[0].total_estimated_cost, + frappe.bold(staffing_plan_detail.designation), + parent_plan_details[0].name, + parent_company))) + + #Get vacanices already planned for all companies down the herarchy of Parent Company + lft, rgt = frappe.db.get_value("Company", parent_company, ["lft", "rgt"]) + all_sibling_details = frappe.db.sql("""select sum(spd.vacancies) as vacancies, + sum(spd.total_estimated_cost) as total_estimated_cost + from `tabStaffing Plan Detail` spd join `tabStaffing Plan` sp on spd.parent=sp.name + where spd.designation=%s and sp.docstatus=1 + and sp.to_date >= %s and sp.from_date <=%s + and sp.company in (select name from tabCompany where lft > %s and rgt < %s) + """, (staffing_plan_detail.designation, self.from_date, self.to_date, lft, rgt), as_dict = 1)[0] + + if (cint(parent_plan_details[0].vacancies) < \ + (staffing_plan_detail.vacancies + cint(all_sibling_details.vacancies))) or \ + (flt(parent_plan_details[0].total_estimated_cost) < \ + (staffing_plan_detail.total_estimated_cost + flt(all_sibling_details.total_estimated_cost))): + frappe.throw(_("{0} vacancies and {1} budget for {2} already planned for subsidiary companies of {3}. \ + You can only plan for upto {4} vacancies and and budget {5} as per staffing plan {6} for parent company {3}" + .format(cint(all_sibling_details.vacancies), + all_sibling_details.total_estimated_cost, + frappe.bold(staffing_plan_detail.designation), + parent_company, + cint(parent_plan_details[0].vacancies), + parent_plan_details[0].total_estimated_cost, + parent_plan_details[0].name))) + + def validate_with_subsidiary_plans(self, staffing_plan_detail): + #Valdate this plan with all child company plan + children_details = frappe.db.sql("""select sum(spd.vacancies) as vacancies, + sum(spd.total_estimated_cost) as total_estimated_cost + from `tabStaffing Plan Detail` spd join `tabStaffing Plan` sp on spd.parent=sp.name + where spd.designation=%s and sp.docstatus=1 + and sp.to_date >= %s and sp.from_date <=%s + and sp.company in (select name from tabCompany where parent_company = %s) + """, (staffing_plan_detail.designation, self.from_date, self.to_date, self.company), as_dict = 1)[0] + + if children_details and \ + staffing_plan_detail.vacancies < cint(children_details.vacancies) or \ + staffing_plan_detail.total_estimated_cost < flt(children_details.total_estimated_cost): + frappe.throw(_("Subsidiary companies have already planned for {1} vacancies at a budget of {2}. \ + Staffing Plan for {0} should allocate more vacancies and budget for {3} than planned for its subsidiary companies" + .format(self.company, + cint(children_details.vacancies), + children_details.total_estimated_cost, + frappe.bold(staffing_plan_detail.designation)))) @frappe.whitelist() -def get_current_employee_count(designation, company): +def get_designation_counts(designation, company): if not designation: return False + employee_counts_dict = {} lft, rgt = frappe.db.get_value("Company", company, ["lft", "rgt"]) - employee_count = frappe.db.sql("""select count(*) from `tabEmployee` + employee_counts_dict["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())): + employee_counts_dict['job_openings'] = 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) + """, (designation, lft, rgt))[0][0] + + return employee_counts_dict + +@frappe.whitelist() +def get_active_staffing_plan_details(company, designation, department=None, date=getdate(nowdate())): if not company or not designation: frappe.throw(_("Please select Company and Designation")) @@ -51,16 +147,16 @@ def get_active_staffing_plan_and_vacancies(company, designation, department=None conditions += " and '{0}' between sp.from_date and sp.to_date".format(date) staffing_plan = frappe.db.sql(""" - select sp.name, spd.vacancies + select sp.name, spd.vacancies, spd.total_estimated_cost 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)) + """.format(conditions), (company, designation), as_dict = 1) 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, + staffing_plan = get_active_staffing_plan_details(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 + # Only a single staffing plan can be active for a designation on given date + return staffing_plan if staffing_plan else None diff --git a/erpnext/hr/doctype/staffing_plan_detail/staffing_plan_detail.json b/erpnext/hr/doctype/staffing_plan_detail/staffing_plan_detail.json index eb77b43914..f1d16096c0 100644 --- a/erpnext/hr/doctype/staffing_plan_detail/staffing_plan_detail.json +++ b/erpnext/hr/doctype/staffing_plan_detail/staffing_plan_detail.json @@ -1,258 +1,297 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2018-04-13 18:04:20.978931", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2018-04-13 18:04:20.978931", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "designation", - "fieldtype": "Link", - "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": "Designation", - "length": 0, - "no_copy": 0, - "options": "Designation", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "designation", + "fieldtype": "Link", + "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": "Designation", + "length": 0, + "no_copy": 0, + "options": "Designation", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "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": "number_of_positions", - "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": "Number Of Positions", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "number_of_positions", + "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": "Number Of Positions", + "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": "estimated_cost_per_position", - "fieldtype": "Currency", - "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": "Estimated Cost Per Position", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "estimated_cost_per_position", + "fieldtype": "Currency", + "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": "Estimated Cost Per Position", + "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": "total_estimated_cost", - "fieldtype": "Currency", - "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": "Total Estimated Cost", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 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, + "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, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 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": 0, + "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": "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "current_openings", + "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": "Current Openings", + "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 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, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2018-04-15 16:09:12.622186", - "modified_by": "Administrator", - "module": "HR", - "name": "Staffing Plan Detail", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "total_estimated_cost", + "fieldtype": "Currency", + "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": "Total Estimated Cost", + "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, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 1, + "max_attachments": 0, + "modified": "2018-06-01 17:03:38.020993", + "modified_by": "Administrator", + "module": "HR", + "name": "Staffing Plan Detail", + "name_case": "", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, "track_seen": 0 -} \ No newline at end of file +}