feat: FB Lead Sync first cut
This commit is contained in:
parent
b1b7c5d246
commit
d0cccc2e61
@ -22,6 +22,8 @@ add_to_apps_screen = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export_python_type_annotations = True
|
||||||
|
|
||||||
# Includes in <head>
|
# Includes in <head>
|
||||||
# ------------------
|
# ------------------
|
||||||
|
|
||||||
|
|||||||
0
crm/lead_syncing/__init__.py
Normal file
0
crm/lead_syncing/__init__.py
Normal file
0
crm/lead_syncing/doctype/__init__.py
Normal file
0
crm/lead_syncing/doctype/__init__.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"allow_rename": 1,
|
||||||
|
"creation": "2025-09-26 19:45:47.696180",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"label",
|
||||||
|
"id",
|
||||||
|
"column_break_hgde",
|
||||||
|
"key",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "label",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Label"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_hgde",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "key",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Key",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "type",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Type"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "id",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "ID"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"grid_page_length": 50,
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"istable": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2025-09-26 19:48:30.897092",
|
||||||
|
"modified_by": "hussain@frappe.io",
|
||||||
|
"module": "Lead Syncing",
|
||||||
|
"name": "Facebook Lead Form Question",
|
||||||
|
"owner": "hussain@frappe.io",
|
||||||
|
"permissions": [],
|
||||||
|
"row_format": "Dynamic",
|
||||||
|
"sort_field": "creation",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"states": []
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
|
||||||
|
class FacebookLeadFormQuestion(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
|
||||||
|
|
||||||
|
id: DF.Data | None
|
||||||
|
key: DF.Data
|
||||||
|
label: DF.Data | None
|
||||||
|
parent: DF.Data
|
||||||
|
parentfield: DF.Data
|
||||||
|
parenttype: DF.Data
|
||||||
|
type: DF.Data | None
|
||||||
|
# end: auto-generated types
|
||||||
|
|
||||||
|
pass
|
||||||
0
crm/lead_syncing/doctype/facebook_page/__init__.py
Normal file
0
crm/lead_syncing/doctype/facebook_page/__init__.py
Normal file
8
crm/lead_syncing/doctype/facebook_page/facebook_page.js
Normal file
8
crm/lead_syncing/doctype/facebook_page/facebook_page.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
// frappe.ui.form.on("Facebook Page", {
|
||||||
|
// refresh(frm) {
|
||||||
|
|
||||||
|
// },
|
||||||
|
// });
|
||||||
83
crm/lead_syncing/doctype/facebook_page/facebook_page.json
Normal file
83
crm/lead_syncing/doctype/facebook_page/facebook_page.json
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"autoname": "field:id",
|
||||||
|
"creation": "2025-09-26 18:59:12.833879",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"page_name",
|
||||||
|
"account_id",
|
||||||
|
"category",
|
||||||
|
"column_break_eteo",
|
||||||
|
"id",
|
||||||
|
"access_token"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "category",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Category"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "id",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "ID",
|
||||||
|
"unique": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "account_id",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Account ID"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_eteo",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "access_token",
|
||||||
|
"fieldtype": "Small Text",
|
||||||
|
"label": "Access Token"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "page_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Page Name"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"grid_page_length": 50,
|
||||||
|
"in_create": 1,
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"link_doctype": "Facebook Lead Form",
|
||||||
|
"link_fieldname": "page"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"modified": "2025-09-26 19:36:59.413214",
|
||||||
|
"modified_by": "hussain@frappe.io",
|
||||||
|
"module": "Lead Syncing",
|
||||||
|
"name": "Facebook Page",
|
||||||
|
"naming_rule": "By fieldname",
|
||||||
|
"owner": "hussain@frappe.io",
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "System Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"row_format": "Dynamic",
|
||||||
|
"show_title_field_in_link": 1,
|
||||||
|
"sort_field": "creation",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"states": [],
|
||||||
|
"title_field": "page_name",
|
||||||
|
"track_changes": 1
|
||||||
|
}
|
||||||
24
crm/lead_syncing/doctype/facebook_page/facebook_page.py
Normal file
24
crm/lead_syncing/doctype/facebook_page/facebook_page.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
|
||||||
|
class FacebookPage(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
|
||||||
|
|
||||||
|
access_token: DF.SmallText | None
|
||||||
|
account_id: DF.Data | None
|
||||||
|
category: DF.Data | None
|
||||||
|
id: DF.Data | None
|
||||||
|
page_name: DF.Data | None
|
||||||
|
# end: auto-generated types
|
||||||
|
|
||||||
|
pass
|
||||||
22
crm/lead_syncing/doctype/facebook_page/test_facebook_page.py
Normal file
22
crm/lead_syncing/doctype/facebook_page/test_facebook_page.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# 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 IntegrationTestFacebookPage(IntegrationTestCase):
|
||||||
|
"""
|
||||||
|
Integration tests for FacebookPage.
|
||||||
|
Use this class for testing interactions between multiple components.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"allow_rename": 1,
|
||||||
|
"creation": "2025-09-26 18:54:57.313880",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"source_field_name",
|
||||||
|
"column_break_zbml",
|
||||||
|
"crm_field_name"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "source_field_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Source Field Name",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_zbml",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "crm_field_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "CRM Field Name",
|
||||||
|
"reqd": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"grid_page_length": 50,
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"istable": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2025-09-26 18:55:59.773584",
|
||||||
|
"modified_by": "hussain@frappe.io",
|
||||||
|
"module": "Lead Syncing",
|
||||||
|
"name": "Lead Form Field Mapping",
|
||||||
|
"owner": "hussain@frappe.io",
|
||||||
|
"permissions": [],
|
||||||
|
"row_format": "Dynamic",
|
||||||
|
"sort_field": "creation",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"states": []
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
|
||||||
|
class LeadFormFieldMapping(Document):
|
||||||
|
pass
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
frappe.ui.form.on("Lead Sync Source", {
|
||||||
|
refresh(frm) {
|
||||||
|
frm.add_custom_button(__('Sync Now'), () => {
|
||||||
|
frm.call("sync_leads").then(() => {
|
||||||
|
frappe.msgprint(__('Lead sync initiated.'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
105
crm/lead_syncing/doctype/lead_sync_source/lead_sync_source.json
Normal file
105
crm/lead_syncing/doctype/lead_sync_source/lead_sync_source.json
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"allow_rename": 1,
|
||||||
|
"autoname": "autoincrement",
|
||||||
|
"creation": "2025-09-26 18:51:41.145560",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"type",
|
||||||
|
"access_token",
|
||||||
|
"column_break_lwcw",
|
||||||
|
"last_synced_at",
|
||||||
|
"section_break_itlk",
|
||||||
|
"field_mapping",
|
||||||
|
"facebook_tab",
|
||||||
|
"facebook_page",
|
||||||
|
"column_break_uxlr",
|
||||||
|
"facebook_lead_form"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"default": "Facebook",
|
||||||
|
"fieldname": "type",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Type",
|
||||||
|
"options": "Facebook"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_lwcw",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "last_synced_at",
|
||||||
|
"fieldtype": "Datetime",
|
||||||
|
"label": "Last Synced At",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "access_token",
|
||||||
|
"fieldtype": "Small Text",
|
||||||
|
"label": "Access Token"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_itlk",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "field_mapping",
|
||||||
|
"fieldtype": "Table",
|
||||||
|
"label": "Field Mapping",
|
||||||
|
"options": "Lead Form Field Mapping"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.type===\"Facebook\"",
|
||||||
|
"fieldname": "facebook_tab",
|
||||||
|
"fieldtype": "Tab Break",
|
||||||
|
"label": "Facebook"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "facebook_page",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Facebook Page",
|
||||||
|
"options": "Facebook Page"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_uxlr",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "facebook_lead_form",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Facebook Lead Form",
|
||||||
|
"options": "Facebook Lead Form"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"grid_page_length": 50,
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2025-09-26 19:04:31.584094",
|
||||||
|
"modified_by": "hussain@frappe.io",
|
||||||
|
"module": "Lead Syncing",
|
||||||
|
"name": "Lead Sync Source",
|
||||||
|
"naming_rule": "Autoincrement",
|
||||||
|
"owner": "hussain@frappe.io",
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "System Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"row_format": "Dynamic",
|
||||||
|
"sort_field": "creation",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"states": [],
|
||||||
|
"title_field": "type",
|
||||||
|
"track_changes": 1
|
||||||
|
}
|
||||||
116
crm/lead_syncing/doctype/lead_sync_source/lead_sync_source.py
Normal file
116
crm/lead_syncing/doctype/lead_sync_source/lead_sync_source.py
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
from frappe.integrations.utils import make_get_request
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
FB_GRAPH_API_BASE = "https://graph.facebook.com"
|
||||||
|
FB_GRAPH_API_VERSION = "v23.0"
|
||||||
|
|
||||||
|
|
||||||
|
def get_fb_graph_api_url(endpoint: str) -> str:
|
||||||
|
if endpoint.startswith("/"):
|
||||||
|
endpoint = endpoint[1:]
|
||||||
|
|
||||||
|
return f"{FB_GRAPH_API_BASE}/{FB_GRAPH_API_VERSION}/{endpoint}"
|
||||||
|
|
||||||
|
|
||||||
|
class LeadSyncSource(Document):
|
||||||
|
def before_save(self):
|
||||||
|
if self.type == "Facebook" and self.access_token:
|
||||||
|
fetch_and_store_pages_from_facebook(self.access_token)
|
||||||
|
pass
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def sync_leads(self):
|
||||||
|
if self.type == "Facebook" and self.access_token:
|
||||||
|
sync_leads_from_facebook(self.access_token, self.facebook_lead_form)
|
||||||
|
|
||||||
|
|
||||||
|
def sync_leads_from_facebook(access_token: str, lead_form_id: str) -> None:
|
||||||
|
url = get_fb_graph_api_url(f"/{lead_form_id}/leads")
|
||||||
|
leads = make_get_request(
|
||||||
|
url,
|
||||||
|
params={
|
||||||
|
"access_token": access_token,
|
||||||
|
"fields": "id,created_time,field_data",
|
||||||
|
"limit": 15000,
|
||||||
|
},
|
||||||
|
).get("data", [])
|
||||||
|
for lead in leads:
|
||||||
|
frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "CRM Lead",
|
||||||
|
"first_name": lead["field_data"][0]["values"][0],
|
||||||
|
"source": "Facebook",
|
||||||
|
}
|
||||||
|
).insert(ignore_permissions=True)
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_and_store_pages_from_facebook(access_token: str) -> None:
|
||||||
|
account_details = get_fb_account_details(access_token)
|
||||||
|
if not account_details.get("id"):
|
||||||
|
frappe.log_error("Invalid access token provided for Facebook.", "Lead Sync Source")
|
||||||
|
return
|
||||||
|
|
||||||
|
url = get_fb_graph_api_url("/me/accounts")
|
||||||
|
pages = make_get_request(url, params={"access_token": access_token}).get("data", [])
|
||||||
|
for page in pages:
|
||||||
|
page_id = page["id"]
|
||||||
|
already_synced = frappe.db.exists("Facebook Page", page_id)
|
||||||
|
if not already_synced:
|
||||||
|
create_facebook_page_in_db(page, account_details)
|
||||||
|
fetch_and_store_leadgen_forms_from_facebook(page_id, page["access_token"])
|
||||||
|
|
||||||
|
|
||||||
|
def get_fb_account_details(access_token: str) -> dict:
|
||||||
|
url = get_fb_graph_api_url("me")
|
||||||
|
return make_get_request(url, params={"access_token": access_token})
|
||||||
|
|
||||||
|
|
||||||
|
def create_facebook_page_in_db(page: dict, account_details: dict) -> None:
|
||||||
|
frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Facebook Page",
|
||||||
|
"page_name": page["name"],
|
||||||
|
"id": page["id"],
|
||||||
|
"category": page["category"],
|
||||||
|
"access_token": page["access_token"],
|
||||||
|
"account_id": account_details["id"],
|
||||||
|
}
|
||||||
|
).insert(ignore_permissions=True)
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_and_store_leadgen_forms_from_facebook(page_id: str, page_access_token: str) -> None:
|
||||||
|
fields = "id,name,questions"
|
||||||
|
url = get_fb_graph_api_url(f"/{page_id}/leadgen_forms")
|
||||||
|
forms = make_get_request(
|
||||||
|
url,
|
||||||
|
params={
|
||||||
|
"access_token": page_access_token,
|
||||||
|
"fields": fields,
|
||||||
|
"limit": 15000,
|
||||||
|
},
|
||||||
|
).get("data", [])
|
||||||
|
for form in forms:
|
||||||
|
form_id = form["id"]
|
||||||
|
already_synced = frappe.db.exists("Facebook Lead Form", form_id)
|
||||||
|
if already_synced:
|
||||||
|
continue
|
||||||
|
create_facebook_lead_form_in_db(form, page_id)
|
||||||
|
|
||||||
|
|
||||||
|
def create_facebook_lead_form_in_db(form: dict, page_id: str) -> None:
|
||||||
|
form_doc = frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Facebook Lead Form",
|
||||||
|
"form_name": form["name"],
|
||||||
|
"id": form["id"],
|
||||||
|
"page": page_id,
|
||||||
|
"questions": form["questions"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
frappe.errprint(form_doc.as_dict())
|
||||||
|
form_doc.insert(ignore_permissions=True)
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
# 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 IntegrationTestLeadSyncSource(IntegrationTestCase):
|
||||||
|
"""
|
||||||
|
Integration tests for LeadSyncSource.
|
||||||
|
Use this class for testing interactions between multiple components.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass
|
||||||
@ -1 +1,2 @@
|
|||||||
FCRM
|
FCRM
|
||||||
|
Lead Syncing
|
||||||
@ -61,4 +61,4 @@ typing-modules = ["frappe.types.DF"]
|
|||||||
[tool.ruff.format]
|
[tool.ruff.format]
|
||||||
quote-style = "double"
|
quote-style = "double"
|
||||||
indent-style = "tab"
|
indent-style = "tab"
|
||||||
docstring-code-format = true
|
# docstring-code-format = true
|
||||||
Loading…
x
Reference in New Issue
Block a user