fix estimate row rendering bug
This commit is contained in:
parent
07af3c52ea
commit
b3e6e4f6a2
8 changed files with 3705 additions and 4292 deletions
|
|
@ -145,7 +145,7 @@ def get_estimate(estimate_name):
|
||||||
est_dict["address_details"] = address_doc
|
est_dict["address_details"] = address_doc
|
||||||
|
|
||||||
est_dict["history"] = get_doc_history("Quotation", estimate_name)
|
est_dict["history"] = get_doc_history("Quotation", estimate_name)
|
||||||
est_dict["items"] = [ItemService.get_full_dict(item.item_code) for item in estimate.items]
|
est_dict["items"] = [{**ItemService.get_full_dict(item.item_code), **item.as_dict()} for item in estimate.items]
|
||||||
|
|
||||||
return build_success_response(est_dict)
|
return build_success_response(est_dict)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@ from custom_ui.services import AddressService, ClientService, TaskService
|
||||||
def before_insert(doc, method):
|
def before_insert(doc, method):
|
||||||
"""Set values before inserting a Task."""
|
"""Set values before inserting a Task."""
|
||||||
print("DEBUG: Before Insert Triggered for Task")
|
print("DEBUG: Before Insert Triggered for Task")
|
||||||
|
if doc.status == "Template":
|
||||||
|
print("DEBUG: Task is a Template, skipping project linking")
|
||||||
|
return
|
||||||
project_doc = frappe.get_doc("Project", doc.project)
|
project_doc = frappe.get_doc("Project", doc.project)
|
||||||
doc.project_template = project_doc.project_template
|
doc.project_template = project_doc.project_template
|
||||||
doc.customer = project_doc.customer
|
doc.customer = project_doc.customer
|
||||||
|
|
@ -12,6 +15,9 @@ def before_insert(doc, method):
|
||||||
|
|
||||||
def after_insert(doc, method):
|
def after_insert(doc, method):
|
||||||
print("DEBUG: After Insert Triggered for Task")
|
print("DEBUG: After Insert Triggered for Task")
|
||||||
|
if doc.status == "Template":
|
||||||
|
print("DEBUG: Task is a Template, skipping linking to Customer and Address")
|
||||||
|
return
|
||||||
print("DEBUG: Linking Task to Customer and Address")
|
print("DEBUG: Linking Task to Customer and Address")
|
||||||
AddressService.append_link_v2(
|
AddressService.append_link_v2(
|
||||||
doc.custom_property, "tasks", {"task": doc.name, "project_template": doc.project_template }
|
doc.custom_property, "tasks", {"task": doc.name, "project_template": doc.project_template }
|
||||||
|
|
@ -27,10 +33,12 @@ def after_insert(doc, method):
|
||||||
|
|
||||||
def before_save(doc, method):
|
def before_save(doc, method):
|
||||||
print("DEBUG: Before Save Triggered for Task:", doc.name)
|
print("DEBUG: Before Save Triggered for Task:", doc.name)
|
||||||
|
if doc.type:
|
||||||
task_type_weight = frappe.get_value("Task Type", doc.type, "weight") or 0
|
task_type_weight = frappe.get_value("Task Type", doc.type, "weight") or 0
|
||||||
if doc.task_weight != task_type_weight:
|
if doc.task_weight != task_type_weight:
|
||||||
print(f"DEBUG: Updating Task weight from {doc.task_weight} to {task_type_weight}")
|
print(f"DEBUG: Updating Task weight from {doc.task_weight} to {task_type_weight}")
|
||||||
doc.task_weight = task_type_weight
|
doc.task_weight = task_type_weight
|
||||||
|
if doc.status != "Template":
|
||||||
event = TaskService.determine_event(doc)
|
event = TaskService.determine_event(doc)
|
||||||
if event:
|
if event:
|
||||||
task_names = [task.name for task in TaskService.get_tasks_by_project(doc.project)]
|
task_names = [task.name for task in TaskService.get_tasks_by_project(doc.project)]
|
||||||
|
|
@ -38,6 +46,9 @@ def before_save(doc, method):
|
||||||
|
|
||||||
def after_save(doc, method):
|
def after_save(doc, method):
|
||||||
print("DEBUG: After Save Triggered for Task:", doc.name)
|
print("DEBUG: After Save Triggered for Task:", doc.name)
|
||||||
|
if doc.status == "Template":
|
||||||
|
print("DEBUG: Task is a Template, skipping after save logic")
|
||||||
|
return
|
||||||
if doc.project and doc.status == "Completed":
|
if doc.project and doc.status == "Completed":
|
||||||
print("DEBUG: Task is completed, checking if project has calculated 100% Progress.")
|
print("DEBUG: Task is completed, checking if project has calculated 100% Progress.")
|
||||||
project_doc = frappe.get_doc("Project", doc.project)
|
project_doc = frappe.get_doc("Project", doc.project)
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +1,100 @@
|
||||||
[
|
[
|
||||||
|
{
|
||||||
|
"default_value": null,
|
||||||
|
"doc_type": "Task Depends On",
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Property Setter",
|
||||||
|
"doctype_or_field": "DocType",
|
||||||
|
"field_name": null,
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"modified": "2026-02-07 03:50:27.263355",
|
||||||
|
"module": null,
|
||||||
|
"name": "Task Depends On-main-field_order",
|
||||||
|
"property": "field_order",
|
||||||
|
"property_type": "Data",
|
||||||
|
"row_name": null,
|
||||||
|
"value": "[\"task\", \"custom_depends_on_doctype\", \"custom_depends_on\", \"custom_event\", \"column_break_2\", \"subject\", \"project\"]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default_value": null,
|
||||||
|
"doc_type": "Project",
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Property Setter",
|
||||||
|
"doctype_or_field": "DocField",
|
||||||
|
"field_name": "percent_complete_method",
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"modified": "2026-02-07 04:16:27.055142",
|
||||||
|
"module": null,
|
||||||
|
"name": "Project-percent_complete_method-fetch_from",
|
||||||
|
"property": "fetch_from",
|
||||||
|
"property_type": "Small Text",
|
||||||
|
"row_name": null,
|
||||||
|
"value": "project_template.custom__complete_method"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default_value": null,
|
||||||
|
"doc_type": "Project",
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Property Setter",
|
||||||
|
"doctype_or_field": "DocField",
|
||||||
|
"field_name": "percent_complete_method",
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"modified": "2026-02-07 04:16:27.092804",
|
||||||
|
"module": null,
|
||||||
|
"name": "Project-percent_complete_method-fetch_if_empty",
|
||||||
|
"property": "fetch_if_empty",
|
||||||
|
"property_type": "Check",
|
||||||
|
"row_name": null,
|
||||||
|
"value": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default_value": null,
|
||||||
|
"doc_type": "Task",
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Property Setter",
|
||||||
|
"doctype_or_field": "DocField",
|
||||||
|
"field_name": "description",
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"modified": "2026-02-08 02:52:56.753089",
|
||||||
|
"module": null,
|
||||||
|
"name": "Task-description-fetch_from",
|
||||||
|
"property": "fetch_from",
|
||||||
|
"property_type": "Small Text",
|
||||||
|
"row_name": null,
|
||||||
|
"value": "type.description"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default_value": null,
|
||||||
|
"doc_type": "Task",
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Property Setter",
|
||||||
|
"doctype_or_field": "DocField",
|
||||||
|
"field_name": "description",
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"modified": "2026-02-08 02:52:56.836830",
|
||||||
|
"module": null,
|
||||||
|
"name": "Task-description-fetch_if_empty",
|
||||||
|
"property": "fetch_if_empty",
|
||||||
|
"property_type": "Check",
|
||||||
|
"row_name": null,
|
||||||
|
"value": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default_value": null,
|
||||||
|
"doc_type": "Task Type",
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Property Setter",
|
||||||
|
"doctype_or_field": "DocType",
|
||||||
|
"field_name": null,
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"modified": "2026-02-09 01:29:07.457962",
|
||||||
|
"module": null,
|
||||||
|
"name": "Task Type-main-field_order",
|
||||||
|
"property": "field_order",
|
||||||
|
"property_type": "Data",
|
||||||
|
"row_name": null,
|
||||||
|
"value": "[\"weight\", \"description\", \"base_date\", \"offset_days\", \"skip_weekends\", \"skip_holidays\", \"logic_key\", \"offset_direction\", \"title\", \"days\", \"calculate_from\", \"trigger\", \"task_type_calculate_from\", \"work_type\", \"no_due_date\", \"triggering_doctype\", \"custom_completion_trigger\", \"custom_completion_trigger_doctype\", \"target_percent\"]"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"default_value": null,
|
"default_value": null,
|
||||||
"doc_type": "Contact",
|
"doc_type": "Contact",
|
||||||
|
|
|
||||||
|
|
@ -313,5 +313,50 @@
|
||||||
"total_costing_amount": 0.0,
|
"total_costing_amount": 0.0,
|
||||||
"total_expense_claim": 0.0,
|
"total_expense_claim": 0.0,
|
||||||
"type": "Labor"
|
"type": "Labor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"act_end_date": null,
|
||||||
|
"act_start_date": null,
|
||||||
|
"actual_time": 0.0,
|
||||||
|
"closing_date": null,
|
||||||
|
"color": null,
|
||||||
|
"company": "Sprinklers Northwest",
|
||||||
|
"completed_by": null,
|
||||||
|
"completed_on": null,
|
||||||
|
"custom_foreman": "HR-EMP-00014",
|
||||||
|
"custom_property": null,
|
||||||
|
"customer": null,
|
||||||
|
"department": null,
|
||||||
|
"depends_on": [],
|
||||||
|
"depends_on_tasks": "",
|
||||||
|
"description": null,
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Task",
|
||||||
|
"duration": 0,
|
||||||
|
"exp_end_date": null,
|
||||||
|
"exp_start_date": null,
|
||||||
|
"expected_time": 0.0,
|
||||||
|
"is_group": 0,
|
||||||
|
"is_milestone": 0,
|
||||||
|
"is_template": 1,
|
||||||
|
"issue": null,
|
||||||
|
"modified": "2026-01-23 02:29:45.172285",
|
||||||
|
"name": "TASK-2025-00007",
|
||||||
|
"old_parent": "",
|
||||||
|
"parent_task": null,
|
||||||
|
"priority": "Low",
|
||||||
|
"progress": 0.0,
|
||||||
|
"project": null,
|
||||||
|
"project_template": null,
|
||||||
|
"review_date": null,
|
||||||
|
"start": 0,
|
||||||
|
"status": "Template",
|
||||||
|
"subject": "15-Day QA",
|
||||||
|
"task_weight": 0.0,
|
||||||
|
"template_task": null,
|
||||||
|
"total_billing_amount": 0.0,
|
||||||
|
"total_costing_amount": 0.0,
|
||||||
|
"total_expense_claim": 0.0,
|
||||||
|
"type": "15 Day Warranty Follow-Up"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
@ -195,7 +195,8 @@ doc_events = {
|
||||||
"Task": {
|
"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",
|
"after_insert": "custom_ui.events.task.after_insert",
|
||||||
"before_save": "custom_ui.events.task.before_save"
|
"before_save": "custom_ui.events.task.before_save",
|
||||||
|
"after_save": "custom_ui.events.task.after_save"
|
||||||
},
|
},
|
||||||
"Bid Meeting Note Form": {
|
"Bid Meeting Note Form": {
|
||||||
"after_insert": "custom_ui.events.general.attach_bid_note_form_to_project_template"
|
"after_insert": "custom_ui.events.general.attach_bid_note_form_to_project_template"
|
||||||
|
|
@ -257,7 +258,7 @@ scheduler_events = {
|
||||||
# "custom_ui.tasks.all"
|
# "custom_ui.tasks.all"
|
||||||
# ],
|
# ],
|
||||||
"daily": [
|
"daily": [
|
||||||
"custom_ui.scheduled_tasks.daily"
|
"custom_ui.scheduled_tasks.daily_task"
|
||||||
],
|
],
|
||||||
# "hourly": [
|
# "hourly": [
|
||||||
# "custom_ui.tasks.hourly"
|
# "custom_ui.tasks.hourly"
|
||||||
|
|
|
||||||
|
|
@ -850,11 +850,24 @@ def add_custom_fields():
|
||||||
meta = frappe.get_meta(doctype)
|
meta = frappe.get_meta(doctype)
|
||||||
for field_spec in field_options:
|
for field_spec in field_options:
|
||||||
fieldname = field_spec["fieldname"]
|
fieldname = field_spec["fieldname"]
|
||||||
if not meta.has_field(fieldname):
|
|
||||||
missing_fields.append(f"{doctype}: {fieldname}")
|
|
||||||
else:
|
|
||||||
# Field exists, check if specs match
|
|
||||||
custom_field_name = f"{doctype}-{fieldname}"
|
custom_field_name = f"{doctype}-{fieldname}"
|
||||||
|
|
||||||
|
# First check if it's a regular DocType field (not a custom field)
|
||||||
|
is_regular_field = False
|
||||||
|
if frappe.db.exists("DocType", doctype):
|
||||||
|
doctype_doc = frappe.get_doc("DocType", doctype)
|
||||||
|
for df in doctype_doc.fields:
|
||||||
|
if df.fieldname == fieldname:
|
||||||
|
is_regular_field = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if is_regular_field:
|
||||||
|
# It's a regular DocType field, skip it completely
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Check if field exists in meta or as a custom field
|
||||||
|
if meta.has_field(fieldname) or frappe.db.exists("Custom Field", custom_field_name):
|
||||||
|
# Field exists as a custom field, check if it needs updating
|
||||||
if frappe.db.exists("Custom Field", custom_field_name):
|
if frappe.db.exists("Custom Field", custom_field_name):
|
||||||
custom_field_doc = frappe.get_doc("Custom Field", custom_field_name)
|
custom_field_doc = frappe.get_doc("Custom Field", custom_field_name)
|
||||||
needs_update = False
|
needs_update = False
|
||||||
|
|
@ -870,6 +883,9 @@ def add_custom_fields():
|
||||||
|
|
||||||
if needs_update:
|
if needs_update:
|
||||||
fields_to_update.append((doctype, fieldname, field_spec))
|
fields_to_update.append((doctype, fieldname, field_spec))
|
||||||
|
else:
|
||||||
|
# Field doesn't exist at all, add to missing
|
||||||
|
missing_fields.append(f"{doctype}: {fieldname}")
|
||||||
|
|
||||||
if missing_fields:
|
if missing_fields:
|
||||||
print("\n❌ Missing custom fields:")
|
print("\n❌ Missing custom fields:")
|
||||||
|
|
@ -1543,7 +1559,7 @@ def create_bid_meeting_note_form_templates():
|
||||||
doc.title = form["title"]
|
doc.title = form["title"]
|
||||||
doc.description = form.get("description")
|
doc.description = form.get("description")
|
||||||
doc.project_template = form.get("project_template")
|
doc.project_template = form.get("project_template")
|
||||||
|
frappe.set_value("Project Template", doc.project_template, "bid_meeting_note_form",doc.name)
|
||||||
for idx, field in enumerate(form.get("fields", []), start=1):
|
for idx, field in enumerate(form.get("fields", []), start=1):
|
||||||
doc.append(
|
doc.append(
|
||||||
"fields",
|
"fields",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue