diff --git a/erpnext/accounts/doctype/currency_exchange_settings/currency_exchange_settings.py b/erpnext/accounts/doctype/currency_exchange_settings/currency_exchange_settings.py new file mode 100644 index 00000000000..160e791978e --- /dev/null +++ b/erpnext/accounts/doctype/currency_exchange_settings/currency_exchange_settings.py @@ -0,0 +1,119 @@ +# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +import frappe +import requests +from frappe import _ +from frappe.model.document import Document +from frappe.utils import nowdate + + +class CurrencyExchangeSettings(Document): + # begin: auto-generated types + # This code is auto-generated. Do not modify anything in this block. + + from typing import TYPE_CHECKING + + if TYPE_CHECKING: + from frappe.types import DF + + from erpnext.accounts.doctype.currency_exchange_settings_details.currency_exchange_settings_details import ( + CurrencyExchangeSettingsDetails, + ) + from erpnext.accounts.doctype.currency_exchange_settings_result.currency_exchange_settings_result import ( + CurrencyExchangeSettingsResult, + ) + + access_key: DF.Data | None + api_endpoint: DF.Data + disabled: DF.Check + req_params: DF.Table[CurrencyExchangeSettingsDetails] + result_key: DF.Table[CurrencyExchangeSettingsResult] + service_provider: DF.Literal["frankfurter.app", "exchangerate.host", "Custom"] + url: DF.Data | None + use_http: DF.Check + # end: auto-generated types + + def validate(self): + self.set_parameters_and_result() + if frappe.flags.in_test or frappe.flags.in_install or frappe.flags.in_setup_wizard: + return + response, value = self.validate_parameters() + self.validate_result(response, value) + + def set_parameters_and_result(self): + if self.service_provider == "exchangerate.host": + if not self.access_key: + frappe.throw( + _("Access Key is required for Service Provider: {0}").format( + frappe.bold(self.service_provider) + ) + ) + + self.set("result_key", []) + self.set("req_params", []) + + self.api_endpoint = get_api_endpoint(self.service_provider, self.use_http) + self.append("result_key", {"key": "result"}) + self.append("req_params", {"key": "access_key", "value": self.access_key}) + self.append("req_params", {"key": "amount", "value": "1"}) + self.append("req_params", {"key": "date", "value": "{transaction_date}"}) + self.append("req_params", {"key": "from", "value": "{from_currency}"}) + self.append("req_params", {"key": "to", "value": "{to_currency}"}) + elif self.service_provider == "frankfurter.app": + self.set("result_key", []) + self.set("req_params", []) + + self.api_endpoint = get_api_endpoint(self.service_provider, self.use_http) + self.append("result_key", {"key": "rates"}) + self.append("result_key", {"key": "{to_currency}"}) + self.append("req_params", {"key": "base", "value": "{from_currency}"}) + self.append("req_params", {"key": "symbols", "value": "{to_currency}"}) + + def validate_parameters(self): + params = {} + for row in self.req_params: + params[row.key] = row.value.format( + transaction_date=nowdate(), to_currency="INR", from_currency="USD" + ) + + api_url = self.api_endpoint.format(transaction_date=nowdate(), to_currency="INR", from_currency="USD") + + try: + response = requests.get(api_url, params=params) + except requests.exceptions.RequestException as e: + frappe.throw("Error: " + str(e)) + + response.raise_for_status() + value = response.json() + + return response, value + + def validate_result(self, response, value): + try: + for key in self.result_key: + value = value[ + str(key.key).format(transaction_date=nowdate(), to_currency="INR", from_currency="USD") + ] + except Exception: + frappe.throw(_("Invalid result key. Response:") + " " + response.text) + if not isinstance(value, int | float): + frappe.throw(_("Returned exchange rate is neither integer not float.")) + + self.url = response.url + + +@frappe.whitelist() +def get_api_endpoint(service_provider: str | None = None, use_http: bool = False): + if service_provider and service_provider in ["exchangerate.host", "frankfurter.app"]: + if service_provider == "exchangerate.host": + api = "api.exchangerate.host/convert" + elif service_provider == "frankfurter.app": + api = "api.frankfurter.app/{transaction_date}" + + protocol = "https://" + if use_http: + protocol = "http://" + + return protocol + api + return None diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py index 3407b4377f3..d9e25d7def3 100644 --- a/erpnext/setup/install.py +++ b/erpnext/setup/install.py @@ -72,9 +72,30 @@ def set_single_defaults(): frappe.db.set_default("date_format", "dd-mm-yyyy") +<<<<<<< HEAD def create_compact_item_print_custom_field(): create_custom_field( "Print Settings", +======= +def setup_currency_exchange(): + ces = frappe.get_single("Currency Exchange Settings") + try: + ces.set("result_key", []) + ces.set("req_params", []) + + ces.api_endpoint = "https://api.frankfurter.app/{transaction_date}" + ces.append("result_key", {"key": "rates"}) + ces.append("result_key", {"key": "{to_currency}"}) + ces.append("req_params", {"key": "base", "value": "{from_currency}"}) + ces.append("req_params", {"key": "symbols", "value": "{to_currency}"}) + ces.save() + except frappe.ValidationError: + pass + + +def create_print_setting_custom_fields(): + create_custom_fields( +>>>>>>> 33e72111c7 (fix: Fix API endpoint for Frankfurter) { "label": _("Compact Item Print"), "fieldname": "compact_item_print",