mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-17 00:18:39 +00:00
Co-authored-by: Diptanil Saha <diptanil@frappe.io>
This commit is contained in:
@@ -20,7 +20,11 @@
|
||||
"section_break_13",
|
||||
"carry_forward_communication_and_comments",
|
||||
"column_break_junk",
|
||||
"update_timestamp_on_new_communication"
|
||||
"update_timestamp_on_new_communication",
|
||||
"frappe_crm_section",
|
||||
"enable_frappe_crm_data_synchronization",
|
||||
"column_break_jbzj",
|
||||
"allowed_users"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@@ -105,6 +109,30 @@
|
||||
"fieldname": "enable_opportunity_creation_from_contact_us",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enable Opportunity Creation from Contact Us"
|
||||
},
|
||||
{
|
||||
"fieldname": "frappe_crm_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Frappe CRM"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_jbzj",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.enable_frappe_crm_data_synchronization === 1;",
|
||||
"fieldname": "allowed_users",
|
||||
"fieldtype": "Table MultiSelect",
|
||||
"label": "Allowed Users",
|
||||
"options": "Frappe CRM Allowed User",
|
||||
"permlevel": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "enable_frappe_crm_data_synchronization",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enable Frappe CRM Data Synchronization",
|
||||
"permlevel": 1
|
||||
}
|
||||
],
|
||||
"grid_page_length": 50,
|
||||
@@ -112,7 +140,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2026-06-11 23:09:49.750381",
|
||||
"modified": "2026-06-22 01:26:13.474915",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "CRM Settings",
|
||||
@@ -146,6 +174,16 @@
|
||||
"role": "Sales Master Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"permlevel": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields, delete_custom_fields
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
@@ -15,12 +16,16 @@ class CRMSettings(Document):
|
||||
if TYPE_CHECKING:
|
||||
from frappe.types import DF
|
||||
|
||||
from erpnext.crm.doctype.frappe_crm_allowed_user.frappe_crm_allowed_user import FrappeCRMAllowedUser
|
||||
|
||||
allow_lead_duplication_based_on_emails: DF.Check
|
||||
allowed_users: DF.TableMultiSelect[FrappeCRMAllowedUser]
|
||||
auto_creation_of_contact: DF.Check
|
||||
campaign_naming_by: DF.Literal["Campaign Name", "Naming Series"]
|
||||
carry_forward_communication_and_comments: DF.Check
|
||||
close_opportunity_after_days: DF.Int
|
||||
default_valid_till: DF.Data | None
|
||||
enable_frappe_crm_data_synchronization: DF.Check
|
||||
enable_opportunity_creation_from_contact_us: DF.Check
|
||||
update_timestamp_on_new_communication: DF.Check
|
||||
# end: auto-generated types
|
||||
@@ -28,6 +33,7 @@ class CRMSettings(Document):
|
||||
def validate(self):
|
||||
frappe.db.set_default("campaign_naming_by", self.get("campaign_naming_by", ""))
|
||||
self.validate_enable_opportunity_creation_from_contact_us()
|
||||
self.validate_allowed_users()
|
||||
|
||||
def validate_enable_opportunity_creation_from_contact_us(self):
|
||||
contact_disabled = frappe.get_single_value("Contact Us Settings", "is_disabled")
|
||||
@@ -38,3 +44,43 @@ class CRMSettings(Document):
|
||||
"Cannot enable Opportunity creation from Contact Us because the Contact Us form is disabled."
|
||||
)
|
||||
)
|
||||
|
||||
def validate_allowed_users(self):
|
||||
if self.enable_frappe_crm_data_synchronization and not self.allowed_users:
|
||||
frappe.throw(
|
||||
_(
|
||||
"Please add atleast one user on Allowed Users to allow Data Synchronization from Frappe CRM site."
|
||||
)
|
||||
)
|
||||
|
||||
def before_save(self):
|
||||
self.clear_allowed_users()
|
||||
|
||||
def on_update(self):
|
||||
self.custom_fields_for_frappe_crm_data_sync()
|
||||
|
||||
def clear_allowed_users(self):
|
||||
if not self.enable_frappe_crm_data_synchronization:
|
||||
self.allowed_users = []
|
||||
|
||||
def custom_fields_for_frappe_crm_data_sync(self):
|
||||
custom_fields = {
|
||||
"Quotation": [
|
||||
{
|
||||
"fieldname": "crm_deal",
|
||||
"fieldtype": "Data",
|
||||
"label": "Frappe CRM Deal",
|
||||
"insert_after": "party_name",
|
||||
}
|
||||
],
|
||||
"Customer": [
|
||||
{
|
||||
"fieldname": "crm_deal",
|
||||
"fieldtype": "Data",
|
||||
"label": "Frappe CRM Deal",
|
||||
"insert_after": "prospect_name",
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
create_custom_fields(custom_fields, ignore_validate=True)
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_bulk_edit": 1,
|
||||
"allow_rename": 1,
|
||||
"creation": "2026-06-22 00:47:12.265968",
|
||||
"doctype": "DocType",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"user"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "user",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "User",
|
||||
"options": "User",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"grid_page_length": 50,
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2026-06-22 01:49:54.586410",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Frappe CRM Allowed User",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"row_format": "Dynamic",
|
||||
"rows_threshold_for_grid_search": 20,
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
# Copyright (c) 2026, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class FrappeCRMAllowedUser(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
|
||||
|
||||
parent: DF.Data
|
||||
parentfield: DF.Data
|
||||
parenttype: DF.Data
|
||||
user: DF.Link
|
||||
# end: auto-generated types
|
||||
|
||||
_DOCTYPE_NAME = "Frappe CRM Allowed User"
|
||||
@@ -2,35 +2,12 @@ import json
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def create_custom_fields_for_frappe_crm():
|
||||
frappe.only_for("System Manager")
|
||||
custom_fields = {
|
||||
"Quotation": [
|
||||
{
|
||||
"fieldname": "crm_deal",
|
||||
"fieldtype": "Data",
|
||||
"label": "Frappe CRM Deal",
|
||||
"insert_after": "party_name",
|
||||
}
|
||||
],
|
||||
"Customer": [
|
||||
{
|
||||
"fieldname": "crm_deal",
|
||||
"fieldtype": "Data",
|
||||
"label": "Frappe CRM Deal",
|
||||
"insert_after": "prospect_name",
|
||||
}
|
||||
],
|
||||
}
|
||||
create_custom_fields(custom_fields, ignore_validate=True)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def create_prospect_against_crm_deal():
|
||||
validate_frappe_crm_sync()
|
||||
|
||||
doc = frappe.form_dict
|
||||
prospect = frappe.new_doc("Prospect")
|
||||
prospect.company_name = doc.organization or doc.lead_name
|
||||
@@ -161,6 +138,8 @@ CUSTOMER_ALLOWED_FIELDS = {
|
||||
|
||||
@frappe.whitelist()
|
||||
def create_customer(customer_data=None):
|
||||
validate_frappe_crm_sync()
|
||||
|
||||
if not customer_data:
|
||||
customer_data = frappe.form_dict
|
||||
|
||||
@@ -181,3 +160,21 @@ def create_customer(customer_data=None):
|
||||
except Exception:
|
||||
frappe.log_error(frappe.get_traceback(), "Error while creating customer against Frappe CRM Deal")
|
||||
pass
|
||||
|
||||
|
||||
def validate_frappe_crm_sync():
|
||||
CRMSettings = frappe.get_single("CRM Settings")
|
||||
if not CRMSettings.enable_frappe_crm_data_synchronization:
|
||||
frappe.throw(
|
||||
_("Frappe CRM data synchronization is not enabled on ERPNext. Contact System Manager of ERPNext.")
|
||||
)
|
||||
|
||||
allowed_users = [d.user for d in CRMSettings.allowed_users]
|
||||
|
||||
if frappe.session.user not in allowed_users:
|
||||
frappe.throw(
|
||||
_(
|
||||
"User not allowed to synchronize data from Frappe CRM on ERPNext. Contact System Manager of ERPNext."
|
||||
),
|
||||
exc=frappe.PermissionError,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user