big update

This commit is contained in:
Casey 2026-01-13 08:11:58 -06:00
parent 6853950cc5
commit 992672b51b
11 changed files with 647 additions and 64 deletions

View file

@ -1,6 +1,7 @@
import frappe import frappe
import json import json
from custom_ui.db_utils import build_error_response, build_success_response, process_filters, process_sorting from custom_ui.db_utils import build_error_response, build_success_response, process_filters, process_sorting
from custom_ui.services import DbService
@frappe.whitelist() @frappe.whitelist()
def get_week_bid_meetings(week_start, week_end): def get_week_bid_meetings(week_start, week_end):
@ -66,10 +67,10 @@ def get_unscheduled_bid_meetings():
@frappe.whitelist() @frappe.whitelist()
def create_bid_meeting(address, notes=""): def create_bid_meeting(address, notes="", company=None, contact=None):
"""Create a new On-Site Meeting with Unscheduled status.""" """Create a new On-Site Meeting with Unscheduled status."""
try: try:
print(f"DEBUG: Creating meeting with address='{address}', notes='{notes}'") print(f"DEBUG: Creating meeting with address='{address}', notes='{notes}', company='{company}'")
# Validate address parameter # Validate address parameter
if not address or address == "None" or not address.strip(): if not address or address == "None" or not address.strip():
@ -78,17 +79,23 @@ def create_bid_meeting(address, notes=""):
# Get the address document name from the full address string # Get the address document name from the full address string
address_name = frappe.db.get_value("Address", filters={"full_address": address}, fieldname="name") address_name = frappe.db.get_value("Address", filters={"full_address": address}, fieldname="name")
print(f"DEBUG: Address lookup result: address_name='{address_name}'") print(f"DEBUG: Address lookup result: address_name='{address_name}'")
if not address_name: if not address_name:
return build_error_response(f"Address '{address}' not found in the system.", 404) return build_error_response(f"Address '{address}' not found in the system.", 404)
address_doc = DbService.get("Address", address_name)
# Create the meeting with Unscheduled status # Create the meeting with Unscheduled status
meeting = frappe.get_doc({ meeting = frappe.get_doc({
"doctype": "On-Site Meeting", "doctype": "On-Site Meeting",
"address": address_name, "address": address_doc.name,
"notes": notes or "", "notes": notes or "",
"status": "Unscheduled" "status": "Unscheduled",
"company": company,
"contact": contact,
"party_type": address_doc.customer_type,
"party_name": address_doc.customer_name
}) })
meeting.flags.ignore_permissions = True meeting.flags.ignore_permissions = True
meeting.insert(ignore_permissions=True) meeting.insert(ignore_permissions=True)
@ -113,7 +120,9 @@ def update_bid_meeting(name, data):
"end_time": None, "end_time": None,
"notes": None, "notes": None,
"assigned_employee": None, "assigned_employee": None,
"completed_by": None "completed_by": None,
"contact": None,
"status": None
} }
try: try:
if isinstance(data, str): if isinstance(data, str):

View file

@ -258,6 +258,9 @@ def upsert_client(data):
contacts = data.get("contacts", []) contacts = data.get("contacts", [])
# Check for existing address # Check for existing address
client_doc = check_and_get_client_doc(customer_name)
if client_doc:
return build_error_response(f"Client with name '{customer_name}' already exists.", 400)
if address_exists( if address_exists(
data.get("address_line1"), data.get("address_line1"),
data.get("address_line2"), data.get("address_line2"),
@ -268,23 +271,22 @@ def upsert_client(data):
return build_error_response("This address already exists. Please use a different address or search for the address to find the associated client.", 400) return build_error_response("This address already exists. Please use a different address or search for the address to find the associated client.", 400)
# Handle customer creation/update # Handle customer creation/update
client_doc = check_and_get_client_doc(customer_name)
if not client_doc: print("#####DEBUG: Creating new lead.")
print("#####DEBUG: Creating new lead.") customer_type = data.get("customer_type", "Individual")
customer_type = data.get("customer_type", "Individual") primary_contact = find_primary_contact_or_throw(contacts)
primary_contact = find_primary_contact_or_throw(contacts) lead_data = {
lead_data = { "first_name": primary_contact.get("first_name"),
"first_name": primary_contact.get("first_name"), "last_name": primary_contact.get("last_name"),
"last_name": primary_contact.get("last_name"), "email_id": primary_contact.get("email"),
"email_id": primary_contact.get("email"), "phone": primary_contact.get("phone_number"),
"phone": primary_contact.get("phone_number"), "company": data.get("company"),
"company": data.get("company"), "custom_customer_name": customer_name,
"custom_customer_name": customer_name, "customer_type": customer_type
"customer_type": customer_type }
} if customer_type == "Company":
if customer_type == "Company": lead_data["company_name"] = data.get("customer_name")
lead_data["company_name"] = data.get("customer_name") client_doc = create_lead(lead_data)
client_doc = create_lead(lead_data)
print(f"#####DEBUG: {client_doc.doctype}:", client_doc.as_dict()) print(f"#####DEBUG: {client_doc.doctype}:", client_doc.as_dict())
# Handle address creation # Handle address creation
@ -295,7 +297,9 @@ def upsert_client(data):
"city": data.get("city"), "city": data.get("city"),
"state": data.get("state"), "state": data.get("state"),
"country": "United States", "country": "United States",
"pincode": data.get("pincode") "pincode": data.get("pincode"),
"customer_type": "Lead",
"customer_name": client_doc.name
}) })
#Handle contact creation #Handle contact creation
@ -330,24 +334,24 @@ def upsert_client(data):
}) })
contact_docs.append(contact_doc) contact_docs.append(contact_doc)
##### Create links # ##### Create links
# Customer -> Address # # Customer -> Address
if client_doc.doctype == "Customer": # if client_doc.doctype == "Customer":
print("#####DEBUG: Linking address to customer.") # print("#####DEBUG: Linking address to customer.")
client_doc.append("custom_select_address", { # client_doc.append("custom_select_address", {
"address_name": address_doc.name, # "address_name": address_doc.name,
}) # })
# Customer -> Contact # # Customer -> Contact
print("#####DEBUG: Linking contacts to customer.") # print("#####DEBUG: Linking contacts to customer.")
for contact_doc in contact_docs: # for contact_doc in contact_docs:
client_doc.append("custom_add_contacts", { # client_doc.append("custom_add_contacts", {
"contact": contact_doc.name, # "contact": contact_doc.name,
"email": contact_doc.custom_email, # "email": contact_doc.custom_email,
"phone": contact_doc.phone, # "phone": contact_doc.phone,
"role": contact_doc.role # "role": contact_doc.role
}) # })
client_doc.save(ignore_permissions=True) # client_doc.save(ignore_permissions=True)
# Address -> Customer/Lead # Address -> Customer/Lead
create_address_links(address_doc, client_doc, contact_docs) create_address_links(address_doc, client_doc, contact_docs)

View file

@ -111,14 +111,14 @@ def get_estimate_items():
@frappe.whitelist() @frappe.whitelist()
def get_estimate_from_address(full_address): def get_estimate_from_address(full_address):
address_name = frappe.db.get_value("Address", {"full_address": full_address}, "name") address_name = frappe.db.get_value("Address", {"full_address": full_address}, "name")
quotation_name = frappe.db.get_value("Quotation", {"custom_installation_address": address_name}, "name") quotation_name = frappe.db.get_value("Quotation", {"custom_job_address": address_name}, "name")
quotation_doc = frappe.get_doc("Quotation", quotation_name) quotation_doc = frappe.get_doc("Quotation", quotation_name)
return build_success_response(quotation_doc.as_dict()) return build_success_response(quotation_doc.as_dict())
# quotation = frappe.db.sql(""" # quotation = frappe.db.sql("""
# SELECT q.name, q.custom_installation_address # SELECT q.name, q.custom_job_address
# FROM `tabQuotation` q # FROM `tabQuotation` q
# JOIN `tabAddress` a # JOIN `tabAddress` a
# ON q.custom_installation_address = a.name # ON q.custom_job_address = a.name
# WHERE a.full_address =%s # WHERE a.full_address =%s
# """, (full_address,), as_dict=True) # """, (full_address,), as_dict=True)
# if quotation: # if quotation:
@ -156,8 +156,8 @@ def send_estimate_email(estimate_name):
primary = next((e for e in party.email_ids if e.is_primary), None) primary = next((e for e in party.email_ids if e.is_primary), None)
email = primary.email_id if primary else party.email_ids[0].email_id email = primary.email_id if primary else party.email_ids[0].email_id
if not email and quotation.custom_installation_address: if not email and quotation.custom_job_address:
address = frappe.get_doc("Address", quotation.custom_installation_address) address = frappe.get_doc("Address", quotation.custom_job_address)
email = getattr(address, 'email_id', None) email = getattr(address, 'email_id', None)
if not email: if not email:
return build_error_response("No email found for the customer or address.", 400) return build_error_response("No email found for the customer or address.", 400)
@ -431,7 +431,8 @@ def upsert_estimate(data):
"customer_address": data.get("address_name"), "customer_address": data.get("address_name"),
"contact_person": data.get("contact_name"), "contact_person": data.get("contact_name"),
"letter_head": data.get("company"), "letter_head": data.get("company"),
"custom_project_template": data.get("project_template", None) "custom_project_template": data.get("project_template", None),
"from_onsite_meeting": data.get("onsite_meeting", None)
}) })
for item in data.get("items", []): for item in data.get("items", []):
item = json.loads(item) if isinstance(item, str) else item item = json.loads(item) if isinstance(item, str) else item

View file

@ -25,11 +25,13 @@ def create_job_from_sales_order(sales_order_name):
project_template = frappe.get_doc("Project Template", "SNW Install") project_template = frappe.get_doc("Project Template", "SNW Install")
new_job = frappe.get_doc({ new_job = frappe.get_doc({
"doctype": "Project", "doctype": "Project",
"custom_installation_address": sales_order.custom_installation_address, "custom_address": sales_order.custom_job_address,
"project_name": sales_order.custom_installation_address, # "custom_installation_address": sales_order.custom_installation_address,
"project_name": sales_order.custom_job_address,
"project_template": project_template, "project_template": project_template,
"custom_warranty_duration_days": 90, "custom_warranty_duration_days": 90,
"sales_order": sales_order "sales_order": sales_order,
"custom_company": sales_order.company
}) })
new_job.insert() new_job.insert()
return build_success_response(new_job.as_dict()) return build_success_response(new_job.as_dict())

View file

@ -29,6 +29,7 @@ def get_job_task_table_data(filters={}, sortings={}, page=1, page_size=10):
tableRows = [] tableRows = []
for task in tasks: for task in tasks:
print("DEBUG: Processing task:", task)
tableRow = {} tableRow = {}
tableRow["id"] = task["name"] tableRow["id"] = task["name"]
tableRow["subject"] = task["subject"] tableRow["subject"] = task["subject"]

7
custom_ui/events/task.py Normal file
View file

@ -0,0 +1,7 @@
import frappe
def before_insert(doc, method):
"""Set values before inserting a Task."""
project_doc = frappe.get_doc("Project", doc.project)
if project_doc.custom_installation_address:
doc.custom_property = project_doc.custom_installation_address

View file

@ -562,8 +562,8 @@
"make_attachments_public": 0, "make_attachments_public": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": null, "menu_index": null,
"migration_hash": "d5c5525a76e0cba00a479f83d71ac74c", "migration_hash": "1db94a5f84dbbad8602c84d9153a9ce5",
"modified": "2026-01-09 09:08:21.281081", "modified": "2026-01-13 03:06:43.486249",
"module": "Selling", "module": "Selling",
"name": "Quotation Template", "name": "Quotation Template",
"naming_rule": "", "naming_rule": "",
@ -1060,8 +1060,8 @@
"make_attachments_public": 0, "make_attachments_public": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": null, "menu_index": null,
"migration_hash": "d5c5525a76e0cba00a479f83d71ac74c", "migration_hash": "1db94a5f84dbbad8602c84d9153a9ce5",
"modified": "2026-01-09 08:52:19.818789", "modified": "2026-01-13 03:06:43.578733",
"module": "Selling", "module": "Selling",
"name": "Quotation Template Item", "name": "Quotation Template Item",
"naming_rule": "", "naming_rule": "",
@ -1098,5 +1098,467 @@
"track_views": 0, "track_views": 0,
"translated_doctype": 0, "translated_doctype": 0,
"website_search_field": null "website_search_field": null
},
{
"_assign": null,
"_comments": null,
"_last_update": null,
"_liked_by": null,
"_user_tags": null,
"actions": [],
"allow_auto_repeat": 0,
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 1,
"app": null,
"autoname": null,
"beta": 0,
"color": null,
"colour": null,
"custom": 1,
"default_email_template": null,
"default_print_format": null,
"default_view": null,
"description": null,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"documentation": null,
"editable_grid": 1,
"email_append_to": 0,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible_depends_on": null,
"columns": 0,
"default": null,
"depends_on": null,
"description": null,
"documentation_url": null,
"fetch_from": null,
"fetch_if_empty": 0,
"fieldname": "section_break_flvp",
"fieldtype": "Section Break",
"hidden": 0,
"hide_border": 0,
"hide_days": 0,
"hide_seconds": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_preview": 0,
"in_standard_filter": 0,
"is_virtual": 0,
"label": null,
"length": 0,
"link_filters": null,
"make_attachment_public": 0,
"mandatory_depends_on": null,
"max_height": null,
"no_copy": 0,
"non_negative": 0,
"oldfieldname": null,
"oldfieldtype": null,
"options": null,
"parent": "Customer Company Link",
"parentfield": "fields",
"parenttype": "DocType",
"permlevel": 0,
"placeholder": null,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": null,
"read_only": 0,
"read_only_depends_on": null,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"show_dashboard": 0,
"show_on_timeline": 0,
"show_preview_popup": 0,
"sort_options": 0,
"translatable": 0,
"trigger": null,
"unique": 0,
"width": null
}
],
"force_re_route_to_default_view": 0,
"grid_page_length": 50,
"has_web_view": 0,
"hide_toolbar": 0,
"icon": null,
"image_field": null,
"in_create": 0,
"index_web_pages_for_search": 1,
"is_calendar_and_gantt": 0,
"is_published_field": null,
"is_submittable": 0,
"is_tree": 0,
"is_virtual": 0,
"issingle": 0,
"istable": 1,
"links": [],
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "1db94a5f84dbbad8602c84d9153a9ce5",
"modified": "2026-01-13 03:06:43.634983",
"module": "Custom UI",
"name": "Customer Company Link",
"naming_rule": "",
"nsm_parent_field": null,
"parent_node": null,
"permissions": [],
"print_outline": null,
"protect_attached_files": 0,
"queue_in_background": 0,
"quick_entry": 0,
"read_only": 0,
"recipient_account_field": null,
"restrict_to_domain": null,
"route": null,
"row_format": "Dynamic",
"rows_threshold_for_grid_search": 20,
"search_fields": null,
"sender_field": null,
"sender_name_field": null,
"show_name_in_global_search": 0,
"show_preview_popup": 0,
"show_title_field_in_link": 0,
"smallicon": null,
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"subject": null,
"subject_field": null,
"tag_fields": null,
"timeline_field": null,
"title_field": null,
"track_changes": 0,
"track_seen": 0,
"track_views": 0,
"translated_doctype": 0,
"website_search_field": null
},
{
"_assign": null,
"_comments": null,
"_last_update": null,
"_liked_by": null,
"_user_tags": null,
"actions": [],
"allow_auto_repeat": 0,
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 1,
"app": null,
"autoname": null,
"beta": 0,
"color": null,
"colour": null,
"custom": 1,
"default_email_template": null,
"default_print_format": null,
"default_view": null,
"description": null,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"documentation": null,
"editable_grid": 1,
"email_append_to": 0,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible_depends_on": null,
"columns": 0,
"default": null,
"depends_on": null,
"description": null,
"documentation_url": null,
"fetch_from": null,
"fetch_if_empty": 0,
"fieldname": "address",
"fieldtype": "Link",
"hidden": 0,
"hide_border": 0,
"hide_days": 0,
"hide_seconds": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_preview": 0,
"in_standard_filter": 0,
"is_virtual": 0,
"label": "Address",
"length": 0,
"link_filters": null,
"make_attachment_public": 0,
"mandatory_depends_on": null,
"max_height": null,
"no_copy": 0,
"non_negative": 0,
"oldfieldname": null,
"oldfieldtype": null,
"options": "Address",
"parent": "Customer Address Link",
"parentfield": "fields",
"parenttype": "DocType",
"permlevel": 0,
"placeholder": null,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": null,
"read_only": 0,
"read_only_depends_on": null,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"show_dashboard": 0,
"show_on_timeline": 0,
"show_preview_popup": 0,
"sort_options": 0,
"translatable": 0,
"trigger": null,
"unique": 0,
"width": null
}
],
"force_re_route_to_default_view": 0,
"grid_page_length": 50,
"has_web_view": 0,
"hide_toolbar": 0,
"icon": null,
"image_field": null,
"in_create": 0,
"index_web_pages_for_search": 1,
"is_calendar_and_gantt": 0,
"is_published_field": null,
"is_submittable": 0,
"is_tree": 0,
"is_virtual": 0,
"issingle": 0,
"istable": 1,
"links": [],
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": null,
"modified": "2026-01-13 04:04:51.277600",
"module": "Custom UI",
"name": "Customer Address Link",
"naming_rule": "",
"nsm_parent_field": null,
"parent_node": null,
"permissions": [],
"print_outline": null,
"protect_attached_files": 0,
"queue_in_background": 0,
"quick_entry": 0,
"read_only": 0,
"recipient_account_field": null,
"restrict_to_domain": null,
"route": null,
"row_format": "Dynamic",
"rows_threshold_for_grid_search": 20,
"search_fields": null,
"sender_field": null,
"sender_name_field": null,
"show_name_in_global_search": 0,
"show_preview_popup": 0,
"show_title_field_in_link": 0,
"smallicon": null,
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"subject": null,
"subject_field": null,
"tag_fields": null,
"timeline_field": null,
"title_field": null,
"track_changes": 0,
"track_seen": 0,
"track_views": 0,
"translated_doctype": 0,
"website_search_field": null
},
{
"_assign": null,
"_comments": null,
"_last_update": null,
"_liked_by": null,
"_user_tags": null,
"actions": [],
"allow_auto_repeat": 0,
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 1,
"app": null,
"autoname": null,
"beta": 0,
"color": null,
"colour": null,
"custom": 1,
"default_email_template": null,
"default_print_format": null,
"default_view": null,
"description": null,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"documentation": null,
"editable_grid": 1,
"email_append_to": 0,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible_depends_on": null,
"columns": 0,
"default": null,
"depends_on": null,
"description": null,
"documentation_url": null,
"fetch_from": null,
"fetch_if_empty": 0,
"fieldname": "contact",
"fieldtype": "Link",
"hidden": 0,
"hide_border": 0,
"hide_days": 0,
"hide_seconds": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_preview": 0,
"in_standard_filter": 0,
"is_virtual": 0,
"label": "Contact",
"length": 0,
"link_filters": null,
"make_attachment_public": 0,
"mandatory_depends_on": null,
"max_height": null,
"no_copy": 0,
"non_negative": 0,
"oldfieldname": null,
"oldfieldtype": null,
"options": "Contact",
"parent": "Customer Contact Link",
"parentfield": "fields",
"parenttype": "DocType",
"permlevel": 0,
"placeholder": null,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": null,
"read_only": 0,
"read_only_depends_on": null,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"show_dashboard": 0,
"show_on_timeline": 0,
"show_preview_popup": 0,
"sort_options": 0,
"translatable": 0,
"trigger": null,
"unique": 0,
"width": null
}
],
"force_re_route_to_default_view": 0,
"grid_page_length": 50,
"has_web_view": 0,
"hide_toolbar": 0,
"icon": null,
"image_field": null,
"in_create": 0,
"index_web_pages_for_search": 1,
"is_calendar_and_gantt": 0,
"is_published_field": null,
"is_submittable": 0,
"is_tree": 0,
"is_virtual": 0,
"issingle": 0,
"istable": 1,
"links": [],
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": null,
"modified": "2026-01-13 04:06:36.339054",
"module": "Custom UI",
"name": "Customer Contact Link",
"naming_rule": "",
"nsm_parent_field": null,
"parent_node": null,
"permissions": [],
"print_outline": null,
"protect_attached_files": 0,
"queue_in_background": 0,
"quick_entry": 0,
"read_only": 0,
"recipient_account_field": null,
"restrict_to_domain": null,
"route": null,
"row_format": "Dynamic",
"rows_threshold_for_grid_search": 20,
"search_fields": null,
"sender_field": null,
"sender_name_field": null,
"show_name_in_global_search": 0,
"show_preview_popup": 0,
"show_title_field_in_link": 0,
"smallicon": null,
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"subject": null,
"subject_field": null,
"tag_fields": null,
"timeline_field": null,
"title_field": null,
"track_changes": 0,
"track_seen": 0,
"track_views": 0,
"translated_doctype": 0,
"website_search_field": null
} }
] ]

View file

@ -174,6 +174,9 @@ doc_events = {
}, },
"Sales Order": { "Sales Order": {
"on_submit": "custom_ui.events.sales_order.on_submit", "on_submit": "custom_ui.events.sales_order.on_submit",
},
"Task": {
"before_insert": "custom_ui.events.task.before_insert"
} }
} }
@ -183,7 +186,10 @@ fixtures = [
"filters": [ "filters": [
["name", "in", [ ["name", "in", [
"Quotation Template", "Quotation Template",
"Quotation Template Item" "Quotation Template Item",
"Customer Company Link",
"Customer Address Link",
"Customer Contact Link"
]] ]]
] ]
}, },

View file

@ -72,6 +72,36 @@ def add_custom_fields():
print("\n🔧 Adding custom fields to doctypes...") print("\n🔧 Adding custom fields to doctypes...")
custom_fields = { custom_fields = {
"Customer": [
dict(
fieldname="companies",
label="Companies",
fieldtype="Table",
options="Customer Company Link",
insert_after="customer_type"
),
dict(
fieldname="from_lead",
label="From Lead",
fieldname="Link",
options="Lead",
insert_after="customer_name"
),
dict(
fieldname="properties",
label="Properties",
fieldtype="Table",
options="Customer Address Link",
insert_after="customer_name"
),
dict(
fieldname="contacts",
label="Contacts",
fieldtype="Table",
options="Customer Contact Link",
insert_after="properties"
)
],
"Lead": [ "Lead": [
dict( dict(
fieldname="customer_type", fieldname="customer_type",
@ -139,6 +169,20 @@ def add_custom_fields():
label="Lead Name", label="Lead Name",
fieldtype="Data", fieldtype="Data",
insert_after="custom_customer_to_bill" insert_after="custom_customer_to_bill"
),
dict(
fieldname="customer_type",
label="Customer Type",
fieldtype="Select",
options="Customer\nLead",
insert_after="lead_name"
),
dict(
fieldname="customer_name",
label="Customer Name",
fieldtype="Dynamic Link",
options="customer_type",
insert_after="customer_type"
) )
], ],
"Contact": [ "Contact": [
@ -185,6 +229,34 @@ def add_custom_fields():
fieldtype="Link", fieldtype="Link",
options="Employee", options="Employee",
insert_after="status" insert_after="status"
),
dict(
fieldname="company",
label="Company",
fieldtype="Link",
options="Company",
insert_after="assigned_employee"
),
dict(
fieldname="party_type",
label="Party Type",
fieldtype="Select",
options="Customer\nLead",
insert_after="company"
),
dict(
fieldname="party_name",
label="Party Name",
fieldtype="Dynamic Link",
options="party_type",
insert_after="party_type"
),
dict(
fieldname="contact",
label="Contact",
fieldtype="Link",
options="Contact",
insert_after="party_name"
) )
], ],
"Quotation": [ "Quotation": [
@ -220,6 +292,13 @@ def add_custom_fields():
insert_after="custom_installation_address", insert_after="custom_installation_address",
description="The address where the job will be performed.", description="The address where the job will be performed.",
allow_on_submit=1 allow_on_submit=1
),
dict(
fieldname="from_onsite_meeting",
label="From On-Site Meeting",
fieldtype="Link",
options="On-Site Meeting",
insert_after="custom_job_address"
) )
], ],
"Sales Order": [ "Sales Order": [
@ -357,10 +436,12 @@ def update_address_fields():
quotations = frappe.get_all("Quotation", pluck="name") quotations = frappe.get_all("Quotation", pluck="name")
addresses = frappe.get_all("Address", pluck="name") addresses = frappe.get_all("Address", pluck="name")
sales_orders = frappe.get_all("Sales Order", pluck="name") sales_orders = frappe.get_all("Sales Order", pluck="name")
tasks = frappe.get_all("Task", pluck="name")
total_addresses = len(addresses) total_addresses = len(addresses)
total_quotations = len(quotations) total_quotations = len(quotations)
total_sales_orders = len(sales_orders) total_sales_orders = len(sales_orders)
total_doctypes = total_addresses + total_quotations + total_sales_orders total_tasks = len(tasks)
total_doctypes = total_addresses + total_quotations + total_sales_orders + total_tasks
combined_doctypes = [] combined_doctypes = []
for sales_order in sales_orders: for sales_order in sales_orders:
combined_doctypes.append({"doctype": "Sales Order", "name": sales_order}) combined_doctypes.append({"doctype": "Sales Order", "name": sales_order})
@ -368,9 +449,10 @@ def update_address_fields():
combined_doctypes.append({"doctype": "Quotation", "name": quotation}) combined_doctypes.append({"doctype": "Quotation", "name": quotation})
for address in addresses: for address in addresses:
combined_doctypes.append({"doctype": "Address", "name": address}) combined_doctypes.append({"doctype": "Address", "name": address})
for task in tasks:
combined_doctypes.append({"doctype": "Task", "name": task})
print(f"\n📍 Updating field values for {total_addresses} addresses, {total_quotations} quotations, {total_sales_orders} sales orders, and {total_tasks} tasks...")
print(f"\n📍 Updating field values for {total_addresses} addresses, {total_quotations} quotations, and {total_sales_orders} sales orders...")
# Field update counters # Field update counters
field_counters = { field_counters = {
@ -389,7 +471,8 @@ def update_address_fields():
'quotations_updated': 0, 'quotations_updated': 0,
'sales_orders_updated': 0, 'sales_orders_updated': 0,
'customers_updated': 0, 'customers_updated': 0,
'contacts_updated': 0 'contacts_updated': 0,
'tasks_updated': 0
} }
onsite_meta = frappe.get_meta("On-Site Meeting") onsite_meta = frappe.get_meta("On-Site Meeting")
@ -553,7 +636,16 @@ def update_address_fields():
address_doc.save(ignore_permissions=True) address_doc.save(ignore_permissions=True)
field_counters['address_linked_to_customer'] += 1 field_counters['address_linked_to_customer'] += 1
field_counters['total_field_updates'] += 1 field_counters['total_field_updates'] += 1
if doc['doctype'] == "Task":
for task_name in tasks:
property = frappe.get_value("Task", task_name, "custom_property")
project = frappe.get_value("Task", task_name, "project")
project_address = frappe.get_value("Project", project, "custom_installation_address")
alt_project_address = frappe.get_value("Project", project, "custom_address")
if project_address or alt_project_address:
frappe.db.set_value("Task", task_name, "custom_property", project_address if project_address else alt_project_address)
field_counters['tasks_updated'] += 1
field_counters['total_field_updates'] += 1
@ -570,6 +662,7 @@ def update_address_fields():
print(f" • Sales Orders updated: {field_counters['sales_orders_updated']:,}") print(f" • Sales Orders updated: {field_counters['sales_orders_updated']:,}")
print(f" • Customers updated: {field_counters['customers_updated']:,}") print(f" • Customers updated: {field_counters['customers_updated']:,}")
print(f" • Total field updates: {field_counters['total_field_updates']:,}") print(f" • Total field updates: {field_counters['total_field_updates']:,}")
print(f" • Tasks Updated: {field_counters['tasks_updated']:,}")
print(f"\n📝 Field-specific updates:") print(f"\n📝 Field-specific updates:")
print(f" • Full Address: {field_counters['full_address']:,}") print(f" • Full Address: {field_counters['full_address']:,}")
print(f" • On-Site Meeting Status: {field_counters['custom_onsite_meeting_scheduled']:,}") print(f" • On-Site Meeting Status: {field_counters['custom_onsite_meeting_scheduled']:,}")

View file

@ -77,5 +77,3 @@ class AddressService:
print("DEBUG: Created new Address:", address.as_dict()) print("DEBUG: Created new Address:", address.as_dict())
return address return address

View file

@ -22,7 +22,7 @@ const FRAPPE_GET_JOB_TASK_LIST_METHOD = "custom_ui.api.db.jobs.get_job_task_tabl
const FRAPPE_GET_INSTALL_PROJECTS_METHOD = "custom_ui.api.db.jobs.get_install_projects"; const FRAPPE_GET_INSTALL_PROJECTS_METHOD = "custom_ui.api.db.jobs.get_install_projects";
const FRAPPE_GET_JOB_TEMPLATES_METHOD = "custom_ui.api.db.jobs.get_job_templates"; const FRAPPE_GET_JOB_TEMPLATES_METHOD = "custom_ui.api.db.jobs.get_job_templates";
// Task methods // Task methods
const FRAPPE_GET_TASKS_METHOD = "custom_ui.api.db.tasks.get_tasks_table_data"; const FRAPPE_GET_TASKS_METHOD = "custom_ui.api.db.tasks.get_job_task_table_data";
// Invoice methods // Invoice methods
const FRAPPE_GET_INVOICES_METHOD = "custom_ui.api.db.invoices.get_invoice_table_data"; const FRAPPE_GET_INVOICES_METHOD = "custom_ui.api.db.invoices.get_invoice_table_data";
const FRAPPE_UPSERT_INVOICE_METHOD = "custom_ui.api.db.invoices.upsert_invoice"; const FRAPPE_UPSERT_INVOICE_METHOD = "custom_ui.api.db.invoices.upsert_invoice";