Enhance Currency Exchange Management (#10482)

* add new settings in Accouts Settings

* patch for new settings

* refactor `get_exchange_rate`

* adds validation

* tests validation

* disables conversion rate field if stale rates not allowed

* more test cases

more test case...

test `get_exchange_rate` behaviour with stale not allowed in sett..

fix currency exchange test case

do housekeeping after running accounts settings test

* clean up

* documentation

* make use of correct api url

* Fix tests failing due to wrong exchange rate from fixer.io

* remove mandatory constraint from `allow_stale`

* added info to documentation
diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py
index bdbf3f4..f003ce4 100644
--- a/erpnext/setup/utils.py
+++ b/erpnext/setup/utils.py
@@ -4,7 +4,7 @@
 from __future__ import unicode_literals
 import frappe
 from frappe import _
-from frappe.utils import flt
+from frappe.utils import flt, add_days
 from frappe.utils import get_datetime_str, nowdate
 
 def get_root_of(doctype):
@@ -56,8 +56,6 @@
 
 @frappe.whitelist()
 def get_exchange_rate(from_currency, to_currency, transaction_date=None):
-	if not transaction_date:
-		transaction_date = nowdate()
 	if not (from_currency and to_currency):
 		# manqala 19/09/2016: Should this be an empty return or should it throw and exception?
 		return
@@ -65,13 +63,27 @@
 	if from_currency == to_currency:
 		return 1
 
+	if not transaction_date:
+		transaction_date = nowdate()
+
+	currency_settings = frappe.get_doc("Accounts Settings").as_dict()
+	allow_stale_rates = currency_settings.get("allow_stale")
+
+	filters = [
+		["date", "<=", get_datetime_str(transaction_date)],
+		["from_currency", "=", from_currency],
+		["to_currency", "=", to_currency]
+	]
+
+	if not allow_stale_rates:
+		stale_days = currency_settings.get("stale_days")
+		checkpoint_date = add_days(transaction_date, -stale_days)
+		filters.append(["date", ">", get_datetime_str(checkpoint_date)])
+
 	# cksgb 19/09/2016: get last entry in Currency Exchange with from_currency and to_currency.
-	entries = frappe.get_all("Currency Exchange", fields = ["exchange_rate"],
-		filters=[
-			["date", "<=", get_datetime_str(transaction_date)],
-			["from_currency", "=", from_currency],
-			["to_currency", "=", to_currency]
-		], order_by="date desc", limit=1)
+	entries = frappe.get_all(
+		"Currency Exchange", fields=["exchange_rate"], filters=filters, order_by="date desc",
+		limit=1)
 
 	if entries:
 		return flt(entries[0].exchange_rate)