Merge pull request #14061 from rohitwaghchaure/budget_validation_enhance_in_mr_po

[Enhance] Budget validation on material request, purchase order
diff --git a/erpnext/accounts/doctype/budget/budget.json b/erpnext/accounts/doctype/budget/budget.json
index 45f549e..7c273ee 100644
--- a/erpnext/accounts/doctype/budget/budget.json
+++ b/erpnext/accounts/doctype/budget/budget.json
@@ -1,5 +1,6 @@
 {
  "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
  "allow_import": 1, 
  "allow_rename": 0, 
  "beta": 0, 
@@ -11,6 +12,7 @@
  "editable_grid": 1, 
  "fields": [
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -23,7 +25,7 @@
    "ignore_xss_filter": 0, 
    "in_filter": 0, 
    "in_global_search": 0, 
-   "in_list_view": 0, 
+   "in_list_view": 1, 
    "in_standard_filter": 1, 
    "label": "Budget Against", 
    "length": 0, 
@@ -39,9 +41,11 @@
    "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, 
@@ -53,7 +57,7 @@
    "ignore_xss_filter": 0, 
    "in_filter": 0, 
    "in_global_search": 0, 
-   "in_list_view": 0, 
+   "in_list_view": 1, 
    "in_standard_filter": 1, 
    "label": "Company", 
    "length": 0, 
@@ -69,9 +73,11 @@
    "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, 
@@ -100,9 +106,11 @@
    "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, 
@@ -131,9 +139,11 @@
    "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, 
@@ -145,7 +155,7 @@
    "ignore_xss_filter": 0, 
    "in_filter": 0, 
    "in_global_search": 0, 
-   "in_list_view": 0, 
+   "in_list_view": 1, 
    "in_standard_filter": 1, 
    "label": "Fiscal Year", 
    "length": 0, 
@@ -161,9 +171,11 @@
    "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, 
@@ -189,77 +201,16 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
-   "allow_on_submit": 1, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "Stop", 
-   "fieldname": "action_if_annual_budget_exceeded", 
-   "fieldtype": "Select", 
-   "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": "Action if Annual Budget Exceeded", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "\nStop\nWarn\nIgnore", 
-   "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, 
-   "unique": 0
-  }, 
-  {
-   "allow_on_submit": 1, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "Warn", 
-   "description": "", 
-   "fieldname": "action_if_accumulated_monthly_budget_exceeded", 
-   "fieldtype": "Select", 
-   "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": "Action if Accumulated Monthly Budget Exceeded", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "\nStop\nWarn\nIgnore", 
-   "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, 
-   "unique": 0
-  }, 
-  {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
-   "depends_on": "eval:in_list([\"Stop\", \"Warn\"], doc.action_if_accumulated_monthly_budget_exceeded)", 
+   "depends_on": "eval:in_list([\"Stop\", \"Warn\"], doc.action_if_accumulated_monthly_budget_exceeded_on_po || doc.action_if_accumulated_monthly_budget_exceeded_on_mr || doc.action_if_accumulated_monthly_budget_exceeded_on_actual)", 
    "fieldname": "monthly_distribution", 
    "fieldtype": "Link", 
    "hidden": 0, 
@@ -283,9 +234,11 @@
    "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, 
@@ -312,9 +265,11 @@
    "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, 
@@ -328,6 +283,7 @@
    "in_global_search": 0, 
    "in_list_view": 0, 
    "in_standard_filter": 0, 
+   "label": "Control Section", 
    "length": 0, 
    "no_copy": 0, 
    "permlevel": 0, 
@@ -340,13 +296,313 @@
    "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": "applicable_on_material_request", 
+   "fieldtype": "Check", 
+   "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": "Applicable on Material Request", 
+   "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, 
+   "default": "Stop", 
+   "depends_on": "eval:doc.applicable_on_material_request == 1", 
+   "fieldname": "action_if_annual_budget_exceeded_on_mr", 
+   "fieldtype": "Select", 
+   "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": "Action if Annual Budget Exceeded on MR", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "\nStop\nWarn\nIgnore", 
+   "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, 
+   "default": "Warn", 
+   "depends_on": "eval:doc.applicable_on_material_request == 1", 
+   "fieldname": "action_if_accumulated_monthly_budget_exceeded_on_mr", 
+   "fieldtype": "Select", 
+   "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": "Action if Accumulated Monthly Budget Exceeded on MR", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "\nStop\nWarn\nIgnore", 
+   "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": "applicable_on_purchase_order", 
+   "fieldtype": "Check", 
+   "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": "Applicable on Purchase Order", 
+   "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, 
+   "default": "Stop", 
+   "depends_on": "eval:doc.applicable_on_purchase_order == 1", 
+   "fieldname": "action_if_annual_budget_exceeded_on_po", 
+   "fieldtype": "Select", 
+   "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": "Action if Annual Budget Exceeded on PO", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "\nStop\nWarn\nIgnore", 
+   "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, 
+   "default": "Warn", 
+   "depends_on": "eval:doc.applicable_on_purchase_order == 1", 
+   "fieldname": "action_if_accumulated_monthly_budget_exceeded_on_po", 
+   "fieldtype": "Select", 
+   "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": "Action if Accumulated Monthly Budget Exceeded on PO", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "\nStop\nWarn\nIgnore", 
+   "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": "applicable_on_booking_actual_expenses", 
+   "fieldtype": "Check", 
+   "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": "Applicable on booking actual expenses", 
+   "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, 
+   "default": "Stop", 
+   "depends_on": "eval:doc.applicable_on_booking_actual_expenses == 1", 
+   "fieldname": "action_if_annual_budget_exceeded", 
+   "fieldtype": "Select", 
+   "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": "Action if Annual Budget Exceeded on Actual", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "\nStop\nWarn\nIgnore", 
+   "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, 
+   "default": "Warn", 
+   "depends_on": "eval:doc.applicable_on_booking_actual_expenses == 1", 
+   "fieldname": "action_if_accumulated_monthly_budget_exceeded", 
+   "fieldtype": "Select", 
+   "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": "Action if Accumulated Monthly Budget Exceeded on Actual", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "\nStop\nWarn\nIgnore", 
+   "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, 
+   "depends_on": "", 
    "fieldname": "accounts", 
    "fieldtype": "Table", 
    "hidden": 0, 
@@ -367,23 +623,24 @@
    "read_only": 0, 
    "remember_last_selected_value": 0, 
    "report_hide": 0, 
-   "reqd": 1, 
+   "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, 
- "in_dialog": 0, 
  "is_submittable": 1, 
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2017-02-17 16:25:32.342055", 
+ "modified": "2018-05-15 19:26:13.840265", 
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "Budget", 
@@ -392,7 +649,6 @@
  "permissions": [
   {
    "amend": 1, 
-   "apply_user_permissions": 0, 
    "cancel": 1, 
    "create": 1, 
    "delete": 1, 
diff --git a/erpnext/accounts/doctype/budget/budget.py b/erpnext/accounts/doctype/budget/budget.py
index f99d0bb..f2aa59b 100644
--- a/erpnext/accounts/doctype/budget/budget.py
+++ b/erpnext/accounts/doctype/budget/budget.py
@@ -5,8 +5,9 @@
 from __future__ import unicode_literals
 import frappe
 from frappe import _
-from frappe.utils import flt, getdate, add_months, get_last_day, fmt_money
+from frappe.utils import flt, getdate, add_months, get_last_day, fmt_money, nowdate
 from frappe.model.naming import make_autoname
+from erpnext.accounts.utils import get_fiscal_year
 from frappe.model.document import Document
 
 class BudgetError(frappe.ValidationError): pass
@@ -23,6 +24,7 @@
 		self.validate_duplicate()
 		self.validate_accounts()
 		self.set_null_value()
+		self.validate_applicable_for()
 
 	def validate_duplicate(self):
 		budget_against_field = frappe.scrub(self.budget_against)
@@ -61,13 +63,35 @@
 		else:
 			self.cost_center = None
 
-def validate_expense_against_budget(args):
+	def validate_applicable_for(self):
+		if (self.applicable_on_material_request
+			and not (self.applicable_on_purchase_order and self.applicable_on_booking_actual_expenses)):
+			frappe.throw(_("Please enable Applicable on Purchase Order and Applicable on Booking Actual Expenses"))
+
+		elif (self.applicable_on_purchase_order
+			and not (self.applicable_on_booking_actual_expenses)):
+			frappe.throw(_("Please enable Applicable on Booking Actual Expenses"))
+
+		elif not(self.applicable_on_material_request
+			or self.applicable_on_purchase_order or self.applicable_on_booking_actual_expenses):
+			self.applicable_on_booking_actual_expenses = 1
+
+def validate_expense_against_budget(args, company=None):
 	args = frappe._dict(args)
-	if not args.cost_center and not args.project:
+
+	if company:
+		args.company = company
+		args.fiscal_year = get_fiscal_year(nowdate(), company=company)[0]
+
+	if not (args.get('account') and args.get('cost_center')) and args.item_code:
+		args.cost_center, args.account = get_item_details(args)
+
+	if not (args.cost_center or args.project) and not args.account:
 		return
+
 	for budget_against in ['project', 'cost_center']:
-		if args.get(budget_against) \
-				and frappe.db.get_value("Account", {"name": args.account, "root_type": "Expense"}):
+		if (args.get(budget_against) and args.account
+				and frappe.db.get_value("Account", {"name": args.account, "root_type": "Expense"})):
 
 			if args.project and budget_against == 'project':
 				condition = "and b.project='%s'" % frappe.db.escape(args.project)
@@ -84,8 +108,12 @@
 			budget_records = frappe.db.sql("""
 				select
 					b.{budget_against_field} as budget_against, ba.budget_amount, b.monthly_distribution,
-					b.action_if_annual_budget_exceeded, 
-					b.action_if_accumulated_monthly_budget_exceeded
+					ifnull(b.applicable_on_material_request, 0) as for_material_request,
+					ifnull(applicable_on_purchase_order,0) as for_purchase_order,
+					ifnull(applicable_on_booking_actual_expenses,0) as for_actual_expenses,
+					b.action_if_annual_budget_exceeded, b.action_if_accumulated_monthly_budget_exceeded,
+					b.action_if_annual_budget_exceeded_on_mr, b.action_if_accumulated_monthly_budget_exceeded_on_mr,
+					b.action_if_annual_budget_exceeded_on_po, b.action_if_accumulated_monthly_budget_exceeded_on_po
 				from 
 					`tabBudget` b, `tabBudget Account` ba
 				where
@@ -102,8 +130,8 @@
 def validate_budget_records(args, budget_records):
 	for budget in budget_records:
 		if flt(budget.budget_amount):
-			yearly_action = budget.action_if_annual_budget_exceeded
-			monthly_action = budget.action_if_accumulated_monthly_budget_exceeded
+			amount = get_amount(args, budget)
+			yearly_action, monthly_action = get_actions(args, budget)
 
 			if monthly_action in ["Stop", "Warn"]:
 				budget_amount = get_accumulated_monthly_budget(budget.monthly_distribution,
@@ -111,16 +139,15 @@
 				args["month_end_date"] = get_last_day(args.posting_date)
 
 				compare_expense_with_budget(args, budget_amount, 
-					_("Accumulated Monthly"), monthly_action, budget.budget_against)
+					_("Accumulated Monthly"), monthly_action, budget.budget_against, amount)
 
 			if yearly_action in ("Stop", "Warn") and monthly_action != "Stop" \
 				and yearly_action != monthly_action:
 				compare_expense_with_budget(args, flt(budget.budget_amount), 
-						_("Annual"), yearly_action, budget.budget_against)
+						_("Annual"), yearly_action, budget.budget_against, amount)
 
-
-def compare_expense_with_budget(args, budget_amount, action_for, action, budget_against):
-	actual_expense = get_actual_expense(args)
+def compare_expense_with_budget(args, budget_amount, action_for, action, budget_against, amount=0):
+	actual_expense = amount or get_actual_expense(args)
 	if actual_expense > budget_amount:
 		diff = actual_expense - budget_amount
 		currency = frappe.db.get_value('Company', args.company, 'default_currency')
@@ -136,6 +163,45 @@
 		else:
 			frappe.msgprint(msg, indicator='orange')
 
+def get_actions(args, budget):
+	yearly_action = budget.action_if_annual_budget_exceeded
+	monthly_action = budget.action_if_accumulated_monthly_budget_exceeded
+
+	if args.get('doctype') == 'Material Request' and budget.for_material_request:
+		yearly_action = budget.action_if_annual_budget_exceeded_on_mr
+		monthly_action = budget.action_if_accumulated_monthly_budget_exceeded_on_mr
+
+	elif args.get('doctype') == 'Purchase Order' and budget.for_purchase_order:
+		yearly_action = budget.action_if_annual_budget_exceeded_on_po
+		monthly_action = budget.action_if_accumulated_monthly_budget_exceeded_on_po
+
+	return yearly_action, monthly_action
+
+def get_amount(args, budget):
+	amount = 0
+
+	if args.get('doctype') == 'Material Request' and budget.for_material_request:
+		amount = (get_requested_amount(args.item_code)
+			+ get_ordered_amount(args.item_code) + get_actual_expense(args))
+
+	elif args.get('doctype') == 'Purchase Order' and budget.for_purchase_order:
+		amount = get_ordered_amount(args.item_code) + get_actual_expense(args)
+
+	return amount
+
+def get_requested_amount(item_code):
+	data = frappe.db.sql(""" select ifnull((sum(stock_qty - ordered_qty) * rate), 0) as amount
+		from `tabMaterial Request Item` where item_code = %s and docstatus = 1
+		and stock_qty > ordered_qty """, item_code, as_list=1)
+
+	return data[0][0] if data else 0
+
+def get_ordered_amount(item_code):
+	data = frappe.db.sql(""" select ifnull(sum(amount - billed_amt), 0) as amount
+		from `tabPurchase Order Item` where item_code = %s and docstatus = 1
+		and amount > billed_amt""", item_code, as_list=1)
+
+	return data[0][0] if data else 0
 
 def get_actual_expense(args):
 	condition1 = " and gle.posting_date <= %(month_end_date)s" \
@@ -161,7 +227,6 @@
 			{condition2}
 	""".format(condition1=condition1, condition2=condition2), (args))[0][0])
 
-
 def get_accumulated_monthly_budget(monthly_distribution, posting_date, fiscal_year, annual_budget):
 	distribution = {}
 	if monthly_distribution:
@@ -182,3 +247,32 @@
 		dt = add_months(dt, 1)
 
 	return annual_budget * accumulated_percentage / 100
+
+def get_item_details(args):
+	cost_center, expense_account = None, None
+
+	if args.item_code:
+		cost_center, expense_account = frappe.db.get_value('Item',
+			args.item_code, ['buying_cost_center', 'expense_account'])
+
+	if not (cost_center and expense_account):
+		for doctype in ['Item Group', 'Company']:
+			data = get_expense_cost_center(doctype,
+				args.get(frappe.scrub(doctype)))
+
+			if not cost_center and data:
+				cost_center = data[0]
+
+			if not expense_account and data:
+				expense_account = data[1]
+
+			if cost_center and expense_account:
+				return cost_center, expense_account
+
+	return cost_center, expense_account
+
+def get_expense_cost_center(doctype, value):
+	fields = (['default_cost_center', 'default_expense_account']
+		if doctype == 'Item Group'else ['cost_center', 'default_expense_account'])
+
+	return frappe.db.get_value(doctype, value, fields)
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index cce5d19..5a7573b 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -210,6 +210,8 @@
 		self.update_prevdoc_status()
 		self.update_requested_qty()
 		self.update_ordered_qty()
+		self.validate_budget()
+
 		if self.is_subcontracted == "Yes":
 			self.update_reserved_qty_for_subcontract()
 
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 85fb3f0..45b9d78 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -13,6 +13,7 @@
 from erpnext.stock.doctype.stock_entry.stock_entry import get_used_alternative_items
 from erpnext.stock.doctype.serial_no.serial_no import get_auto_serial_nos, auto_make_serial_nos, get_serial_nos
 
+from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget
 from erpnext.controllers.stock_controller import StockController
 
 class BuyingController(StockController):
@@ -465,6 +466,16 @@
 			self.delete_linked_asset()
 			self.update_fixed_asset(field, delete_asset=True)
 
+	def validate_budget(self):
+		if self.docstatus == 1:
+			for data in self.get('items'):
+				validate_expense_against_budget({
+					'item_code': data.item_code,
+					'item_group': data.item_group,
+					'posting_date': data.schedule_date,
+					'doctype': self.doctype
+				}, self.company)
+
 	def process_fixed_asset(self):
 		if self.doctype == 'Purchase Invoice' and not self.update_stock:
 			return
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index ef0fe8d..7adb38e 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -741,7 +741,7 @@
 	},
 
 	conversion_factor: function(doc, cdt, cdn, dont_fetch_price_list_rate) {
-		if(frappe.meta.get_docfield(cdt, "stock_qty", cdn)) {
+		if(doc.doctype != 'Material Request' && frappe.meta.get_docfield(cdt, "stock_qty", cdn)) {
 			var item = frappe.get_doc(cdt, cdn);
 			frappe.model.round_floats_in(item, ["qty", "conversion_factor"]);
 			item.stock_qty = flt(item.qty * item.conversion_factor, precision("stock_qty", item));
diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js
index caf4e49..8e66b55 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -28,7 +28,39 @@
 				filters: {'company': doc.company}
 			}
 		}
-	}
+	},
+	get_item_data: function(frm, item) {
+		frm.call({
+			method: "erpnext.stock.get_item_details.get_item_details",
+			child: item,
+			args: {
+				args: {
+					item_code: item.item_code,
+					warehouse: item.warehouse,
+					doctype: frm.doc.doctype,
+					buying_price_list: frappe.defaults.get_default('buying_price_list'),
+					currency: frappe.defaults.get_default('Currency'),
+					name: frm.doc.name,
+					qty: item.qty || 1,
+					stock_qty: item.stock_qty,
+					company: frm.doc.company,
+					conversion_rate: 1,
+					plc_conversion_rate: 1,
+					rate: item.rate,
+					conversion_factor: item.conversion_factor
+				}
+			},
+			callback: function(r) {
+				const d = item;
+				if(!r.exc) {
+					$.each(r.message, function(k, v) {
+						if(!d[k]) d[k] = v;
+					});
+					debugger
+				}
+			}
+		});
+	},
 });
 
 frappe.ui.form.on("Material Request Item", {
@@ -37,10 +69,21 @@
 		if (flt(d.qty) < flt(d.min_order_qty)) {
 			frappe.msgprint(__("Warning: Material Requested Qty is less than Minimum Order Qty"));
 		}
+
+		const item = locals[doctype][name];
+		frm.events.get_item_data(frm, item);
+	},
+
+	rate: function(frm, doctype, name) {
+		const item = locals[doctype][name];
+		frm.events.get_item_data(frm, item);
 	},
 
 	item_code: function(frm, doctype, name) {
+		const item = locals[doctype][name];
+		item.rate = 0
 		set_schedule_date(frm);
+		frm.events.get_item_data(frm, item);
 	},
 
 	schedule_date: function(frm, cdt, cdn) {
@@ -186,6 +229,10 @@
 		this.get_terms();
 	},
 
+	item_code: function() {
+		// to override item code trigger from transaction.js
+	},
+
 	validate_company_and_party: function(party_field) {
 		return true;
 	},
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index d4dc523..df40654 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -93,6 +93,8 @@
 		# frappe.db.set(self, 'status', 'Submitted')
 		self.update_requested_qty()
 		self.update_requested_qty_in_production_plan()
+		if self.material_request_type == 'Purchase':
+			self.validate_budget()
 
 	def before_save(self):
 		self.set_status(update=True)
diff --git a/erpnext/stock/doctype/material_request_item/material_request_item.json b/erpnext/stock/doctype/material_request_item/material_request_item.json
index d31d9e7..ac6eefc 100644
--- a/erpnext/stock/doctype/material_request_item/material_request_item.json
+++ b/erpnext/stock/doctype/material_request_item/material_request_item.json
@@ -44,6 +44,7 @@
    "reqd": 1, 
    "search_index": 1, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0, 
    "width": "100px"
   }, 
@@ -73,6 +74,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -105,6 +107,7 @@
    "reqd": 0, 
    "search_index": 1, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0, 
    "width": "100px"
   }, 
@@ -136,6 +139,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -168,6 +172,7 @@
    "reqd": 1, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0, 
    "width": "250px"
   }, 
@@ -198,6 +203,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -228,6 +234,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -257,6 +264,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -289,6 +297,7 @@
    "reqd": 1, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0, 
    "width": "80px"
   }, 
@@ -298,8 +307,8 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
-   "fieldname": "stock_uom", 
-   "fieldtype": "Link", 
+   "fieldname": "rate", 
+   "fieldtype": "Currency", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
    "ignore_xss_filter": 0, 
@@ -307,20 +316,51 @@
    "in_global_search": 0, 
    "in_list_view": 0, 
    "in_standard_filter": 0, 
-   "label": "Stock UOM", 
+   "label": "Rate", 
    "length": 0, 
    "no_copy": 0, 
-   "options": "UOM", 
    "permlevel": 0, 
    "precision": "", 
-   "print_hide": 1, 
+   "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": "amount", 
+   "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": "Amount", 
+   "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": 1, 
+   "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -354,12 +394,42 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0, 
    "width": "100px"
   }, 
   {
    "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "col_break2", 
+   "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, 
+   "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": 1, 
    "collapsible": 0, 
    "columns": 2, 
@@ -388,6 +458,7 @@
    "reqd": 1, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0, 
    "width": "100px"
   }, 
@@ -397,34 +468,6 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
-   "fieldname": "col_break2", 
-   "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, 
-   "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, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
    "fieldname": "uom", 
    "fieldtype": "Link", 
    "hidden": 0, 
@@ -450,6 +493,7 @@
    "reqd": 1, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0, 
    "width": "70px"
   }, 
@@ -481,6 +525,39 @@
    "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": "stock_uom", 
+   "fieldtype": "Link", 
+   "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": "Stock UOM", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "UOM", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 1, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 1, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -511,6 +588,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -540,6 +618,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -573,6 +652,7 @@
    "reqd": 0, 
    "search_index": 1, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -606,6 +686,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0, 
    "width": "100px"
   }, 
@@ -638,6 +719,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -668,6 +750,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -698,6 +781,7 @@
    "reqd": 0, 
    "search_index": 1, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -729,6 +813,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -760,6 +845,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -790,6 +876,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -818,6 +905,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -850,6 +938,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0, 
    "width": "70px"
   }, 
@@ -883,6 +972,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0, 
    "width": "70px"
   }, 
@@ -914,6 +1004,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -945,6 +1036,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
@@ -976,6 +1068,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }
  ], 
@@ -989,7 +1082,7 @@
  "issingle": 0, 
  "istable": 1, 
  "max_attachments": 0, 
- "modified": "2018-02-12 05:51:39.954530", 
+ "modified": "2018-05-15 18:19:36.673046", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Material Request Item", 
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 6003974..b336565 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -101,6 +101,9 @@
 		out.bom = args.get('bom') or get_default_bom(args.item_code)
 
 	get_gross_profit(out)
+	if args.doctype == 'Material Request':
+		out.rate = args.rate or out.price_list_rate
+		out.amount = flt(args.qty * out.rate)
 
 	return out
 
@@ -320,9 +323,9 @@
 def get_price_list_rate(args, item_doc, out):
 	meta = frappe.get_meta(args.parenttype or args.doctype)
 
-	if meta.get_field("currency"):
+	if meta.get_field("currency") or args.get('currency'):
 		validate_price_list(args)
-		if args.price_list:
+		if meta.get_field("currency") and args.price_list:
 			validate_conversion_rate(args, meta)
 
 		price_list_rate = get_price_list_rate_for(args.price_list, item_doc.name)