Merge pull request #18194 from deepeshgarg007/dimensions_reports

fix: Add accounting dimensions to various reports and fixes
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.json b/erpnext/accounts/doctype/gl_entry/gl_entry.json
index 333d39a..a232a95 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.json
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.json
@@ -848,6 +848,39 @@
    "set_only_once": 0,
    "translatable": 0,
    "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fetch_if_empty": 0,
+   "fieldname": "due_date",
+   "fieldtype": "Date",
+   "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": "Due Date",
+   "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
   }
  ],
  "has_web_view": 0,
@@ -861,7 +894,7 @@
  "issingle": 0,
  "istable": 0,
  "max_attachments": 0,
- "modified": "2019-01-07 07:05:00.366399",
+ "modified": "2019-05-01 07:05:00.366399",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "GL Entry",
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 3132c93..8fbddb9 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -498,6 +498,7 @@
 					self.get_gl_dict({
 						"account": d.account,
 						"party_type": d.party_type,
+						"due_date": self.due_date,
 						"party": d.party,
 						"against": d.against_account,
 						"debit": flt(d.debit, d.precision("debit")),
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index 2c382c5..f17b2cb 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -302,7 +302,7 @@
 							},
 							() => frm.set_value("party_balance", r.message.party_balance),
 							() => frm.set_value("party_name", r.message.party_name),
-							() => frm.events.get_outstanding_documents(frm),
+							() => frm.clear_table("references"),
 							() => frm.events.hide_unhide_fields(frm),
 							() => frm.events.set_dynamic_labels(frm),
 							() => {
@@ -323,9 +323,7 @@
 
 		frm.events.set_account_currency_and_balance(frm, frm.doc.paid_from,
 			"paid_from_account_currency", "paid_from_account_balance", function(frm) {
-				if (frm.doc.payment_type == "Receive") {
-					frm.events.get_outstanding_documents(frm);
-				} else if (frm.doc.payment_type == "Pay") {
+				if (frm.doc.payment_type == "Pay") {
 					frm.events.paid_amount(frm);
 				}
 			}
@@ -337,9 +335,7 @@
 
 		frm.events.set_account_currency_and_balance(frm, frm.doc.paid_to,
 			"paid_to_account_currency", "paid_to_account_balance", function(frm) {
-				if(frm.doc.payment_type == "Pay") {
-					frm.events.get_outstanding_documents(frm);
-				} else if (frm.doc.payment_type == "Receive") {
+				if (frm.doc.payment_type == "Receive") {
 					if(frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency) {
 						if(frm.doc.source_exchange_rate) {
 							frm.set_value("target_exchange_rate", frm.doc.source_exchange_rate);
@@ -533,26 +529,87 @@
 			frm.events.set_unallocated_amount(frm);
 	},
 
-	get_outstanding_documents: function(frm) {
+	get_outstanding_invoice: function(frm) {
+		const today = frappe.datetime.get_today();
+		const fields = [
+			{fieldtype:"Section Break", label: __("Posting Date")},
+			{fieldtype:"Date", label: __("From Date"),
+				fieldname:"from_posting_date", default:frappe.datetime.add_days(today, -30)},
+			{fieldtype:"Column Break"},
+			{fieldtype:"Date", label: __("To Date"), fieldname:"to_posting_date", default:today},
+			{fieldtype:"Section Break", label: __("Due Date")},
+			{fieldtype:"Date", label: __("From Date"), fieldname:"from_due_date"},
+			{fieldtype:"Column Break"},
+			{fieldtype:"Date", label: __("To Date"), fieldname:"to_due_date"},
+			{fieldtype:"Section Break", label: __("Outstanding Amount")},
+			{fieldtype:"Float", label: __("Greater Than Amount"),
+				fieldname:"outstanding_amt_greater_than", default: 0},
+			{fieldtype:"Column Break"},
+			{fieldtype:"Float", label: __("Less Than Amount"), fieldname:"outstanding_amt_less_than"},
+			{fieldtype:"Section Break"},
+			{fieldtype:"Check", label: __("Allocate Payment Amount"), fieldname:"allocate_payment_amount", default:1},
+		];
+
+		frappe.prompt(fields, function(filters){
+			frappe.flags.allocate_payment_amount = true;
+			frm.events.validate_filters_data(frm, filters);
+			frm.events.get_outstanding_documents(frm, filters);
+		}, __("Filters"), __("Get Outstanding Invoices"));
+	},
+
+	validate_filters_data: function(frm, filters) {
+		const fields = {
+			'Posting Date': ['from_posting_date', 'to_posting_date'],
+			'Due Date': ['from_posting_date', 'to_posting_date'],
+			'Advance Amount': ['from_posting_date', 'to_posting_date'],
+		};
+
+		for (let key in fields) {
+			let from_field = fields[key][0];
+			let to_field = fields[key][1];
+
+			if (filters[from_field] && !filters[to_field]) {
+				frappe.throw(__("Error: {0} is mandatory field",
+					[to_field.replace(/_/g, " ")]
+				));
+			} else if (filters[from_field] && filters[from_field] > filters[to_field]) {
+				frappe.throw(__("{0}: {1} must be less than {2}",
+					[key, from_field.replace(/_/g, " "), to_field.replace(/_/g, " ")]
+				));
+			}
+		}
+	},
+
+	get_outstanding_documents: function(frm, filters) {
 		frm.clear_table("references");
 
-		if(!frm.doc.party) return;
+		if(!frm.doc.party) {
+			return;
+		}
 
 		frm.events.check_mandatory_to_fetch(frm);
 		var company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
 
+		var args = {
+			"posting_date": frm.doc.posting_date,
+			"company": frm.doc.company,
+			"party_type": frm.doc.party_type,
+			"payment_type": frm.doc.payment_type,
+			"party": frm.doc.party,
+			"party_account": frm.doc.payment_type=="Receive" ? frm.doc.paid_from : frm.doc.paid_to,
+			"cost_center": frm.doc.cost_center
+		}
+
+		for (let key in filters) {
+			args[key] = filters[key];
+		}
+
+		frappe.flags.allocate_payment_amount = filters['allocate_payment_amount'];
+
 		return  frappe.call({
 			method: 'erpnext.accounts.doctype.payment_entry.payment_entry.get_outstanding_reference_documents',
 			args: {
-				args: {
-					"posting_date": frm.doc.posting_date,
-					"company": frm.doc.company,
-					"party_type": frm.doc.party_type,
-					"payment_type": frm.doc.payment_type,
-					"party": frm.doc.party,
-					"party_account": frm.doc.payment_type=="Receive" ? frm.doc.paid_from : frm.doc.paid_to,
-					"cost_center": frm.doc.cost_center
-				}
+				args:args
 			},
 			callback: function(r, rt) {
 				if(r.message) {
@@ -608,25 +665,11 @@
 
 				frm.events.allocate_party_amount_against_ref_docs(frm,
 					(frm.doc.payment_type=="Receive" ? frm.doc.paid_amount : frm.doc.received_amount));
+
 			}
 		});
 	},
 
-	allocate_payment_amount: function(frm) {
-		if(frm.doc.payment_type == 'Internal Transfer'){
-			return
-		}
-
-		if(frm.doc.references.length == 0){
-			frm.events.get_outstanding_documents(frm);
-		}
-		if(frm.doc.payment_type == 'Internal Transfer') {
-			frm.events.allocate_party_amount_against_ref_docs(frm, frm.doc.paid_amount);
-		} else {
-			frm.events.allocate_party_amount_against_ref_docs(frm, frm.doc.received_amount);
-		}
-	},
-
 	allocate_party_amount_against_ref_docs: function(frm, paid_amount) {
 		var total_positive_outstanding_including_order = 0;
 		var total_negative_outstanding = 0;
@@ -677,7 +720,7 @@
 
 		$.each(frm.doc.references || [], function(i, row) {
 			row.allocated_amount = 0 //If allocate payment amount checkbox is unchecked, set zero to allocate amount
-			if(frm.doc.allocate_payment_amount){
+			if(frappe.flags.allocate_payment_amount){
 				if(row.outstanding_amount > 0 && allocated_positive_outstanding > 0) {
 					if(row.outstanding_amount >= allocated_positive_outstanding) {
 						row.allocated_amount = allocated_positive_outstanding;
@@ -958,7 +1001,7 @@
 							},
 							() => {
 								if(frm.doc.payment_type != "Internal") {
-									frm.events.get_outstanding_documents(frm);
+									frm.clear_table("references");
 								}
 							}
 						]);
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json
index fcaa570..a85eccd 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.json
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json
@@ -40,7 +40,7 @@
   "target_exchange_rate",
   "base_received_amount",
   "section_break_14",
-  "allocate_payment_amount",
+  "get_outstanding_invoice",
   "references",
   "section_break_34",
   "total_allocated_amount",
@@ -325,19 +325,15 @@
    "reqd": 1
   },
   {
-   "collapsible": 1,
-   "collapsible_depends_on": "references",
    "depends_on": "eval:(doc.party && doc.paid_from && doc.paid_to && doc.paid_amount && doc.received_amount)",
    "fieldname": "section_break_14",
    "fieldtype": "Section Break",
    "label": "Reference"
   },
   {
-   "default": "1",
-   "depends_on": "eval:in_list(['Pay', 'Receive'], doc.payment_type)",
-   "fieldname": "allocate_payment_amount",
-   "fieldtype": "Check",
-   "label": "Allocate Payment Amount"
+   "fieldname": "get_outstanding_invoice",
+   "fieldtype": "Button",
+   "label": "Get Outstanding Invoice"
   },
   {
    "fieldname": "references",
@@ -570,7 +566,7 @@
   }
  ],
  "is_submittable": 1,
- "modified": "2019-05-25 22:02:40.575822",
+ "modified": "2019-05-27 15:53:21.108857",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Payment Entry",
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index ea76126..699f046 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -574,8 +574,8 @@
 	# Get negative outstanding sales /purchase invoices
 	negative_outstanding_invoices = []
 	if args.get("party_type") not in ["Student", "Employee"] and not args.get("voucher_no"):
-		negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"),
-			args.get("party"), args.get("party_account"), party_account_currency, company_currency)
+		negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"), args.get("party"),
+			args.get("party_account"), args.get("company"), party_account_currency, company_currency)
 
 	# Get positive outstanding sales /purchase invoices/ Fees
 	condition = ""
@@ -585,10 +585,23 @@
 
 	# Add cost center condition
 	if args.get("cost_center") and get_allow_cost_center_in_entry_of_bs_account():
-			condition += " and cost_center='%s'" % args.get("cost_center")
+		condition += " and cost_center='%s'" % args.get("cost_center")
+
+	date_fields_dict = {
+		'posting_date': ['from_posting_date', 'to_posting_date'],
+		'due_date': ['from_due_date', 'to_due_date']
+	}
+
+	for fieldname, date_fields in date_fields_dict.items():
+		if args.get(date_fields[0]) and args.get(date_fields[1]):
+			condition += " and {0} between '{1}' and '{2}'".format(fieldname,
+				args.get(date_fields[0]), args.get(date_fields[1]))
+
+	if args.get("company"):
+		condition += " and company = {0}".format(frappe.db.escape(args.get("company")))
 
 	outstanding_invoices = get_outstanding_invoices(args.get("party_type"), args.get("party"),
-		args.get("party_account"), condition=condition)
+		args.get("party_account"), filters=args, condition=condition, limit=100)
 
 	for d in outstanding_invoices:
 		d["exchange_rate"] = 1
@@ -606,12 +619,19 @@
 	orders_to_be_billed = []
 	if (args.get("party_type") != "Student"):
 		orders_to_be_billed =  get_orders_to_be_billed(args.get("posting_date"),args.get("party_type"),
-			args.get("party"), party_account_currency, company_currency)
+			args.get("party"), args.get("company"), party_account_currency, company_currency, filters=args)
 
-	return negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
+	data = negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
+
+	if not data:
+		frappe.msgprint(_("No outstanding invoices found for the {0} <b>{1}</b>.")
+			.format(args.get("party_type").lower(), args.get("party")))
+
+	return data
 
 
-def get_orders_to_be_billed(posting_date, party_type, party, party_account_currency, company_currency, cost_center=None):
+def get_orders_to_be_billed(posting_date, party_type, party,
+	company, party_account_currency, company_currency, cost_center=None, filters=None):
 	if party_type == "Customer":
 		voucher_type = 'Sales Order'
 	elif party_type == "Supplier":
@@ -641,6 +661,7 @@
 			where
 				{party_type} = %s
 				and docstatus = 1
+				and company = %s
 				and ifnull(status, "") != "Closed"
 				and {ref_field} > advance_paid
 				and abs(100 - per_billed) > 0.01
@@ -652,10 +673,14 @@
 			"voucher_type": voucher_type,
 			"party_type": scrub(party_type),
 			"condition": condition
-		}), party, as_dict=True)
+		}), (party, company), as_dict=True)
 
 	order_list = []
 	for d in orders:
+		if not (d.outstanding_amount >= filters.get("outstanding_amt_greater_than")
+			and d.outstanding_amount <= filters.get("outstanding_amt_less_than")):
+			continue
+
 		d["voucher_type"] = voucher_type
 		# This assumes that the exchange rate required is the one in the SO
 		d["exchange_rate"] = get_exchange_rate(party_account_currency, company_currency, posting_date)
@@ -663,7 +688,8 @@
 
 	return order_list
 
-def get_negative_outstanding_invoices(party_type, party, party_account, party_account_currency, company_currency, cost_center=None):
+def get_negative_outstanding_invoices(party_type, party, party_account,
+	company, party_account_currency, company_currency, cost_center=None):
 	voucher_type = "Sales Invoice" if party_type == "Customer" else "Purchase Invoice"
 	supplier_condition = ""
 	if voucher_type == "Purchase Invoice":
@@ -684,7 +710,8 @@
 		from
 			`tab{voucher_type}`
 		where
-			{party_type} = %s and {party_account} = %s and docstatus = 1 and outstanding_amount < 0
+			{party_type} = %s and {party_account} = %s and docstatus = 1 and
+			company = %s and outstanding_amount < 0
 			{supplier_condition}
 		order by
 			posting_date, name
@@ -696,7 +723,7 @@
 			"party_type": scrub(party_type),
 			"party_account": "debit_to" if party_type == "Customer" else "credit_to",
 			"cost_center": cost_center
-		}), (party, party_account), as_dict=True)
+		}), (party, party_account, company), as_dict=True)
 
 
 @frappe.whitelist()
@@ -924,7 +951,6 @@
 	pe.paid_to_account_currency = party_account_currency if payment_type=="Pay" else bank.account_currency
 	pe.paid_amount = paid_amount
 	pe.received_amount = received_amount
-	pe.allocate_payment_amount = 1
 	pe.letter_head = doc.get("letter_head")
 
 	if pe.party_type in ["Customer", "Supplier"]:
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 70e98d9..219d989 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -417,6 +417,7 @@
 					"account": self.credit_to,
 					"party_type": "Supplier",
 					"party": self.supplier,
+					"due_date": self.due_date,
 					"against": self.against_expense_account,
 					"credit": grand_total_in_company_currency,
 					"credit_in_account_currency": grand_total_in_company_currency \
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 71bdc2a..f8bb971 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -734,6 +734,7 @@
 					"account": self.debit_to,
 					"party_type": "Customer",
 					"party": self.customer,
+					"due_date": self.due_date,
 					"against": self.against_income_account,
 					"debit": grand_total_in_company_currency,
 					"debit_in_account_currency": grand_total_in_company_currency \
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 7a1f6c5..542c7e4 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -628,7 +628,7 @@
 	return held_invoices
 
 
-def get_outstanding_invoices(party_type, party, account, condition=None):
+def get_outstanding_invoices(party_type, party, account, condition=None, filters=None):
 	outstanding_invoices = []
 	precision = frappe.get_precision("Sales Invoice", "outstanding_amount") or 2
 
@@ -644,7 +644,8 @@
 
 	invoice_list = frappe.db.sql("""
 		select
-			voucher_no, voucher_type, posting_date, ifnull(sum({dr_or_cr}), 0) as invoice_amount
+			voucher_no, voucher_type, posting_date, due_date,
+			ifnull(sum({dr_or_cr}), 0) as invoice_amount
 		from
 			`tabGL Entry`
 		where
@@ -677,7 +678,7 @@
 	""".format(payment_dr_or_cr=payment_dr_or_cr), {
 		"party_type": party_type,
 		"party": party,
-		"account": account,
+		"account": account
 	}, as_dict=True)
 
 	pe_map = frappe._dict()
@@ -688,10 +689,12 @@
 		payment_amount = pe_map.get((d.voucher_type, d.voucher_no), 0)
 		outstanding_amount = flt(d.invoice_amount - payment_amount, precision)
 		if outstanding_amount > 0.5 / (10**precision):
-			if not d.voucher_type == "Purchase Invoice" or d.voucher_no not in held_invoices:
-				due_date = frappe.db.get_value(
-					d.voucher_type, d.voucher_no, "posting_date" if party_type == "Employee" else "due_date")
+			if (filters.get("outstanding_amt_greater_than") and
+				not (outstanding_amount >= filters.get("outstanding_amt_greater_than") and
+				outstanding_amount <= filters.get("outstanding_amt_less_than"))):
+				continue
 
+			if not d.voucher_type == "Purchase Invoice" or d.voucher_no not in held_invoices:
 				outstanding_invoices.append(
 					frappe._dict({
 						'voucher_no': d.voucher_no,
@@ -700,7 +703,7 @@
 						'invoice_amount': flt(d.invoice_amount),
 						'payment_amount': payment_amount,
 						'outstanding_amount': outstanding_amount,
-						'due_date': due_date
+						'due_date': d.due_date
 					})
 				)
 
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index bd41c7e..0dd88e9 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -615,4 +615,5 @@
 erpnext.patches.v12_0.set_quotation_status
 erpnext.patches.v12_0.set_priority_for_support
 erpnext.patches.v12_0.delete_priority_property_setter
+erpnext.patches.v12_0.update_due_date_in_gle
 erpnext.patches.v12_0.add_default_buying_selling_terms_in_company
diff --git a/erpnext/patches/v12_0/update_due_date_in_gle.py b/erpnext/patches/v12_0/update_due_date_in_gle.py
new file mode 100644
index 0000000..4c47a82
--- /dev/null
+++ b/erpnext/patches/v12_0/update_due_date_in_gle.py
@@ -0,0 +1,17 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+    frappe.reload_doc("accounts", "doctype", "gl_entry")
+
+    for doctype in ["Sales Invoice", "Purchase Invoice", "Journal Entry"]:
+        frappe.reload_doc("accounts", "doctype", frappe.scrub(doctype))
+
+        frappe.db.sql(""" UPDATE `tabGL Entry`, `tab{doctype}`
+            SET
+                `tabGL Entry`.due_date = `tab{doctype}`.due_date
+            WHERE
+                `tabGL Entry`.voucher_no = `tab{doctype}`.name and `tabGL Entry`.party is not null
+                and `tabGL Entry`.voucher_type in ('Sales Invoice', 'Purchase Invoice', 'Journal Entry')
+                and account in (select name from `tabAccount` where account_type in ('Receivable', 'Payable') )""" #nosec
+            .format(doctype=doctype))