build meeting notes form in install on migrate
This commit is contained in:
parent
6cd3d138ad
commit
c024e7fd86
12 changed files with 227 additions and 124 deletions
|
|
@ -445,12 +445,16 @@ def upsert_client(data):
|
|||
address_docs = []
|
||||
for address in addresses:
|
||||
is_billing = True if address.get("is_billing_address") else False
|
||||
is_service = True if address.get("is_service_address") else False
|
||||
print("#####DEBUG: Creating address with data:", address)
|
||||
address_doc = AddressService.create_address({
|
||||
"address_title": AddressService.build_address_title(customer_name, address),
|
||||
"address_line1": address.get("address_line1"),
|
||||
"address_line2": address.get("address_line2"),
|
||||
"address_type": "Billing" if is_billing else "Service",
|
||||
"custom_billing_address": is_billing,
|
||||
"is_service_address": is_service,
|
||||
"is_primary_address": is_billing,
|
||||
"city": address.get("city"),
|
||||
"state": address.get("state"),
|
||||
"country": "United States",
|
||||
|
|
@ -480,13 +484,12 @@ def upsert_client(data):
|
|||
"address": address_doc.name
|
||||
})
|
||||
client_doc.save(ignore_permissions=True)
|
||||
client_dict = client_doc.as_dict()
|
||||
client_dict["contacts"] = [contact.as_dict() for contact in contact_docs]
|
||||
client_dict["addresses"] = [address.as_dict() for address in address_docs]
|
||||
|
||||
frappe.local.message_log = []
|
||||
return build_success_response({
|
||||
"customer": client_doc.as_dict(),
|
||||
"address": [address_doc.as_dict() for address_doc in address_docs],
|
||||
"contacts": [contact_doc.as_dict() for contact_doc in contact_docs]
|
||||
})
|
||||
return build_success_response(client_dict)
|
||||
except frappe.ValidationError as ve:
|
||||
return build_error_response(str(ve), 400)
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -485,7 +485,7 @@ def upsert_estimate(data):
|
|||
"letter_head": data.get("company"),
|
||||
"custom_project_template": data.get("project_template", None),
|
||||
"custom_quotation_template": data.get("quotation_template", None),
|
||||
"from_onsite_meeting": data.get("onsite_meeting", None)
|
||||
"from_onsite_meeting": data.get("from_onsite_meeting", None)
|
||||
})
|
||||
for item in data.get("items", []):
|
||||
item = json.loads(item) if isinstance(item, str) else item
|
||||
|
|
|
|||
|
|
@ -12,7 +12,31 @@ def get_service_appointments(companies, filters={}):
|
|||
filters = json.loads(filters)
|
||||
filters["company"] = ["in", companies]
|
||||
service_appointment_names = frappe.get_all(
|
||||
"Service Appointment",
|
||||
"Service Address 2",
|
||||
filters=filters,
|
||||
pluck="name"
|
||||
)
|
||||
service_appointments = [
|
||||
ServiceAppointmentService.get_full_dict(name)
|
||||
for name in service_appointment_names
|
||||
]
|
||||
return build_success_response(service_appointments)
|
||||
except Exception as e:
|
||||
return build_error_response(str(e), 500)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_unscheduled_service_appointments(companies):
|
||||
"""Get unscheduled Service Appointments for given companies."""
|
||||
try:
|
||||
if isinstance(companies, str):
|
||||
companies = json.loads(companies)
|
||||
filters = {
|
||||
"company": ["in", companies],
|
||||
"expected_start_date": None,
|
||||
"status": "Open"
|
||||
}
|
||||
service_appointment_names = frappe.get_all(
|
||||
"Service Address 2",
|
||||
filters=filters,
|
||||
pluck="name"
|
||||
)
|
||||
|
|
@ -27,9 +51,11 @@ def get_service_appointments(companies, filters={}):
|
|||
@frappe.whitelist()
|
||||
def update_service_appointment_scheduled_dates(service_appointment_name: str, start_date, end_date, crew_lead_name, start_time=None, end_time=None):
|
||||
"""Update scheduled dates for a Service Appointment."""
|
||||
print(f"DEBUG: Updating scheduled dates for Service Appointment {service_appointment_name} to start: {start_date}, end: {end_date}, crew lead: {crew_lead_name}, start time: {start_time}, end time: {end_time}")
|
||||
try:
|
||||
updated_service_appointment = ServiceAppointmentService.update_scheduled_dates(
|
||||
service_appointment_name,
|
||||
crew_lead_name,
|
||||
start_date,
|
||||
end_date,
|
||||
start_time,
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ def on_update_after_submit(doc, method):
|
|||
print("DEBUG: Quotation marked as Won, updating current status.")
|
||||
if doc.customer_type == "Lead":
|
||||
print("DEBUG: Customer is a Lead, converting to Customer and updating Quotation.")
|
||||
new_customer = ClientService.convert_lead_to_customer(doc.actual_customer_name, update_quotations=False)
|
||||
new_customer = ClientService.convert_lead_to_customer(doc.actual_customer_name)
|
||||
doc.actual_customer_name = new_customer.name
|
||||
doc.customer_type = "Customer"
|
||||
new_customer.reload()
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@ def after_insert(doc, method):
|
|||
)
|
||||
if doc.project_template == "SNW Install":
|
||||
print("DEBUG: Project template is SNW Install, creating Service Appointment")
|
||||
# AddressService.update_value(
|
||||
# doc.job_address,
|
||||
# "job_status",
|
||||
# "In Progress"
|
||||
# )
|
||||
AddressService.update_value(
|
||||
doc.job_address,
|
||||
"job_status",
|
||||
"In Progress"
|
||||
)
|
||||
try:
|
||||
service_apt = ServiceAppointmentService.create({
|
||||
"project": doc.name,
|
||||
|
|
@ -50,7 +50,7 @@ def after_insert(doc, method):
|
|||
)
|
||||
if task_names:
|
||||
doc.save(ignore_permissions=True)
|
||||
TaskService.calculate_and_set_due_dates(task_names, "Created", "Project")
|
||||
TaskService.calculate_and_set_due_dates(task_names, "Created", current_triggering_dict=doc.as_dict())
|
||||
|
||||
|
||||
|
||||
|
|
@ -69,16 +69,16 @@ def before_save(doc, method):
|
|||
elif not doc.expected_start_date or not doc.expected_end_date:
|
||||
print("DEBUG: Project missing expected start or end date, marking as unscheduled")
|
||||
doc.is_scheduled = 0
|
||||
|
||||
def after_save(doc, method):
|
||||
print("DEBUG: After Save Triggered for Project:", doc.name)
|
||||
event = TaskService.determine_event(doc)
|
||||
if event:
|
||||
TaskService.calculate_and_set_due_dates(
|
||||
[task.task for task in doc.tasks],
|
||||
event,
|
||||
"Project"
|
||||
current_triggering_dict=doc.as_dict()
|
||||
)
|
||||
|
||||
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 = {
|
||||
|
|
|
|||
|
|
@ -4,14 +4,28 @@ from custom_ui.services import TaskService
|
|||
|
||||
def on_update(doc, method):
|
||||
print("DEBUG: On Update Triggered for Service Appointment")
|
||||
event = TaskService.determine_event(doc)
|
||||
if event:
|
||||
tasks = TaskService.get_tasks_by_project(doc.project)
|
||||
task_names = [task.name for task in tasks]
|
||||
TaskService.calculate_and_set_due_dates(task_names=task_names, event=event, triggering_doctype="Service Address 2")
|
||||
# event = TaskService.determine_event(doc)
|
||||
# if event:
|
||||
# tasks = TaskService.get_tasks_by_project(doc.project)
|
||||
# task_names = [task.name for task in tasks]
|
||||
# TaskService.calculate_and_set_due_dates(task_names=task_names, event=event, triggering_doctype="Service Address 2")
|
||||
|
||||
def after_insert(doc, method):
|
||||
print("DEBUG: After Insert Triggered for Service Appointment")
|
||||
task_names = [task.name for task in TaskService.get_tasks_by_project(doc.project)]
|
||||
TaskService.calculate_and_set_due_dates(task_names=task_names, event="Created", triggering_doctype="Service Address 2")
|
||||
|
||||
TaskService.calculate_and_set_due_dates(task_names=task_names, event="Created", current_triggering_dict=doc.as_dict())
|
||||
|
||||
def before_save(doc, method):
|
||||
print("DEBUG: Before Save Triggered for Service Appointment")
|
||||
if doc.status == "Open" and doc.expected_start_date:
|
||||
doc.status = "Scheduled"
|
||||
elif doc.status == "Scheduled" and not doc.expected_start_date:
|
||||
doc.status = "Open"
|
||||
if doc.status == "Scheduled" and doc.actual_start_date:
|
||||
doc.status = "Started"
|
||||
elif doc.status != "Completed" and doc.status != "Canceled" and doc.actual_end_date:
|
||||
doc.status = "Completed"
|
||||
event = TaskService.determine_event(doc)
|
||||
if event:
|
||||
task_names = [task.name for task in TaskService.get_tasks_by_project(doc.project)]
|
||||
TaskService.calculate_and_set_due_dates(task_names=task_names, event=event, current_triggering_dict=doc.as_dict())
|
||||
|
|
@ -23,12 +23,12 @@ def after_insert(doc, method):
|
|||
doc.customer, "tasks", {"task": doc.name, "project_template": doc.project_template }
|
||||
)
|
||||
task_names = [task.name for task in TaskService.get_tasks_by_project(doc.project)]
|
||||
TaskService.calculate_and_set_due_dates(task_names, "Created", "Task")
|
||||
TaskService.calculate_and_set_due_dates(task_names, "Created", current_triggering_dict=doc.as_dict())
|
||||
|
||||
def after_save(doc, method):
|
||||
print("DEBUG: After Save Triggered for Task:", doc.name)
|
||||
def before_save(doc, method):
|
||||
print("DEBUG: Before Save Triggered for Task:", doc.name)
|
||||
event = TaskService.determine_event(doc)
|
||||
if event:
|
||||
task_names = [task.name for task in TaskService.get_tasks_by_project(doc.project)]
|
||||
TaskService.calculate_and_set_due_dates(task_names, event, "Task")
|
||||
TaskService.calculate_and_set_due_dates(task_names, event, current_triggering_dict=doc.as_dict())
|
||||
|
||||
|
|
@ -191,10 +191,16 @@ doc_events = {
|
|||
},
|
||||
"Task": {
|
||||
"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"
|
||||
},
|
||||
"Bid Meeting Note Form": {
|
||||
"after_insert": "custom_ui.events.general.attach_bid_note_form_to_project_template"
|
||||
},
|
||||
"Service Address 2": {
|
||||
"before_save": "custom_ui.events.service_appointment.before_save",
|
||||
"after_insert": "custom_ui.events.service_appointment.after_insert",
|
||||
"on_update": "custom_ui.events.service_appointment.on_update"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ def after_migrate():
|
|||
# create_project_templates()
|
||||
create_task_types()
|
||||
# create_tasks()
|
||||
# create_bid_meeting_note_form_templates()
|
||||
create_bid_meeting_note_form_templates()
|
||||
|
||||
# update_address_fields()
|
||||
# build_frontend()
|
||||
|
|
@ -1252,85 +1252,117 @@ def create_project_templates():
|
|||
]
|
||||
}
|
||||
|
||||
import frappe
|
||||
|
||||
|
||||
def create_bid_meeting_note_form_templates():
|
||||
"""Create Bid Meeting Note Forms if they do not exist."""
|
||||
print("\n🔧 Checking for Bid Meeting Note Forms...")
|
||||
|
||||
forms = {
|
||||
"Sprinklers Northwest": [
|
||||
{
|
||||
"name": "SNW Install Bid Meeting Notes",
|
||||
{
|
||||
"title": "SNW Install Bid Meeting Notes",
|
||||
"description": "Notes form for SNW Install bid meetings.",
|
||||
"project_template": "SNW Install",
|
||||
"fields": [{
|
||||
"label": "Locate Needed",
|
||||
"type": "Check",
|
||||
"required": 1,
|
||||
"help_text": "Indicate if a locate is needed for this project.",
|
||||
"row": 1,
|
||||
"column": 1
|
||||
},
|
||||
{
|
||||
"label": "Permit Needed",
|
||||
"type": "Check",
|
||||
"required": 1,
|
||||
"help_text": "Indicate if a permit is needed for this project.",
|
||||
"row": 1,
|
||||
"column": 2
|
||||
},
|
||||
{
|
||||
"label": "Back Flow Test Required",
|
||||
"type": "Check",
|
||||
"required": 1,
|
||||
"help_text": "Indicate if a backflow test is required after installation.",
|
||||
"row": 1,
|
||||
"column": 3
|
||||
},
|
||||
{
|
||||
"label": "Machine Access",
|
||||
"type": "Check",
|
||||
"required": 1,
|
||||
"row": 2,
|
||||
"column": 1
|
||||
},
|
||||
{
|
||||
"label": "Machines",
|
||||
"type": "Multi-Select",
|
||||
"options": "MT, Skip Steer, Excavator-E-50, Link Belt, Tre?, Forks, Auger, Backhoe, Loader, Duzer",
|
||||
"required": 0,
|
||||
"include_options": 1,
|
||||
"conditional_on_field": "Machine Access",
|
||||
"row": 2,
|
||||
"column": 2
|
||||
},
|
||||
{
|
||||
"label": "Materials Required",
|
||||
"type": "Check",
|
||||
"required": 1,
|
||||
"row": 3,
|
||||
"column": 0
|
||||
},
|
||||
{
|
||||
"label": "Materials",
|
||||
"type": "Multi-Select w/ Quantity",
|
||||
"required": 0,
|
||||
"doctype_for_select": "Item",
|
||||
"conditional_on_field": "Materials Required",
|
||||
"doctype_label_field": "itemName",
|
||||
"row": 4,
|
||||
"column": 0
|
||||
}]
|
||||
}]}
|
||||
"fields": [
|
||||
{
|
||||
"label": "Locate Needed",
|
||||
"type": "Check",
|
||||
"required": 1,
|
||||
"help_text": "Indicate if a locate is needed for this project.",
|
||||
"row": 1,
|
||||
"column": 1,
|
||||
},
|
||||
{
|
||||
"label": "Permit Needed",
|
||||
"type": "Check",
|
||||
"required": 1,
|
||||
"help_text": "Indicate if a permit is needed for this project.",
|
||||
"row": 1,
|
||||
"column": 2,
|
||||
},
|
||||
{
|
||||
"label": "Back Flow Test Required",
|
||||
"type": "Check",
|
||||
"required": 1,
|
||||
"help_text": "Indicate if a backflow test is required after installation.",
|
||||
"row": 1,
|
||||
"column": 3,
|
||||
},
|
||||
{
|
||||
"label": "Machine Access",
|
||||
"type": "Check",
|
||||
"required": 1,
|
||||
"row": 2,
|
||||
"column": 1,
|
||||
},
|
||||
{
|
||||
"label": "Machines",
|
||||
"type": "Multi-Select",
|
||||
"options": "MT, Skip Steer, Excavator-E-50, Link Belt, Tre?, Forks, Auger, Backhoe, Loader, Duzer",
|
||||
"include_options": 1,
|
||||
"conditional_on_field": "Machine Access",
|
||||
"row": 2,
|
||||
"column": 2,
|
||||
},
|
||||
{
|
||||
"label": "Materials Required",
|
||||
"type": "Check",
|
||||
"required": 1,
|
||||
"row": 3,
|
||||
"column": 0,
|
||||
},
|
||||
{
|
||||
"label": "Materials",
|
||||
"type": "Multi-Select w/ Quantity",
|
||||
"doctype_for_select": "Item",
|
||||
"doctype_label_field": "itemName",
|
||||
"conditional_on_field": "Materials Required",
|
||||
"row": 4,
|
||||
"column": 0,
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
for company, form_list in forms.items():
|
||||
for form in form_list:
|
||||
if frappe.db.exists("Bid Meeting Note Form", form["name"]):
|
||||
# Idempotency check
|
||||
if frappe.db.exists(
|
||||
"Bid Meeting Note Form",
|
||||
{"title": form["title"], "company": company},
|
||||
):
|
||||
continue
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "Bid Meeting Note Form",
|
||||
"company": company,
|
||||
"title": form["title"],
|
||||
"description": form["description"],
|
||||
"project_template": form["project_template"],
|
||||
"fields": form["fields"]
|
||||
})
|
||||
|
||||
doc = frappe.new_doc("Bid Meeting Note Form")
|
||||
doc.company = company
|
||||
doc.title = form["title"]
|
||||
doc.description = form.get("description")
|
||||
doc.project_template = form.get("project_template")
|
||||
|
||||
for idx, field in enumerate(form.get("fields", []), start=1):
|
||||
doc.append(
|
||||
"fields",
|
||||
{
|
||||
"label": field["label"],
|
||||
"type": field["type"],
|
||||
"options": field.get("options"),
|
||||
"required": field.get("required", 0),
|
||||
"default_value": field.get("default_value"),
|
||||
"read_only": field.get("read_only", 0),
|
||||
"order": field.get("order", 0),
|
||||
"help_text": field.get("help_text"),
|
||||
"doctype_for_select": field.get("doctype_for_select"),
|
||||
"include_options": field.get("include_options", 0),
|
||||
"conditional_on_field": field.get("conditional_on_field"),
|
||||
"conditional_on_value": field.get("conditional_on_value"),
|
||||
"doctype_label_field": field.get("doctype_label_field"),
|
||||
"row": field.get("row"),
|
||||
"column": field.get("column"),
|
||||
"idx": idx,
|
||||
},
|
||||
)
|
||||
|
||||
doc.insert(ignore_permissions=True)
|
||||
|
|
|
|||
|
|
@ -122,7 +122,6 @@ class ClientService:
|
|||
print(f"DEBUG: Linked quotation {quotation.get('quotation')} to customer")
|
||||
except Exception as e:
|
||||
print(f"ERROR: Failed to link quotation {quotation.get('quotation')}: {str(e)}")
|
||||
frappe.log_error(f"Quotation linking error: {str(e)}", "convert_lead_to_customer")
|
||||
|
||||
if update_onsite_meetings:
|
||||
print(f"DEBUG: Updating onsite meetings. Count: {len(lead_doc.get('onsite_meetings', []))}")
|
||||
|
|
|
|||
|
|
@ -22,17 +22,18 @@ class ServiceAppointmentService:
|
|||
service_appointment = frappe.get_doc("Service Address 2", service_appointment_name).as_dict()
|
||||
service_appointment["service_address"] = AddressService.get_or_throw(service_appointment["service_address"]).as_dict()
|
||||
service_appointment["customer"] = ClientService.get_client_or_throw(service_appointment["customer"]).as_dict()
|
||||
service_appointment["project"] = DbService.get_doc_or_throw("Project", service_appointment["project"]).as_dict()
|
||||
service_appointment["project"] = DbService.get_or_throw("Project", service_appointment["project"]).as_dict()
|
||||
|
||||
return service_appointment
|
||||
|
||||
@staticmethod
|
||||
def update_scheduled_dates(service_appointment_name: str, start_date, end_date, start_time=None, end_time=None):
|
||||
def update_scheduled_dates(service_appointment_name: str, crew_lead_name: str,start_date, end_date, start_time=None, end_time=None):
|
||||
"""Update the scheduled start and end dates of a Service Appointment."""
|
||||
print(f"DEBUG: Updating scheduled dates for Service Appointment {service_appointment_name} to start: {start_date}, end: {end_date}")
|
||||
service_appointment = DbService.get_or_throw("Service Address 2", service_appointment_name)
|
||||
service_appointment.expected_start_date = start_date
|
||||
service_appointment.expected_end_date = end_date
|
||||
service_appointment.foreman = crew_lead_name
|
||||
if start_time:
|
||||
service_appointment.expected_start_time = start_time
|
||||
if end_time:
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
import frappe
|
||||
from frappe.utils.safe_exec import safe_eval
|
||||
from datetime import timedelta, datetime, date
|
||||
from frappe.utils import getdate
|
||||
class TaskService:
|
||||
|
||||
|
||||
@staticmethod
|
||||
def calculate_and_set_due_dates(task_names: list[str], event: str, triggering_doctype: str):
|
||||
def calculate_and_set_due_dates(task_names: list[str], event: str, current_triggering_dict=None):
|
||||
"""Calculate the due date for a list of tasks based on their expected end dates."""
|
||||
for task_name in task_names:
|
||||
TaskService.check_and_update_task_due_date(task_name, event, triggering_doctype)
|
||||
TaskService.check_and_update_task_due_date(task_name, event, current_triggering_dict)
|
||||
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -19,14 +20,14 @@ class TaskService:
|
|||
return tasks
|
||||
|
||||
@staticmethod
|
||||
def check_and_update_task_due_date(task_name: str, event: str, triggering_doctype: str):
|
||||
def check_and_update_task_due_date(task_name: str, event: str, current_triggering_dict=None):
|
||||
"""Determine the triggering configuration for a given task."""
|
||||
task_type_doc = TaskService.get_task_type_doc(task_name)
|
||||
if task_type_doc.no_due_date:
|
||||
print(f"DEBUG: Task {task_name} is marked as no due date, skipping calculation.")
|
||||
return
|
||||
if task_type_doc.triggering_doctype != triggering_doctype:
|
||||
print(f"DEBUG: Task {task_name} triggering doctype {task_type_doc.triggering_doctype} does not match triggering doctype {triggering_doctype}, skipping calculation.")
|
||||
if task_type_doc.triggering_doctype != current_triggering_dict.get("doctype") and current_triggering_dict:
|
||||
print(f"DEBUG: Task {task_name} triggering doctype {task_type_doc.triggering_doctype} does not match triggering doctype {current_triggering_dict.get('doctype')}, skipping calculation.")
|
||||
return
|
||||
if task_type_doc.trigger != event:
|
||||
print(f"DEBUG: Task {task_name} trigger {task_type_doc.trigger} does not match event {event}, skipping calculation.")
|
||||
|
|
@ -42,7 +43,7 @@ class TaskService:
|
|||
print(f"DEBUG: Calculating triggering data for Task {task_name} from {calculate_from} on trigger {trigger}")
|
||||
|
||||
|
||||
triggering_doc_dict = TaskService.get_triggering_doc_dict(task_name=task_name, task_type_doc=task_type_doc)
|
||||
triggering_doc_dict = current_triggering_dict if current_triggering_dict else TaskService.get_triggering_doc_dict(task_name=task_name, task_type_doc=task_type_doc)
|
||||
|
||||
|
||||
calculated_due_date, calculated_start_date = TaskService.calculate_dates(
|
||||
|
|
@ -72,15 +73,18 @@ class TaskService:
|
|||
def calculate_dates(task_name: str, triggering_doc_dict: dict, task_type_doc) -> tuple[date | None, date | None]:
|
||||
offset_direction = task_type_doc.offset_direction
|
||||
offset_days = task_type_doc.offset_days
|
||||
base_date_field = TaskService.map_base_date_to_field(task_type_doc.base_date)
|
||||
|
||||
base_date_field = TaskService.map_base_date_to_field(task_type_doc.base_date, task_type_doc.triggering_doctype)
|
||||
print(f"DEBUG: base_date_field for Task {task_name} is {base_date_field}")
|
||||
if offset_direction == "Before":
|
||||
offset_days = -offset_days
|
||||
|
||||
base_date_field_value = triggering_doc_dict.get(base_date_field)
|
||||
print(f"DEBUG: base_date_field_value for Task {task_name} is {base_date_field_value}")
|
||||
|
||||
if isinstance(base_date_field_value, datetime):
|
||||
base_date_field_value = base_date_field_value.date()
|
||||
base_date_field_value = base_date_field_value
|
||||
else:
|
||||
base_date_field_value = getdate(base_date_field_value)
|
||||
|
||||
calculated_due_date = base_date_field_value + timedelta(days=offset_days)
|
||||
calculated_start_date = None
|
||||
|
|
@ -91,8 +95,8 @@ class TaskService:
|
|||
|
||||
@staticmethod
|
||||
def determine_update_required(task_name: str, calculated_due_date: date | None, calculated_start_date: date | None) -> bool:
|
||||
current_due_date = frappe.get_value("Task", task_name, "expected_end_date")
|
||||
current_start_date = frappe.get_value("Task", task_name, "expected_start_date")
|
||||
current_due_date = frappe.get_value("Task", task_name, "exp_end_date")
|
||||
current_start_date = frappe.get_value("Task", task_name, "exp_start_date")
|
||||
if current_due_date != calculated_due_date or current_start_date != calculated_start_date:
|
||||
print(f"DEBUG: Update required for Task {task_name}. Current due date: {current_due_date}, Calculated due date: {calculated_due_date}. Current start date: {current_start_date}, Calculated start date: {calculated_start_date}")
|
||||
return True
|
||||
|
|
@ -104,30 +108,31 @@ class TaskService:
|
|||
@staticmethod
|
||||
def get_triggering_doc_dict(task_name: str, task_type_doc) -> dict | None:
|
||||
project_name = frappe.get_value("Task", task_name, "project")
|
||||
print(f"DEBUG: Project name: {project_name}")
|
||||
dict = None
|
||||
if task_type_doc.calculate_from == "Project":
|
||||
dict = frappe.get_doc("Project", project_name).to_dict()
|
||||
dict = frappe.get_doc("Project", project_name).as_dict()
|
||||
if task_type_doc.calculate_from == "Service Address 2":
|
||||
service_name = frappe.get_value("Project", project_name, "service_appointment")
|
||||
dict = frappe.get_doc("Service Address 2", service_name).to_dict()
|
||||
dict = frappe.get_doc("Service Address 2", service_name).as_dict()
|
||||
if task_type_doc.calculate_from == "Task":
|
||||
project_doc = frappe.get_doc("Project", project_name)
|
||||
for task in project_doc.tasks:
|
||||
if task.task_type == task_type_doc.task_type_calculate_from:
|
||||
dict = frappe.get_doc("Task", task.task).to_dict()
|
||||
dict = frappe.get_doc("Task", task.task).as_dict()
|
||||
print(f"DEBUG: Triggering doc dict for Task {task_name}: {dict}")
|
||||
return dict
|
||||
|
||||
@staticmethod
|
||||
def update_task_dates(task_name: str, calculated_due_date: date | None, calculated_start_date: date | None):
|
||||
task_doc = frappe.get_doc("Task", task_name)
|
||||
task_doc.expected_end_date = calculated_due_date
|
||||
task_doc.expected_start_date = calculated_start_date
|
||||
task_doc.exp_end_date = calculated_due_date
|
||||
task_doc.exp_start_date = calculated_start_date
|
||||
task_doc.save(ignore_permissions=True)
|
||||
print(f"DEBUG: Updated Task {task_name} with new dates - Start: {calculated_start_date}, End: {calculated_due_date}")
|
||||
|
||||
@staticmethod
|
||||
def map_base_date_to_field(base_date: str) -> str:
|
||||
def map_base_date_to_field(base_date: str, triggering_doctype: str) -> str:
|
||||
"""Map a base date configuration to a corresponding field name."""
|
||||
base_date_field_map = {
|
||||
"Start": "expected_start_date",
|
||||
|
|
@ -135,12 +140,29 @@ class TaskService:
|
|||
"Creation": "creation",
|
||||
"Completion": "actual_end_date"
|
||||
}
|
||||
task_date_field_map = {
|
||||
"Start": "exp_start_date",
|
||||
"End": "exp_end_date",
|
||||
"Creation": "creation",
|
||||
"Completion": "actual_end_date"
|
||||
}
|
||||
if triggering_doctype == "Task":
|
||||
return task_date_field_map.get(base_date, "exp_end_date")
|
||||
return base_date_field_map.get(base_date, "expected_end_date")
|
||||
|
||||
@staticmethod
|
||||
def determine_event(triggering_doc) -> str | None:
|
||||
prev_doc = triggering_doc.get_doc_before_save()
|
||||
if prev_doc.expected_end_date != triggering_doc.expected_end_date or prev_doc.expected_start_date != triggering_doc.expected_start_date:
|
||||
def determine_event(triggering_doc) -> str | None:
|
||||
print("DEBUG: Current Document:", triggering_doc.as_dict())
|
||||
if not frappe.db.exists(triggering_doc.doctype, triggering_doc.name):
|
||||
print("DEBUG: Document does not exist in database, returning None for event.")
|
||||
return None
|
||||
prev_doc = frappe.get_doc(triggering_doc.doctype, triggering_doc.name, as_dict=False, ignore_if_missing=True)
|
||||
start_date_field = "expected_start_date" if triggering_doc.doctype != "Task" else "exp_start_date"
|
||||
end_date_field = "expected_end_date" if triggering_doc.doctype != "Task" else "exp_end_date"
|
||||
print("DEBUG: Previous Document:", prev_doc.as_dict() if prev_doc else "None")
|
||||
if not prev_doc:
|
||||
return None
|
||||
if getattr(prev_doc, end_date_field) != getattr(triggering_doc, end_date_field) or getattr(prev_doc, start_date_field) != getattr(triggering_doc, start_date_field):
|
||||
return "Scheduled"
|
||||
elif prev_doc.status != triggering_doc.status and triggering_doc.status == "Completed":
|
||||
return "Completed"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue