Job Opening - get planned opening, validate vacancies by Staffing Plan
diff --git a/erpnext/hr/doctype/job_opening/job_opening.js b/erpnext/hr/doctype/job_opening/job_opening.js
index e69de29..b024310 100644
--- a/erpnext/hr/doctype/job_opening/job_opening.js
+++ b/erpnext/hr/doctype/job_opening/job_opening.js
@@ -0,0 +1,39 @@
+// 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', "");
+  }
+});
diff --git a/erpnext/hr/doctype/job_opening/job_opening.json b/erpnext/hr/doctype/job_opening/job_opening.json
index de15114..a877119 100644
--- a/erpnext/hr/doctype/job_opening/job_opening.json
+++ b/erpnext/hr/doctype/job_opening/job_opening.json
@@ -224,7 +224,38 @@
    "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, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "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, 
@@ -369,7 +400,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2018-04-13 18:52:56.109392", 
+ "modified": "2018-04-18 19:27:15.004385", 
  "modified_by": "Administrator", 
  "module": "HR", 
  "name": "Job Opening", 
diff --git a/erpnext/hr/doctype/job_opening/job_opening.py b/erpnext/hr/doctype/job_opening/job_opening.py
index 60c911a..d3d662a 100644
--- a/erpnext/hr/doctype/job_opening/job_opening.py
+++ b/erpnext/hr/doctype/job_opening/job_opening.py
@@ -8,6 +8,7 @@
 
 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(
@@ -20,6 +21,20 @@
 		if not self.route:
 			self.route = frappe.scrub(self.job_title).replace('_', '-')
 
+		if self.staffing_plan:
+			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]
+
+		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)))
+
 	def get_context(self, context):
 		context.parents = [{'route': 'jobs', 'title': _('All Jobs') }]