blob: a4f2207f1138886068459dfff5363895778ec3fe [file] [log] [blame]
Anand Doshi885e0742015-03-03 14:55:30 +05301# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
Rushabh Mehtae67d1fb2013-08-05 14:59:54 +05302# License: GNU General Public License v3. See license.txt
Anand Doshi9d9aec12013-01-17 15:44:57 +05303
Chillar Anand915b3432021-09-02 16:44:59 +05304
Rushabh Mehta793ba6b2014-02-14 15:47:51 +05305import frappe
Rushabh Mehtacc8b2b22017-03-31 12:44:29 +05306from frappe import _
Chillar Anand915b3432021-09-02 16:44:59 +05307from frappe.utils import add_days, flt, get_datetime_str, nowdate
8
Neil Trini Lasrado771fbb82018-08-24 15:15:56 +05309from erpnext import get_default_company
Rushabh Mehtacf99dc02017-02-09 18:06:11 +053010
Chillar Anand915b3432021-09-02 16:44:59 +053011
Anand Doshi61a2f682013-06-21 17:55:31 +053012def get_root_of(doctype):
Nabin Hait87d70272016-12-08 14:43:11 +053013 """Get root element of a DocType with a tree structure"""
14 result = frappe.db.sql_list("""select name from `tab%s`
15 where lft=1 and rgt=(select max(rgt) from `tab%s` where docstatus < 2)""" %
16 (doctype, doctype))
17 return result[0] if result else None
Rushabh Mehta9f0d6252014-04-14 19:20:45 +053018
Anand Doshi61a2f682013-06-21 17:55:31 +053019def get_ancestors_of(doctype, name):
Nabin Hait87d70272016-12-08 14:43:11 +053020 """Get ancestor elements of a DocType with a tree structure"""
21 lft, rgt = frappe.db.get_value(doctype, name, ["lft", "rgt"])
22 result = frappe.db.sql_list("""select name from `tab%s`
23 where lft<%s and rgt>%s order by lft desc""" % (doctype, "%s", "%s"), (lft, rgt))
24 return result or []
Anand Doshi61a2f682013-06-21 17:55:31 +053025
Rushabh Mehtaa1516472014-04-30 19:38:28 +053026def before_tests():
Nabin Hait87d70272016-12-08 14:43:11 +053027 frappe.clear_cache()
28 # complete setup if missing
29 from frappe.desk.page.setup_wizard.setup_wizard import setup_complete
30 if not frappe.get_list("Company"):
31 setup_complete({
Ankush Menat22cb6422021-07-02 23:32:33 +053032 "currency" :"USD",
33 "full_name" :"Test User",
34 "company_name" :"Wind Power LLC",
35 "timezone" :"America/New_York",
36 "company_abbr" :"WP",
37 "industry" :"Manufacturing",
38 "country" :"United States",
39 "fy_start_date" :"2021-01-01",
40 "fy_end_date" :"2021-12-31",
41 "language" :"english",
42 "company_tagline" :"Testing",
43 "email" :"test@erpnext.com",
44 "password" :"test",
Nabin Hait1749b7c2017-11-16 17:48:59 +053045 "chart_of_accounts" : "Standard",
Ankush Menat22cb6422021-07-02 23:32:33 +053046 "domains" : ["Manufacturing"],
Nabin Hait87d70272016-12-08 14:43:11 +053047 })
Rushabh Mehtaa1516472014-04-30 19:38:28 +053048
Nabin Hait87d70272016-12-08 14:43:11 +053049 frappe.db.sql("delete from `tabLeave Allocation`")
50 frappe.db.sql("delete from `tabLeave Application`")
51 frappe.db.sql("delete from `tabSalary Slip`")
52 frappe.db.sql("delete from `tabItem Price`")
Rushabh Mehta5bd39422015-08-03 15:09:48 +053053
Nabin Hait87d70272016-12-08 14:43:11 +053054 frappe.db.set_value("Stock Settings", None, "auto_insert_price_list_rate_if_missing", 0)
Makarand Bauskard0109a62017-07-26 16:29:22 +053055 enable_all_roles_and_domains()
Ankush Menata8375232021-12-05 22:07:14 +053056 set_defaults_for_tests()
Rushabh Mehta5bd39422015-08-03 15:09:48 +053057
Nabin Hait87d70272016-12-08 14:43:11 +053058 frappe.db.commit()
Anand Doshidffec8f2014-07-01 17:45:15 +053059
Rushabh Mehta66fa1ff2015-05-07 12:25:33 +053060@frappe.whitelist()
Shreya0db85062018-05-15 11:25:46 +053061def get_exchange_rate(from_currency, to_currency, transaction_date=None, args=None):
Nabin Haitad4f1c72016-12-09 12:14:47 +053062 if not (from_currency and to_currency):
Nabin Hait87d70272016-12-08 14:43:11 +053063 # manqala 19/09/2016: Should this be an empty return or should it throw and exception?
64 return
Nabin Hait87d70272016-12-08 14:43:11 +053065 if from_currency == to_currency:
66 return 1
Rushabh Mehtacf99dc02017-02-09 18:06:11 +053067
tundebabzyab5b0302017-09-21 10:20:39 +010068 if not transaction_date:
69 transaction_date = nowdate()
tundebabzyab5b0302017-09-21 10:20:39 +010070 currency_settings = frappe.get_doc("Accounts Settings").as_dict()
71 allow_stale_rates = currency_settings.get("allow_stale")
72
73 filters = [
74 ["date", "<=", get_datetime_str(transaction_date)],
75 ["from_currency", "=", from_currency],
76 ["to_currency", "=", to_currency]
77 ]
Shreyab547cdd2018-05-15 16:58:45 +053078
Shreya0db85062018-05-15 11:25:46 +053079 if args == "for_buying":
80 filters.append(["for_buying", "=", "1"])
81 elif args == "for_selling":
Shreyab547cdd2018-05-15 16:58:45 +053082 filters.append(["for_selling", "=", "1"])
83
tundebabzyab5b0302017-09-21 10:20:39 +010084 if not allow_stale_rates:
85 stale_days = currency_settings.get("stale_days")
86 checkpoint_date = add_days(transaction_date, -stale_days)
87 filters.append(["date", ">", get_datetime_str(checkpoint_date)])
88
Nabin Hait288a18e2016-12-08 15:36:23 +053089 # cksgb 19/09/2016: get last entry in Currency Exchange with from_currency and to_currency.
tundebabzyab5b0302017-09-21 10:20:39 +010090 entries = frappe.get_all(
91 "Currency Exchange", fields=["exchange_rate"], filters=filters, order_by="date desc",
92 limit=1)
Nabin Hait87d70272016-12-08 14:43:11 +053093 if entries:
94 return flt(entries[0].exchange_rate)
Rushabh Mehta746fd902015-10-15 11:50:38 +053095
Nabin Hait87d70272016-12-08 14:43:11 +053096 try:
97 cache = frappe.cache()
Dany Roberte9bc2f32021-06-28 19:01:52 +053098 key = "currency_exchange_rate_{0}:{1}:{2}".format(transaction_date, from_currency, to_currency)
Nabin Hait87d70272016-12-08 14:43:11 +053099 value = cache.get(key)
Rushabh Mehta9f436a72015-10-15 11:57:46 +0530100
Nabin Hait87d70272016-12-08 14:43:11 +0530101 if not value:
102 import requests
Deepesh Garge2dab6f2022-01-10 17:31:38 +0530103 settings = frappe.get_cached_doc('Currency Exchange Settings')
rtdany10a86d9c92021-09-03 19:21:06 +0530104 req_params = {
rtdany10e0938632021-09-03 15:03:47 +0530105 "transaction_date": transaction_date,
106 "from_currency": from_currency,
107 "to_currency": to_currency
108 }
109 params = {}
110 for row in settings.req_params:
rtdany10227466c2021-09-04 14:04:56 +0530111 params[row.key] = format_ces_api(row.value, req_params)
rtdany10a86d9c92021-09-03 19:21:06 +0530112 response = requests.get(format_ces_api(settings.api_endpoint, req_params), params=params)
Nabin Hait87d70272016-12-08 14:43:11 +0530113 # expire in 6 hours
114 response.raise_for_status()
rtdany10e0938632021-09-03 15:03:47 +0530115 value = response.json()
116 for res_key in settings.result_key:
rtdany10a86d9c92021-09-03 19:21:06 +0530117 value = value[format_ces_api(str(res_key.key), req_params)]
Dany Robert909995a2021-07-29 15:58:27 +0530118 cache.setex(name=key, time=21600, value=flt(value))
Nabin Hait87d70272016-12-08 14:43:11 +0530119 return flt(value)
Ankush Menat694ae812021-09-01 14:40:56 +0530120 except Exception:
Faris Ansaribadf1c42019-01-24 16:28:53 +0530121 frappe.log_error(title="Get Exchange Rate")
Nabin Hait7a9bd412017-05-24 16:18:27 +0530122 frappe.msgprint(_("Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually").format(from_currency, to_currency, transaction_date))
Makarand Bauskarddd48452017-07-06 11:09:34 +0530123 return 0.0
Makarand Bauskard0109a62017-07-26 16:29:22 +0530124
Dany Robert1f8be842021-11-04 05:12:09 +0000125def format_ces_api(data, param):
rtdany10a86d9c92021-09-03 19:21:06 +0530126 return data.format(
Dany Robert1f8be842021-11-04 05:12:09 +0000127 transaction_date=param.get("transaction_date"),
128 to_currency=param.get("to_currency"),
129 from_currency=param.get("from_currency")
rtdany10a86d9c92021-09-03 19:21:06 +0530130 )
131
Makarand Bauskard0109a62017-07-26 16:29:22 +0530132def enable_all_roles_and_domains():
133 """ enable all roles and domain for testing """
Makarand Bauskard0109a62017-07-26 16:29:22 +0530134 # add all roles to users
Rushabh Mehtabc4e2cd2017-10-17 12:30:34 +0530135 domains = frappe.get_all("Domain")
Makarand Bauskard0109a62017-07-26 16:29:22 +0530136 if not domains:
137 return
138
Rushabh Mehtabc4e2cd2017-10-17 12:30:34 +0530139 from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to
140 frappe.get_single('Domain Settings').set_active_domains(\
141 [d.name for d in domains])
142 add_all_roles_to('Administrator')
Manas Solanki966f1412017-11-23 15:22:10 +0530143
Ankush Menata8375232021-12-05 22:07:14 +0530144def set_defaults_for_tests():
145 from frappe.utils.nestedset import get_root_of
146
147 selling_settings = frappe.get_single("Selling Settings")
148 selling_settings.customer_group = get_root_of("Customer Group")
149 selling_settings.territory = get_root_of("Territory")
150 selling_settings.save()
151
Manas Solanki966f1412017-11-23 15:22:10 +0530152
153def insert_record(records):
154 for r in records:
155 doc = frappe.new_doc(r.get("doctype"))
156 doc.update(r)
157 try:
Ankush Menat9c7df2e2022-02-22 20:53:19 +0530158 doc.insert(ignore_permissions=True, ignore_if_duplicate=True)
Achilles Rasquinha2862e252018-01-30 13:47:18 +0530159 except frappe.DuplicateEntryError as e:
Manas Solanki966f1412017-11-23 15:22:10 +0530160 # pass DuplicateEntryError and continue
161 if e.args and e.args[0]==doc.doctype and e.args[1]==doc.name:
162 # make sure DuplicateEntryError is for the exact same doc and not a related doc
163 pass
164 else:
165 raise
Neil Trini Lasrado771fbb82018-08-24 15:15:56 +0530166
167def welcome_email():
Chinmay D. Pai612e58d2020-03-05 10:08:43 +0530168 site_name = get_default_company() or "ERPNext"
Suraj Shetty48e9bc32020-01-29 15:06:18 +0530169 title = _("Welcome to {0}").format(site_name)
bcornwellmottb2638762019-03-05 16:44:02 -0800170 return title