diff --git a/crm/fcrm/doctype/crm_lead/api.py b/crm/fcrm/doctype/crm_lead/api.py index 4abd959a..0407d890 100644 --- a/crm/fcrm/doctype/crm_lead/api.py +++ b/crm/fcrm/doctype/crm_lead/api.py @@ -1,20 +1,13 @@ -import json - import frappe from frappe import _ -from frappe.desk.form.load import get_docinfo +from pypika import Criterion @frappe.whitelist() def get_lead(name): Lead = frappe.qb.DocType("CRM Lead") - query = ( - frappe.qb.from_(Lead) - .select("*") - .where(Lead.name == name) - .limit(1) - ) + query = frappe.qb.from_(Lead).select("*").where(Lead.name == name).limit(1) lead = query.run(as_dict=True) if not len(lead): @@ -22,3 +15,127 @@ def get_lead(name): lead = lead.pop() return lead + +@frappe.whitelist() +def get_lead_fields(): + DocField = frappe.qb.DocType("DocField") + CustomField = frappe.qb.DocType("Custom Field") + not_allowed_fieldtypes = [ + "Section Break", + "Column Break", + ] + restricted_fieldnames = [ + "converted", + "lead_owner", + "status", + "image", + "naming_series" + ] + + fields = ( + frappe.qb.from_(DocField) + .select( + DocField.fieldname, + DocField.fieldtype, + DocField.label, + DocField.name, + DocField.options, + DocField.read_only, + DocField.idx, + ) + .where(DocField.parent == "CRM Lead") + .where(DocField.hidden == False) + .where(Criterion.notin(DocField.fieldtype, not_allowed_fieldtypes)) + .where(Criterion.notin(DocField.fieldname, restricted_fieldnames)) + .orderby(DocField.idx) + .run(as_dict=True) + ) + + custom_fields = ( + frappe.qb.from_(CustomField) + .select( + CustomField.fieldname, + CustomField.fieldtype, + CustomField.label, + CustomField.name, + CustomField.options, + CustomField.read_only, + CustomField.idx, + CustomField.insert_after, + ) + .where(CustomField.dt == "CRM Lead") + .where(CustomField.hidden == False) + .where(Criterion.notin(CustomField.fieldtype, not_allowed_fieldtypes)) + .orderby(CustomField.idx) + .run(as_dict=True) + ) + + all_fields = [] + all_fields.extend(fields) + + # Add custom fields based on insert_after + for custom_field in custom_fields: + if custom_field.insert_after: + for i, field in enumerate(all_fields): + if field.fieldname == custom_field.insert_after: + all_fields.insert(i + 1, custom_field) + break + else: + all_fields.prepend(custom_field) + + sections = {} + section_fields = [] + last_section = None + + for field in all_fields: + if field.fieldtype == "Tab Break" and last_section: + sections[last_section]["fields"] = section_fields + last_section = None + if field.read_only: + section_fields = [] + continue + if field.fieldtype == "Tab Break": + section_fields = [] + last_section = field.fieldname + sections[field.fieldname] = { + "label": field.label, + "opened": True, + "fields": [], + } + else: + section_fields.append(get_field_obj(field)) + + lead_fields = [] + for section in sections: + lead_fields.append(sections[section]) + + return lead_fields + +def get_field_obj(field): + obj = { + "label": field.label, + "type": get_type(field), + "name": field.fieldname, + } + + obj["placeholder"] = "Add " + field.label.lower() + "..." + + if field.fieldtype == "Link": + obj["placeholder"] = "Select " + field.label.lower() + "..." + obj["doctype"] = field.options + elif field.fieldtype == "Select": + obj["options"] = [{"label": option, "value": option} for option in field.options.split("\n")] + + if field.read_only: + obj["tooltip"] = "This field is read only and cannot be edited." + + return obj + +def get_type(field): + if field.fieldtype == "Data" and field.options == "Phone": + return "phone" + elif field.fieldtype == "Data" and field.options == "Email": + return "email" + elif field.read_only: + return "read_only" + return field.fieldtype.lower() \ No newline at end of file diff --git a/crm/fcrm/doctype/crm_lead/crm_lead.json b/crm/fcrm/doctype/crm_lead/crm_lead.json index 3aaa2ad6..d75ba940 100644 --- a/crm/fcrm/doctype/crm_lead/crm_lead.json +++ b/crm/fcrm/doctype/crm_lead/crm_lead.json @@ -8,36 +8,32 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ + "details", + "organization", + "website", + "industry", + "job_title", "naming_series", + "source", + "person_tab", "salutation", "first_name", - "middle_name", "last_name", - "column_break_izjs", - "lead_name", - "gender", - "image", - "column_break_lcuv", - "lead_owner", - "status", - "job_title", - "source", - "converted", + "email", + "mobile_no", "organization_tab", "section_break_uixv", - "organization", - "no_of_employees", + "lead_name", + "middle_name", + "gender", + "phone", "column_break_dbsv", - "website", + "status", + "lead_owner", + "no_of_employees", "annual_revenue", - "industry", - "contact_tab", - "section_break_ymew", - "email", - "column_break_sijm", - "mobile_no", - "column_break_sjtw", - "phone" + "image", + "converted" ], "fields": [ { @@ -67,20 +63,12 @@ "fieldtype": "Data", "label": "Last Name" }, - { - "fieldname": "column_break_lcuv", - "fieldtype": "Column Break" - }, { "fieldname": "gender", "fieldtype": "Link", "label": "Gender", "options": "Gender" }, - { - "fieldname": "column_break_izjs", - "fieldtype": "Column Break" - }, { "default": "Open", "fieldname": "status", @@ -91,10 +79,6 @@ "reqd": 1, "search_index": 1 }, - { - "fieldname": "section_break_ymew", - "fieldtype": "Section Break" - }, { "fieldname": "email", "fieldtype": "Data", @@ -110,20 +94,12 @@ "options": "URL", "read_only": 1 }, - { - "fieldname": "column_break_sijm", - "fieldtype": "Column Break" - }, { "fieldname": "mobile_no", "fieldtype": "Data", "label": "Mobile No", "options": "Phone" }, - { - "fieldname": "column_break_sjtw", - "fieldtype": "Column Break" - }, { "fieldname": "phone", "fieldtype": "Data", @@ -192,12 +168,8 @@ { "fieldname": "organization_tab", "fieldtype": "Tab Break", - "label": "Organization" - }, - { - "fieldname": "contact_tab", - "fieldtype": "Tab Break", - "label": "Contact" + "label": "Others", + "read_only": 1 }, { "fieldname": "organization", @@ -212,12 +184,22 @@ "in_list_view": 1, "in_standard_filter": 1, "label": "Converted" + }, + { + "fieldname": "person_tab", + "fieldtype": "Tab Break", + "label": "Person" + }, + { + "fieldname": "details", + "fieldtype": "Tab Break", + "label": "Details" } ], "image_field": "image", "index_web_pages_for_search": 1, "links": [], - "modified": "2023-11-13 13:35:35.783003", + "modified": "2023-11-21 13:02:11.680600", "modified_by": "Administrator", "module": "FCRM", "name": "CRM Lead", diff --git a/frontend/src/pages/Lead.vue b/frontend/src/pages/Lead.vue index 7e25019b..c6c0fe76 100644 --- a/frontend/src/pages/Lead.vue +++ b/frontend/src/pages/Lead.vue @@ -135,7 +135,7 @@