diff --git a/crm/fcrm/doctype/crm_currency_exchange_settings/__init__.py b/crm/fcrm/doctype/crm_currency_exchange_settings/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/crm/fcrm/doctype/crm_currency_exchange_settings/crm_currency_exchange_settings.js b/crm/fcrm/doctype/crm_currency_exchange_settings/crm_currency_exchange_settings.js deleted file mode 100644 index bda41c07..00000000 --- a/crm/fcrm/doctype/crm_currency_exchange_settings/crm_currency_exchange_settings.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -// frappe.ui.form.on("CRM Currency Exchange Settings", { -// refresh(frm) { - -// }, -// }); diff --git a/crm/fcrm/doctype/crm_currency_exchange_settings/crm_currency_exchange_settings.json b/crm/fcrm/doctype/crm_currency_exchange_settings/crm_currency_exchange_settings.json deleted file mode 100644 index 2faeb78b..00000000 --- a/crm/fcrm/doctype/crm_currency_exchange_settings/crm_currency_exchange_settings.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "actions": [], - "allow_rename": 1, - "creation": "2025-07-28 12:29:02.935286", - "doctype": "DocType", - "engine": "InnoDB", - "field_order": [ - "service_provider", - "access_key" - ], - "fields": [ - { - "default": "frankfurter.app", - "fieldname": "service_provider", - "fieldtype": "Select", - "in_list_view": 1, - "label": "Service Provider", - "options": "frankfurter.app\nexchangerate.host", - "reqd": 1 - }, - { - "depends_on": "eval:doc.service_provider == 'exchangerate.host';", - "fieldname": "access_key", - "fieldtype": "Data", - "label": "Access Key", - "mandatory_depends_on": "eval:doc.service_provider == 'exchangerate.host';" - } - ], - "grid_page_length": 50, - "index_web_pages_for_search": 1, - "issingle": 1, - "links": [], - "modified": "2025-07-28 12:30:08.080590", - "modified_by": "Administrator", - "module": "FCRM", - "name": "CRM Currency Exchange Settings", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "print": 1, - "read": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], - "row_format": "Dynamic", - "sort_field": "creation", - "sort_order": "DESC", - "states": [] -} diff --git a/crm/fcrm/doctype/crm_currency_exchange_settings/crm_currency_exchange_settings.py b/crm/fcrm/doctype/crm_currency_exchange_settings/crm_currency_exchange_settings.py deleted file mode 100644 index 1224e7ac..00000000 --- a/crm/fcrm/doctype/crm_currency_exchange_settings/crm_currency_exchange_settings.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright (c) 2025, 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 - - -class CRMCurrencyExchangeSettings(Document): - pass - - -def get_exchange_rate(from_currency, to_currency, date=None): - if not date: - date = "latest" - - api_used = "frankfurter" - - api_endpoint = f"https://api.frankfurter.app/{date}?from={from_currency}&to={to_currency}" - res = requests.get(api_endpoint, timeout=5) - if res.ok: - data = res.json() - return data["rates"][to_currency] - - # Fallback to exchangerate.host if Frankfurter API fails - ces = frappe.get_single("CRM Currency Exchange Settings") - if ces and ces.service_provider == "exchangerate.host": - api_used = "exchangerate.host" - if not ces.access_key: - frappe.throw( - _("Access Key is required for Service Provider: {0}").format( - frappe.bold(ces.service_provider) - ) - ) - - params = { - "access_key": ces.access_key, - "from": from_currency, - "to": to_currency, - "amount": 1, - } - - if date != "latest": - params["date"] = date - - api_endpoint = "https://api.exchangerate.host/convert" - - res = requests.get(api_endpoint, params=params, timeout=5) - if res.ok: - data = res.json() - return data["result"] - - frappe.log_error( - title="Exchange Rate Fetch Error", - message=f"Failed to fetch exchange rate from {from_currency} to {to_currency} using {api_used} API.", - ) - - if api_used == "frankfurter": - user = frappe.session.user - is_manager = ( - "System Manager" in frappe.get_roles(user) - or "Sales Manager" in frappe.get_roles(user) - or user == "Administrator" - ) - - if not is_manager: - frappe.throw( - _( - "Ask your manager to set up the Currency Exchange Provider, as default provider does not support currency conversion for {0} to {1}." - ).format(from_currency, to_currency) - ) - else: - frappe.throw( - _( - "Setup the Currency Exchange Provider as 'exchangerate.host' in settings, as default provider does not support currency conversion for {0} to {1}." - ).format(from_currency, to_currency) - ) - - frappe.throw( - _( - "Failed to fetch exchange rate from {0} to {1} on {2}. Please check your internet connection or try again later." - ).format(from_currency, to_currency, date) - ) diff --git a/crm/fcrm/doctype/crm_currency_exchange_settings/test_crm_currency_exchange_settings.py b/crm/fcrm/doctype/crm_currency_exchange_settings/test_crm_currency_exchange_settings.py deleted file mode 100644 index ec05d679..00000000 --- a/crm/fcrm/doctype/crm_currency_exchange_settings/test_crm_currency_exchange_settings.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -# import frappe -from frappe.tests import IntegrationTestCase - - -# On IntegrationTestCase, the doctype test records and all -# link-field test record dependencies are recursively loaded -# Use these module variables to add/remove to/from that list -EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"] -IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"] - - - -class IntegrationTestCRMCurrencyExchangeSettings(IntegrationTestCase): - """ - Integration tests for CRMCurrencyExchangeSettings. - Use this class for testing interactions between multiple components. - """ - - pass diff --git a/crm/fcrm/doctype/crm_deal/crm_deal.py b/crm/fcrm/doctype/crm_deal/crm_deal.py index a682d4ba..6bc2e020 100644 --- a/crm/fcrm/doctype/crm_deal/crm_deal.py +++ b/crm/fcrm/doctype/crm_deal/crm_deal.py @@ -6,11 +6,9 @@ from frappe import _ from frappe.desk.form.assign_to import add as assign from frappe.model.document import Document -from crm.fcrm.doctype.crm_currency_exchange_settings.crm_currency_exchange_settings import get_exchange_rate from crm.fcrm.doctype.crm_service_level_agreement.utils import get_sla -from crm.fcrm.doctype.crm_status_change_log.crm_status_change_log import ( - add_status_change_log, -) +from crm.fcrm.doctype.crm_status_change_log.crm_status_change_log import add_status_change_log +from crm.fcrm.doctype.fcrm_settings.fcrm_settings import get_exchange_rate class CRMDeal(Document): diff --git a/crm/fcrm/doctype/crm_organization/crm_organization.py b/crm/fcrm/doctype/crm_organization/crm_organization.py index 6c736eee..a8247627 100644 --- a/crm/fcrm/doctype/crm_organization/crm_organization.py +++ b/crm/fcrm/doctype/crm_organization/crm_organization.py @@ -4,7 +4,7 @@ import frappe from frappe.model.document import Document -from crm.fcrm.doctype.crm_currency_exchange_settings.crm_currency_exchange_settings import get_exchange_rate +from crm.fcrm.doctype.fcrm_settings.fcrm_settings import get_exchange_rate class CRMOrganization(Document): diff --git a/crm/fcrm/doctype/fcrm_settings/fcrm_settings.json b/crm/fcrm/doctype/fcrm_settings/fcrm_settings.json index 635c02d3..0e04b4d1 100644 --- a/crm/fcrm/doctype/fcrm_settings/fcrm_settings.json +++ b/crm/fcrm/doctype/fcrm_settings/fcrm_settings.json @@ -8,7 +8,12 @@ "defaults_tab", "restore_defaults", "enable_forecasting", + "currency_tab", "currency", + "exchange_rate_provider_section", + "service_provider", + "column_break_vqck", + "access_key", "branding_tab", "brand_name", "brand_logo", @@ -72,13 +77,42 @@ "in_list_view": 1, "label": "Currency", "options": "Currency" + }, + { + "fieldname": "currency_tab", + "fieldtype": "Tab Break", + "label": "Currency" + }, + { + "fieldname": "exchange_rate_provider_section", + "fieldtype": "Section Break", + "label": "Exchange Rate Provider" + }, + { + "default": "frankfurter.app", + "fieldname": "service_provider", + "fieldtype": "Select", + "label": "Service Provider", + "options": "frankfurter.app\nexchangerate.host", + "reqd": 1 + }, + { + "depends_on": "eval:doc.service_provider == 'exchangerate.host';", + "fieldname": "access_key", + "fieldtype": "Data", + "label": "Access Key", + "mandatory_depends_on": "eval:doc.service_provider == 'exchangerate.host';" + }, + { + "fieldname": "column_break_vqck", + "fieldtype": "Column Break" } ], "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2025-07-13 11:58:34.857638", - "modified_by": "Administrator", + "modified": "2025-07-28 17:04:24.585768", + "modified_by": "shariq@frappe.io", "module": "FCRM", "name": "FCRM Settings", "owner": "Administrator", diff --git a/crm/fcrm/doctype/fcrm_settings/fcrm_settings.py b/crm/fcrm/doctype/fcrm_settings/fcrm_settings.py index 7897bb1a..3c27695f 100644 --- a/crm/fcrm/doctype/fcrm_settings/fcrm_settings.py +++ b/crm/fcrm/doctype/fcrm_settings/fcrm_settings.py @@ -2,6 +2,7 @@ # For license information, please see license.txt import frappe +import requests from frappe import _ from frappe.custom.doctype.property_setter.property_setter import delete_property_setter, make_property_setter from frappe.model.document import Document @@ -132,3 +133,76 @@ def get_forecasting_script(): this.doc.probability = status.probability } }""" + + +def get_exchange_rate(from_currency, to_currency, date=None): + if not date: + date = "latest" + + api_used = "frankfurter" + + api_endpoint = f"https://api.frankfurter.app/{date}?from={from_currency}&to={to_currency}" + res = requests.get(api_endpoint, timeout=5) + if res.ok: + data = res.json() + return data["rates"][to_currency] + + # Fallback to exchangerate.host if Frankfurter API fails + settings = FCRMSettings("FCRM Settings") + if settings and settings.service_provider == "exchangerate.host": + api_used = "exchangerate.host" + if not settings.access_key: + frappe.throw( + _("Access Key is required for Service Provider: {0}").format( + frappe.bold(settings.service_provider) + ) + ) + + params = { + "access_key": settings.access_key, + "from": from_currency, + "to": to_currency, + "amount": 1, + } + + if date != "latest": + params["date"] = date + + api_endpoint = "https://api.exchangerate.host/convert" + + res = requests.get(api_endpoint, params=params, timeout=5) + if res.ok: + data = res.json() + return data["result"] + + frappe.log_error( + title="Exchange Rate Fetch Error", + message=f"Failed to fetch exchange rate from {from_currency} to {to_currency} using {api_used} API.", + ) + + if api_used == "frankfurter": + user = frappe.session.user + is_manager = ( + "System Manager" in frappe.get_roles(user) + or "Sales Manager" in frappe.get_roles(user) + or user == "Administrator" + ) + + if not is_manager: + frappe.throw( + _( + "Ask your manager to set up the Exchange Rate Provider, as default provider does not support currency conversion for {0} to {1}." + ).format(from_currency, to_currency) + ) + else: + frappe.throw( + _( + "Setup the Exchange Rate Provider as 'Exchangerate Host' in settings, as default provider does not support currency conversion for {0} to {1}." + ).format(from_currency, to_currency) + ) + + frappe.throw( + _( + "Failed to fetch exchange rate from {0} to {1} on {2}. Please check your internet connection or try again later." + ).format(from_currency, to_currency, date) + )