From fcd0489982e559c30991bd8cdb4ea354fd2e7c2f Mon Sep 17 00:00:00 2001 From: Casey Date: Tue, 16 Dec 2025 08:43:11 -0600 Subject: [PATCH 1/4] fix client query --- custom_ui/api/db/clients.py | 73 +++++++++++++++++-------------------- custom_ui/db_utils.py | 16 ++++++++ custom_ui/install.py | 14 ++++++- 3 files changed, 61 insertions(+), 42 deletions(-) diff --git a/custom_ui/api/db/clients.py b/custom_ui/api/db/clients.py index 760d998..717790b 100644 --- a/custom_ui/api/db/clients.py +++ b/custom_ui/api/db/clients.py @@ -101,49 +101,35 @@ def get_client(client_name): print("DEBUG: Client not found as Customer. Checking Lead.") lead_name = frappe.db.get_all("Lead", pluck="name", filters={"lead_name": client_name})[0] customer = frappe.get_doc("Lead", lead_name) + if not customer: + return build_error_response(f"Client '{client_name}' not found as Customer or Lead.", 404) + print("DEBUG: Retrieved customer/lead document:", customer.as_dict()) clientData = {**clientData, **customer.as_dict()} + links = [] if customer.doctype == "Customer": - for contact_link in customer.custom_add_contacts: - contact_doc = frappe.get_doc("Contact", contact_link.contact) - clientData["contacts"].append(contact_doc.as_dict()) + links = customer.get("custom_add_contacts", []) + customer.get("custom_select_address", []) else: - contact_names = frappe.db.get_all("Contact", pluck="name", filters={"links": ["like", f'%{{"link_doctype": "Lead", "link_name": client_name}}%']}) - for contact_name in contact_names: - contact_doc = frappe.get_doc("Contact", contact_name) - clientData["contacts"].append(contact_doc.as_dict()) + links = frappe.get_all( + "Dynamic Link", + filters={ + "link_doctype": "Lead", + "link_name": lead_name, + "parenttype": ["in", ["Address", "Contact"]], + }, + fields=[ + "parenttype as link_doctype", + "parent as link_name", + ] + ) - if customer.doctype == "Customer": - for address_link in customer.custom_select_address: - address_doc = frappe.get_doc("Address", address_link.address_name) - # # addressData = {"jobs": [], "contacts": []} - # addressData = {**addressData, **address_doc.as_dict()} - # addressData["estimates"] = frappe.db.get_all("Quotation", fields=["*"], filters={"custom_installation_address": address_doc.address_title}) - # addressData["onsite_meetings"] = frappe.db.get_all("On-Site Meeting", fields=["*"], filters={"address": address_doc.address_title}) - # jobs = frappe.db.get_all("Project", fields=["*"], or_filters=[ - # ["custom_installation_address", "=", address.address_title], - # ["custom_address", "=", address.address_title] - # ]) - # for job in jobs if jobs else []: - # jobData = {} - # jobData = {**jobData, **job} - # jobData["sales_invoices"] = frappe.db.get_all("Sales Invoice", fields=["*"], filters={"project": job.name}) - # jobData["payment_entries"] = frappe.db.get_all( - # "Payment Entry", - # fields=["*"], - # filters={"party_type": "Customer"}, - # or_filters=[ - # ["party", "=", client_name], - # ["party_name", "=", client_name] - # ]) - # jobData["sales_orders"] = frappe.db.get_all("Sales Order", fields=["*"], filters={"project": job.name}) - # jobData["tasks"] = frappe.db.get_all("Task", fields=["*"], filters={"project": job.name}) - # addressData["jobs"].append(jobData) - clientData["addresses"].append(address_doc.as_dict()) - else: - address_names = frappe.db.get_all("Address", pluck="name", filters={"links": ["like", f'%{{"link_doctype": "Lead", "link_name": client_name}}%']}) - for address_name in address_names: - address_doc = frappe.get_doc("Address", address_name) - clientData["addresses"].append(address_doc.as_dict()) + print("DEBUG: Retrieved links from lead:", links) + for link in links: + linked_doc = frappe.get_doc(link.link_doctype, link.link_name) + if link.link_doctype == "Contact": + clientData["contacts"].append(linked_doc.as_dict()) + elif link.link_doctype == "Address": + clientData["addresses"].append(linked_doc.as_dict()) + # TODO: Continue getting other linked docs like jobs, invoices, etc. return build_success_response(clientData) except frappe.ValidationError as ve: return build_error_response(str(ve), 400) @@ -348,6 +334,11 @@ def upsert_client(data): "phone": contact_doc.phone, "role": contact_doc.role }) + new_client_doc.append("links", { + "link_doctype": "Contact", + "link_name": contact_doc.name + } + ) new_client_doc.save(ignore_permissions=True) # Address -> Customer/Lead @@ -356,7 +347,9 @@ def upsert_client(data): "link_doctype": new_client_doc.doctype, "link_name": new_client_doc.name }) - + if new_client_doc.doctype == "Lead": + address_doc.lead_name = new_client_doc.lead_name + # Address -> Contact print("#####DEBUG: Linking address to contacts.") diff --git a/custom_ui/db_utils.py b/custom_ui/db_utils.py index d29913b..aa35bd6 100644 --- a/custom_ui/db_utils.py +++ b/custom_ui/db_utils.py @@ -50,7 +50,23 @@ def process_filters(filters): processed_filters = address_filters continue # Skip the rest of the loop for address field + customer_name_fields = ["custom_customer_to_bill", "lead_name"] if field_name == "customer_name" else [] + if customer_name_fields: + customer_name_filters = [] + for cust_field in customer_name_fields: + if match_mode in ("contains", "contains"): + customer_name_filters.append([cust_field, "like", f"%{filter_obj['value']}%"]) + elif match_mode in ("startswith", "starts_with"): + customer_name_filters.append([cust_field, "like", f"{filter_obj['value']}%"]) + elif match_mode in ("endswith", "ends_with"): + customer_name_filters.append([cust_field, "like", f"%{filter_obj['value']}"]) + elif match_mode in ("equals", "equals"): + customer_name_filters.append([cust_field, "=", filter_obj["value"]]) + else: + customer_name_filters.append([cust_field, "like", f"%{filter_obj['value']}%"]) + processed_filters = customer_name_filters + continue # Skip the rest of the loop for customer_name field if match_mode in ("contains", "contains"): processed_filters[mapped_field_name] = ["like", f"%{filter_obj['value']}%"] elif match_mode in ("startswith", "starts_with"): diff --git a/custom_ui/install.py b/custom_ui/install.py index eaf8bf3..190e5d6 100644 --- a/custom_ui/install.py +++ b/custom_ui/install.py @@ -132,6 +132,12 @@ def add_custom_fields(): options="Not Started\nIn Progress\nCompleted", default="Not Started", insert_after="job_status" + ), + dict( + fieldname="lead_name", + label="Lead Name", + fieldtype="Data", + insert_after="custom_customer_to_bill" ) ], "Contact": [ @@ -268,11 +274,12 @@ def update_address_fields(): ["custom_onsite_meeting_scheduled", "onsite_meeting_scheduled"], ["custom_estimate_sent_status", "estimate_sent_status"], ["custom_job_status", "job_status"], - ["custom_payment_received_status", "payment_received_status"] + ["custom_payment_received_status", "payment_received_status",], + ["custom_lead_name", "lead_name"] ], "Contact": [ ["custom_role", "role"], - ["custom_email", "email"] + ["custom_email", "email"], ], "On-Site Meeting": [ ["custom_notes", "notes"], @@ -285,6 +292,9 @@ def update_address_fields(): ], "Sales Order": [ ["custom_requires_half_payment", "requires_half_payment"] + ], + "Lead": [ + ["custom_customer_type", "customer_type"] ] } From 4401a541ebab404acf41e6ada3e60e3c016813f3 Mon Sep 17 00:00:00 2001 From: Casey Date: Tue, 16 Dec 2025 10:26:58 -0600 Subject: [PATCH 2/4] update mapping of data return for a lead --- custom_ui/api/db/clients.py | 20 ++++++++++---- custom_ui/db_utils.py | 27 +++++++++++++++++++ .../components/clientSubPages/Overview.vue | 10 ++++--- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/custom_ui/api/db/clients.py b/custom_ui/api/db/clients.py index 717790b..035cb9d 100644 --- a/custom_ui/api/db/clients.py +++ b/custom_ui/api/db/clients.py @@ -1,5 +1,5 @@ import frappe, json -from custom_ui.db_utils import build_error_response, process_query_conditions, build_datatable_dict, get_count_or_filters, build_success_response +from custom_ui.db_utils import build_error_response, process_query_conditions, build_datatable_dict, get_count_or_filters, build_success_response, map_lead_client # =============================================================================== # CLIENT MANAGEMENT API METHODS @@ -105,9 +105,18 @@ def get_client(client_name): return build_error_response(f"Client '{client_name}' not found as Customer or Lead.", 404) print("DEBUG: Retrieved customer/lead document:", customer.as_dict()) clientData = {**clientData, **customer.as_dict()} + if customer.doctype == "Lead": + clientData.update(map_lead_client(clientData)) links = [] if customer.doctype == "Customer": - links = customer.get("custom_add_contacts", []) + customer.get("custom_select_address", []) + links = ( + [{"link_doctype": "Contact", "link_name": row.contact} + for row in customer.get("custom_add_contacts", [])] + + + [{"link_doctype": "Address", "link_name": row.address} + for row in customer.get("custom_select_address", [])] + ) + else: links = frappe.get_all( "Dynamic Link", @@ -124,10 +133,11 @@ def get_client(client_name): print("DEBUG: Retrieved links from lead:", links) for link in links: - linked_doc = frappe.get_doc(link.link_doctype, link.link_name) - if link.link_doctype == "Contact": + print("DEBUG: Processing link:", link) + linked_doc = frappe.get_doc(link["link_doctype"], link["link_name"]) + if link["link_doctype"] == "Contact": clientData["contacts"].append(linked_doc.as_dict()) - elif link.link_doctype == "Address": + elif link["link_doctype"] == "Address": clientData["addresses"].append(linked_doc.as_dict()) # TODO: Continue getting other linked docs like jobs, invoices, etc. return build_success_response(clientData) diff --git a/custom_ui/db_utils.py b/custom_ui/db_utils.py index aa35bd6..6e7ab96 100644 --- a/custom_ui/db_utils.py +++ b/custom_ui/db_utils.py @@ -158,4 +158,31 @@ def build_full_address(doc): if first and second: return f"{first}, {second}" return first or second or "" + +def map_lead_client(client_data): + mappings = { + "lead_name": "customer_name", + "customer_type": "customer_type", + "territory": "territory", + "company_name": "company" + } + for lead_field, client_field in mappings.items(): + if lead_field in client_data: + print(f"DEBUG: Mapping field {lead_field} to {client_field} with value {client_data[lead_field]}") + client_data[client_field] = client_data[lead_field] + client_data["customer_group"] = "" # Leads don't have customer groups + return client_data + +def map_lead_update(client_data): + mappings = { + "customer_name": "lead_name", + "customer_type": "customer_type", + "territory": "territory", + "company": "company_name" + } + for client_field, lead_field in mappings.items(): + if client_field in client_data: + print(f"DEBUG: Mapping field {client_field} to {lead_field} with value {client_data[client_field]}") + client_data[lead_field] = client_data[client_field] + return client_data \ No newline at end of file diff --git a/frontend/src/components/clientSubPages/Overview.vue b/frontend/src/components/clientSubPages/Overview.vue index f03b6ec..ef54bde 100644 --- a/frontend/src/components/clientSubPages/Overview.vue +++ b/frontend/src/components/clientSubPages/Overview.vue @@ -1,10 +1,10 @@