updates for company effects
This commit is contained in:
parent
98ec082394
commit
7710a7c8fe
22 changed files with 941 additions and 186 deletions
|
|
@ -4,7 +4,7 @@ from custom_ui.db_utils import build_error_response, build_success_response, pro
|
|||
from custom_ui.services import DbService, ClientService, AddressService, ContactService
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_week_bid_meetings(week_start, week_end):
|
||||
def get_week_bid_meetings(week_start, week_end, company):
|
||||
"""Get On-Site Meetings scheduled within a specific week."""
|
||||
try:
|
||||
meetings = frappe.db.get_all(
|
||||
|
|
@ -12,7 +12,8 @@ def get_week_bid_meetings(week_start, week_end):
|
|||
fields=["*"],
|
||||
filters=[
|
||||
["start_time", ">=", week_start],
|
||||
["start_time", "<=", week_end]
|
||||
["start_time", "<=", week_end],
|
||||
["company", "=", company]
|
||||
],
|
||||
order_by="start_time asc"
|
||||
)
|
||||
|
|
@ -27,7 +28,7 @@ def get_week_bid_meetings(week_start, week_end):
|
|||
return build_error_response(str(e), 500)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_bid_meetings(fields=["*"], filters={}):
|
||||
def get_bid_meetings(fields=["*"], filters={}, company=None):
|
||||
"""Get paginated On-Site Meetings with filtering and sorting support."""
|
||||
try:
|
||||
print("DEBUG: Raw bid meeting options received:", filters)
|
||||
|
|
@ -53,13 +54,13 @@ def get_bid_meetings(fields=["*"], filters={}):
|
|||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_unscheduled_bid_meetings():
|
||||
def get_unscheduled_bid_meetings(company):
|
||||
"""Get On-Site Meetings that are unscheduled."""
|
||||
try:
|
||||
meetings = frappe.db.get_all(
|
||||
"On-Site Meeting",
|
||||
fields=["*"],
|
||||
filters={"status": "Unscheduled"},
|
||||
filters={"status": "Unscheduled", "company": company},
|
||||
order_by="creation desc"
|
||||
)
|
||||
for meeting in meetings:
|
||||
|
|
|
|||
|
|
@ -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, map_lead_client, build_address_title
|
||||
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, build_address_title, normalize_name
|
||||
from erpnext.crm.doctype.lead.lead import make_customer
|
||||
from custom_ui.api.db.addresses import address_exists
|
||||
from custom_ui.api.db.contacts import check_and_get_contact, create_contact, create_contact_links
|
||||
|
|
@ -167,6 +167,81 @@ def get_client_v2(client_name):
|
|||
return build_error_response(str(ve), 400)
|
||||
except Exception as e:
|
||||
return build_error_response(str(e), 500)
|
||||
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_clients_table_data_v2(filters={}, sortings=[], page=1, page_size=10):
|
||||
"""Get paginated client table data with filtering and sorting support."""
|
||||
try:
|
||||
filters = json.loads(filters) if isinstance(filters, str) else filters
|
||||
sortings = json.loads(sortings) if isinstance(sortings, str) else sortings
|
||||
page = int(page)
|
||||
page_size = int(page_size)
|
||||
print("DEBUG: Raw client table query received:", {
|
||||
"filters": filters,
|
||||
"sortings": sortings,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
})
|
||||
where_clauses = []
|
||||
values = []
|
||||
if filters.get("company"):
|
||||
where_clauses.append("c.company = %s")
|
||||
values.append(filters["company"]["value"])
|
||||
|
||||
if filters.get("address"):
|
||||
where_clauses.append("a.full_address LIKE %s")
|
||||
values.append(f"%{filters['address']['value']}%")
|
||||
|
||||
if filters.get("customer_name"):
|
||||
where_clauses.append("a.customer_name LIKE %s")
|
||||
values.append(f"%{filters['customer_name']['value']}%")
|
||||
|
||||
where_sql = ""
|
||||
if where_clauses:
|
||||
where_sql = "WHERE " + " AND ".join(where_clauses)
|
||||
|
||||
offset = (page - 1) * page_size
|
||||
|
||||
address_names = frappe.db.sql(f"""
|
||||
SELECT DISTINCT a.name
|
||||
FROM `tabAddress` a
|
||||
LEFT JOIN `tabAddress Company Link` c ON c.parent = a.name
|
||||
{where_sql}
|
||||
ORDER BY a.modified DESC
|
||||
LIMIT %s OFFSET %s
|
||||
""", values + [page_size, offset], as_dict=True)
|
||||
print("DEBUG: Address names retrieved:", address_names)
|
||||
|
||||
count = frappe.db.sql(f"""
|
||||
SELECT COUNT(DISTINCT a.name) as count
|
||||
FROM `tabAddress` a
|
||||
LEFT JOIN `tabAddress Company Link` c ON c.parent = a.name
|
||||
{where_sql}
|
||||
""", values, as_dict=True)[0]["count"]
|
||||
tableRows = []
|
||||
for address_name in address_names:
|
||||
address = AddressService.get_or_throw(address_name["name"])
|
||||
tableRow = {}
|
||||
tableRow["id"] = address.name
|
||||
tableRow["address"] = address.full_address
|
||||
tableRow["client_type"] = address.customer_type
|
||||
tableRow["customer_name"] = normalize_name(address.customer_name, "-#-")
|
||||
tableRow["companies"] = ", ".join([link.company for link in address.get("companies", [])])
|
||||
tableRows.append(tableRow)
|
||||
|
||||
table_data = build_datatable_dict(data=tableRows, count=count, page=page, page_size=page_size)
|
||||
|
||||
return build_success_response(table_data)
|
||||
except frappe.ValidationError as ve:
|
||||
return build_error_response(str(ve), 400)
|
||||
except Exception as e:
|
||||
print("ERROR in get_clients_table_data_v2:", str(e))
|
||||
return build_error_response(str(e), 500)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ def get_job(job_id=""):
|
|||
project = project.as_dict()
|
||||
project["job_address"] = address_doc
|
||||
project["client"] = ClientService.get_client_or_throw(project.customer)
|
||||
task_names = frappe.get_all("Task", filters={"project": job_id})
|
||||
project["tasks"] = [frappe.get_doc("Task", task_name).as_dict() for task_name in task_names]
|
||||
return build_success_response(project)
|
||||
except Exception as e:
|
||||
return build_error_response(str(e), 500)
|
||||
|
|
@ -167,55 +169,32 @@ def upsert_job(data):
|
|||
return {"status": "error", "message": str(e)}
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_install_projects(start_date=None, end_date=None):
|
||||
def get_projects_for_calendar(date, company=None, project_templates=[]):
|
||||
"""Get install projects for the calendar."""
|
||||
# Parse project_templates if it's a JSON string
|
||||
if isinstance(project_templates, str):
|
||||
project_templates = json.loads(project_templates)
|
||||
|
||||
# put some emojis in the print to make it stand out
|
||||
print("📅📅📅", date, "company:", company, "project_templates:", project_templates, "type:", type(project_templates))
|
||||
try:
|
||||
filters = {"project_template": "SNW Install"}
|
||||
filters = {"company": company} if company else {}
|
||||
if project_templates and len(project_templates) > 0:
|
||||
filters["project_template"] = ["in", project_templates]
|
||||
unscheduled_filters = filters.copy()
|
||||
unscheduled_filters["is_scheduled"] = 0
|
||||
filters["expected_start_date"] = date
|
||||
# If date range provided, we could filter, but for now let's fetch all open/active ones
|
||||
# or maybe filter by status not Closed/Completed if we want active ones.
|
||||
# The user said "unscheduled" are those with status "Open" (and no date).
|
||||
# extend filters into unscheduled_filters
|
||||
|
||||
projects = frappe.get_all("Project", fields=["*"], filters=filters)
|
||||
|
||||
calendar_events = []
|
||||
for project in projects:
|
||||
# Determine status
|
||||
status = "unscheduled"
|
||||
if project.get("expected_start_date"):
|
||||
status = "scheduled"
|
||||
|
||||
# Map to calendar event format
|
||||
event = {
|
||||
"id": project.name,
|
||||
"serviceType": project.project_name, # Using project name as service type/title
|
||||
"customer": project.customer,
|
||||
"status": status,
|
||||
"scheduledDate": project.expected_start_date,
|
||||
"scheduledTime": "08:00", # Default time if not specified? Project doesn't seem to have time.
|
||||
"duration": 480, # Default 8 hours?
|
||||
"foreman": project.get("custom_install_crew"),
|
||||
"crew": [], # Need to map crew
|
||||
"estimatedCost": project.estimated_costing,
|
||||
"priority": project.priority.lower() if project.priority else "medium",
|
||||
"notes": project.notes,
|
||||
"address": project.custom_installation_address
|
||||
}
|
||||
|
||||
calendar_events.append(event)
|
||||
|
||||
return {"status": "success", "data": calendar_events}
|
||||
project_names = frappe.get_all("Project", pluck="name", filters=filters)
|
||||
print("DEBUG: Found scheduled project names:", project_names)
|
||||
unscheduled_project_names = frappe.get_all("Project", pluck="name", filters=unscheduled_filters)
|
||||
print("DEBUG: Found unscheduled project names:", unscheduled_project_names)
|
||||
projects = [frappe.get_doc("Project", name).as_dict() for name in project_names]
|
||||
unscheduled_projects = [frappe.get_doc("Project", name).as_dict() for name in unscheduled_project_names]
|
||||
return build_success_response({ "projects": projects, "unscheduled_projects": unscheduled_projects })
|
||||
except Exception as e:
|
||||
return {"status": "error", "message": str(e)}
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_project_templates_for_company(company_name):
|
||||
"""Get project templates for a specific company."""
|
||||
try:
|
||||
templates = frappe.get_all(
|
||||
"Project Template",
|
||||
fields=["*"],
|
||||
filters={"company": company_name}
|
||||
)
|
||||
return build_success_response(templates)
|
||||
except Exception as e:
|
||||
return build_error_response(str(e), 500),
|
||||
return build_error_response(str(e), 500)
|
||||
|
|
@ -229,3 +229,7 @@ def build_history_entries(comments, versions):
|
|||
# Sort by timestamp descending
|
||||
history.sort(key=lambda x: x["timestamp"], reverse=True)
|
||||
return history
|
||||
|
||||
def normalize_name(name: str, split_target: str = "_") -> str:
|
||||
"""Normalize a name by splitting off anything after and including the split_target."""
|
||||
return name.split(split_target)[0] if split_target in name else name
|
||||
|
|
|
|||
|
|
@ -25,4 +25,27 @@ def after_insert(doc, method):
|
|||
|
||||
def before_insert(doc, method):
|
||||
# This is where we will add logic to set tasks and other properties of a job based on it's project_template
|
||||
pass
|
||||
pass
|
||||
|
||||
def before_save(doc, method):
|
||||
print("DEBUG: Before Save Triggered for Project:", doc.name)
|
||||
if doc.expected_start_date and doc.expected_end_date:
|
||||
doc.is_scheduled = 1
|
||||
else:
|
||||
doc.is_scheduled = 0
|
||||
|
||||
def after_save(doc, method):
|
||||
print("DEBUG: After Save Triggered for Project:", doc.name)
|
||||
if doc.project_template == "SNW Install":
|
||||
print("DEBUG: Project template is SNW Install, updating Address Job Status based on Project status")
|
||||
status_mapping = {
|
||||
"Open": "In Progress",
|
||||
"Completed": "Completed",
|
||||
"Closed": "Completed"
|
||||
}
|
||||
new_status = status_mapping.get(doc.status, "In Progress")
|
||||
AddressService.update_value(
|
||||
doc.job_address,
|
||||
"job_status",
|
||||
new_status
|
||||
)
|
||||
|
|
@ -1,7 +1,24 @@
|
|||
import frappe
|
||||
from custom_ui.services import AddressService, ClientService
|
||||
|
||||
def before_insert(doc, method):
|
||||
"""Set values before inserting a Task."""
|
||||
print("DEBUG: Before Insert Triggered for Task")
|
||||
project_doc = frappe.get_doc("Project", doc.project)
|
||||
if project_doc.custom_installation_address:
|
||||
doc.custom_property = project_doc.custom_installation_address
|
||||
doc.project_template = project_doc.project_template
|
||||
if project_doc.job_address:
|
||||
doc.custom_property = project_doc.job_address
|
||||
|
||||
def after_insert(doc, method):
|
||||
print("DEBUG: After Insert Triggered for Task")
|
||||
print("DEBUG: Linking Task to Customer and Address")
|
||||
AddressService.append_link_v2(
|
||||
doc.custom_property, "tasks", {"task": doc.name, "project_template": doc.project_template }
|
||||
)
|
||||
AddressService.append_link_v2(
|
||||
doc.custom_property, "links", {"link_doctype": "Task", "link_name": doc.name}
|
||||
)
|
||||
ClientService.append_link_v2(
|
||||
doc.customer, "tasks", {"task": doc.name, "project_template": doc.project_template }
|
||||
)
|
||||
|
||||
|
|
@ -44,7 +44,7 @@
|
|||
"documentation_url": null,
|
||||
"fetch_from": null,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "company",
|
||||
"fieldname": "task",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"hide_border": 0,
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
"in_preview": 0,
|
||||
"in_standard_filter": 0,
|
||||
"is_virtual": 0,
|
||||
"label": "Company",
|
||||
"label": "Task",
|
||||
"length": 0,
|
||||
"link_filters": null,
|
||||
"make_attachment_public": 0,
|
||||
|
|
@ -68,8 +68,8 @@
|
|||
"non_negative": 0,
|
||||
"oldfieldname": null,
|
||||
"oldfieldtype": null,
|
||||
"options": "Company",
|
||||
"parent": "Lead Company Link",
|
||||
"options": "Task",
|
||||
"parent": "Customer Task Link",
|
||||
"parentfield": "fields",
|
||||
"parenttype": "DocType",
|
||||
"permlevel": 0,
|
||||
|
|
@ -93,6 +93,70 @@
|
|||
"trigger": null,
|
||||
"unique": 0,
|
||||
"width": null
|
||||
},
|
||||
{
|
||||
"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": "project_template",
|
||||
"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": "Project Template",
|
||||
"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": "Project Template",
|
||||
"parent": "Customer Task 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,
|
||||
|
|
@ -114,10 +178,228 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "5f481f64a0f53ad40b09d8b5694265c1",
|
||||
"modified": "2026-01-15 00:40:39.197431",
|
||||
"module": "Custom",
|
||||
"name": "Lead Company Link",
|
||||
"migration_hash": null,
|
||||
"modified": "2026-01-19 18:10:16.782664",
|
||||
"module": "Custom UI",
|
||||
"name": "Customer Task 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": "task",
|
||||
"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": 1,
|
||||
"in_preview": 0,
|
||||
"in_standard_filter": 0,
|
||||
"is_virtual": 0,
|
||||
"label": "Task",
|
||||
"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": "Task",
|
||||
"parent": "Address Task 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": 1,
|
||||
"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
|
||||
},
|
||||
{
|
||||
"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": "project_template",
|
||||
"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": "Project Template",
|
||||
"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": "Project Template",
|
||||
"parent": "Address Task 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-19 18:10:02.359022",
|
||||
"module": "Custom UI",
|
||||
"name": "Address Task Link",
|
||||
"naming_rule": "",
|
||||
"nsm_parent_field": null,
|
||||
"parent_node": null,
|
||||
|
|
@ -268,8 +550,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:34.521684",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:17.097017",
|
||||
"module": "Custom",
|
||||
"name": "Lead Companies Link",
|
||||
"naming_rule": "",
|
||||
|
|
@ -486,8 +768,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:34.576521",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:17.150584",
|
||||
"module": "Custom",
|
||||
"name": "Address Project Link",
|
||||
"naming_rule": "",
|
||||
|
|
@ -704,8 +986,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:34.628136",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:17.203403",
|
||||
"module": "Custom",
|
||||
"name": "Address Quotation Link",
|
||||
"naming_rule": "",
|
||||
|
|
@ -922,8 +1204,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:34.681893",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:17.255846",
|
||||
"module": "Custom",
|
||||
"name": "Address On-Site Meeting Link",
|
||||
"naming_rule": "",
|
||||
|
|
@ -1140,8 +1422,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:34.737017",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:17.309600",
|
||||
"module": "Custom",
|
||||
"name": "Address Sales Order Link",
|
||||
"naming_rule": "",
|
||||
|
|
@ -1294,8 +1576,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:34.787995",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:17.361237",
|
||||
"module": "Custom",
|
||||
"name": "Contact Address Link",
|
||||
"naming_rule": "",
|
||||
|
|
@ -1448,8 +1730,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:34.837721",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:17.412683",
|
||||
"module": "Custom",
|
||||
"name": "Lead On-Site Meeting Link",
|
||||
"naming_rule": "",
|
||||
|
|
@ -2050,8 +2332,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:34.906370",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:17.483924",
|
||||
"module": "Selling",
|
||||
"name": "Quotation Template",
|
||||
"naming_rule": "",
|
||||
|
|
@ -2548,8 +2830,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:34.977831",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:17.558008",
|
||||
"module": "Selling",
|
||||
"name": "Quotation Template Item",
|
||||
"naming_rule": "",
|
||||
|
|
@ -2702,8 +2984,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:35.031029",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:17.609372",
|
||||
"module": "Custom UI",
|
||||
"name": "Customer Company Link",
|
||||
"naming_rule": "",
|
||||
|
|
@ -2856,8 +3138,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:35.084461",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:17.660893",
|
||||
"module": "Custom UI",
|
||||
"name": "Customer Address Link",
|
||||
"naming_rule": "",
|
||||
|
|
@ -3010,8 +3292,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:35.135851",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:17.712878",
|
||||
"module": "Custom UI",
|
||||
"name": "Customer Contact Link",
|
||||
"naming_rule": "",
|
||||
|
|
@ -3164,8 +3446,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:35.184768",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:17.765849",
|
||||
"module": "Custom",
|
||||
"name": "Address Contact Link",
|
||||
"naming_rule": "",
|
||||
|
|
@ -3318,8 +3600,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:35.236428",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:17.818352",
|
||||
"module": "Custom",
|
||||
"name": "Customer On-Site Meeting Link",
|
||||
"naming_rule": "",
|
||||
|
|
@ -3472,8 +3754,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:35.287145",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:17.870984",
|
||||
"module": "Custom",
|
||||
"name": "Customer Project Link",
|
||||
"naming_rule": "",
|
||||
|
|
@ -3626,8 +3908,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:35.338967",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:17.922695",
|
||||
"module": "Custom",
|
||||
"name": "Customer Quotation Link",
|
||||
"naming_rule": "",
|
||||
|
|
@ -3780,8 +4062,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:35.388711",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:17.975165",
|
||||
"module": "Custom",
|
||||
"name": "Customer Sales Order Link",
|
||||
"naming_rule": "",
|
||||
|
|
@ -3934,8 +4216,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:35.441876",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:18.027046",
|
||||
"module": "Custom",
|
||||
"name": "Lead Address Link",
|
||||
"naming_rule": "",
|
||||
|
|
@ -4088,8 +4370,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:35.492936",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:18.078476",
|
||||
"module": "Custom",
|
||||
"name": "Lead Contact Link",
|
||||
"naming_rule": "",
|
||||
|
|
@ -4242,8 +4524,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:35.545465",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:18.170095",
|
||||
"module": "Custom",
|
||||
"name": "Lead Quotation Link",
|
||||
"naming_rule": "",
|
||||
|
|
@ -4396,8 +4678,8 @@
|
|||
"make_attachments_public": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": null,
|
||||
"migration_hash": "7c3c71cf20b258daa783e541cb045a4b",
|
||||
"modified": "2026-01-16 04:11:35.604415",
|
||||
"migration_hash": "0df0ede31f640435231ba887f40eca91",
|
||||
"modified": "2026-01-19 20:52:18.238066",
|
||||
"module": "Custom",
|
||||
"name": "Address Company Link",
|
||||
"naming_rule": "",
|
||||
|
|
|
|||
1
custom_ui/fixtures/property_setter.json
Normal file
1
custom_ui/fixtures/property_setter.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
[]
|
||||
|
|
@ -181,10 +181,13 @@ doc_events = {
|
|||
},
|
||||
"Project": {
|
||||
"before_insert": "custom_ui.events.jobs.before_insert",
|
||||
"after_insert": "custom_ui.events.jobs.after_insert"
|
||||
"after_insert": "custom_ui.events.jobs.after_insert",
|
||||
"before_save": "custom_ui.events.jobs.before_save",
|
||||
"on_update": "custom_ui.events.jobs.after_save"
|
||||
},
|
||||
"Task": {
|
||||
"before_insert": "custom_ui.events.task.before_insert"
|
||||
"before_insert": "custom_ui.events.task.before_insert",
|
||||
"after_insert": "custom_ui.events.task.after_insert"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -216,6 +219,8 @@ fixtures = [
|
|||
"Address Contact Link",
|
||||
"Address Company Link",
|
||||
"Contact Address Link",
|
||||
"Address Task Link",
|
||||
"Customer Task Link"
|
||||
]]
|
||||
]
|
||||
},
|
||||
|
|
@ -249,7 +254,15 @@ fixtures = [
|
|||
["dt", "=", "Project Template"],
|
||||
["fieldname", "=", "company"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"dt": "Property Setter",
|
||||
"filters": [
|
||||
["doc_type", "=", "Lead"],
|
||||
["doc_type", "=", "Project"]
|
||||
]
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ def after_migrate():
|
|||
frappe.clear_cache(doctype=doctype)
|
||||
frappe.reload_doctype(doctype)
|
||||
|
||||
update_address_fields()
|
||||
# update_address_fields()
|
||||
# build_frontend()
|
||||
|
||||
|
||||
|
|
@ -146,6 +146,13 @@ def add_custom_fields():
|
|||
fieldtype="Link",
|
||||
options="Contact",
|
||||
insert_after="contacts"
|
||||
),
|
||||
dict(
|
||||
fieldname="tasks",
|
||||
label="Tasks",
|
||||
fieldtype="Table",
|
||||
options="Customer Task Link",
|
||||
insert_after="projects"
|
||||
)
|
||||
],
|
||||
"Lead": [
|
||||
|
|
@ -327,6 +334,13 @@ def add_custom_fields():
|
|||
fieldtype="Table",
|
||||
options="Address Company Link",
|
||||
insert_after="contacts"
|
||||
),
|
||||
dict(
|
||||
fieldname="tasks",
|
||||
label="Tasks",
|
||||
fieldtype="Table",
|
||||
options="Address Task Link",
|
||||
insert_after="projects"
|
||||
)
|
||||
],
|
||||
"Contact": [
|
||||
|
|
@ -539,6 +553,37 @@ def add_custom_fields():
|
|||
options="Customer",
|
||||
insert_after="job_address",
|
||||
description="The customer for whom the project is being executed."
|
||||
),
|
||||
dict(
|
||||
fieldname="expected_start_time",
|
||||
label="Expected Start Time",
|
||||
fieldtype="Time",
|
||||
insert_after="expected_start_date"
|
||||
),
|
||||
dict(
|
||||
fieldname="expected_end_time",
|
||||
label="Expected End Time",
|
||||
fieldtype="Time",
|
||||
insert_after="expected_end_date"
|
||||
),
|
||||
dict(
|
||||
fieldname="actual_start_time",
|
||||
label="Actual Start Time",
|
||||
fieldtype="Time",
|
||||
insert_after="actual_start_date"
|
||||
),
|
||||
dict(
|
||||
fieldname="actual_end_time",
|
||||
label="Actual End Time",
|
||||
fieldtype="Time",
|
||||
insert_after="actual_end_date"
|
||||
),
|
||||
dict(
|
||||
fieldname="is_scheduled",
|
||||
label="Is Scheduled",
|
||||
fieldtype="Check",
|
||||
default=0,
|
||||
insert_after="expected_end_time"
|
||||
)
|
||||
],
|
||||
"Project Template": [
|
||||
|
|
@ -550,6 +595,15 @@ def add_custom_fields():
|
|||
insert_after="project_type",
|
||||
description="The company associated with this project template."
|
||||
)
|
||||
],
|
||||
"Task": [
|
||||
dict(
|
||||
fieldname="project_template",
|
||||
label="Project Template",
|
||||
fieldtype="Link",
|
||||
options="Project Template",
|
||||
insert_after="project"
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue