update calendar

This commit is contained in:
Casey 2026-01-21 08:44:20 -06:00
parent 7395d3e048
commit e67805c01f
10 changed files with 848 additions and 325 deletions

View file

@ -404,7 +404,7 @@ def upsert_estimate(data):
# estimate.custom_job_address = data.get("address_name")
# estimate.party_name = data.get("customer")
# estimate.contact_person = data.get("contact_name")
estimate.custom_requires_half_payment = data.get("requires_half_payment", 0)
estimate.requires_half_payment = data.get("requires_half_payment", 0)
estimate.custom_project_template = project_template
estimate.custom_quotation_template = data.get("quotation_template", None)
# estimate.company = data.get("company")
@ -427,6 +427,7 @@ def upsert_estimate(data):
})
estimate.save()
frappe.db.commit()
estimate_dict = estimate.as_dict()
estimate_dict["history"] = get_doc_history("Quotation", estimate_name)
print(f"DEBUG: Estimate updated: {estimate.name}")
@ -444,7 +445,7 @@ def upsert_estimate(data):
# print("DEBUG: No billing address found for client:", client_doc.name)
new_estimate = frappe.get_doc({
"doctype": "Quotation",
"custom_requires_half_payment": data.get("requires_half_payment", 0),
"requires_half_payment": data.get("requires_half_payment", 0),
"custom_job_address": data.get("address_name"),
"custom_current_status": "Draft",
"contact_email": data.get("contact_email"),

View file

@ -1,6 +1,7 @@
import frappe, json
from custom_ui.db_utils import process_query_conditions, build_datatable_dict, get_count_or_filters, build_success_response, build_error_response
from custom_ui.services import AddressService, ClientService
from frappe.utils import getdate
# ===============================================================================
# JOB MANAGEMENT API METHODS
@ -177,21 +178,26 @@ def upsert_job(data):
return {"status": "error", "message": str(e)}
@frappe.whitelist()
def get_projects_for_calendar(date, company=None, project_templates=[]):
def get_projects_for_calendar(start_date, end_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))
print("📅📅📅", start_date, end_date, " company:", company, "project_templates:", project_templates, "type:", type(project_templates))
try:
filters = {"company": company} if company else {}
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
# add to filter for if expected_start_date is between start_date and end_date OR expected_end_date is between start_date and end_date
filters["expected_start_date"] = ["<=", getdate(end_date)]
filters["expected_end_date"] = [">=", getdate(start_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).
@ -206,3 +212,22 @@ def get_projects_for_calendar(date, company=None, project_templates=[]):
return build_success_response({ "projects": projects, "unscheduled_projects": unscheduled_projects })
except Exception as e:
return build_error_response(str(e), 500)
@frappe.whitelist()
def update_job_scheduled_dates(job_name: str, new_start_date: str = None, new_end_date: str = None, foreman_name: str = None):
"""Update job (project) schedule dates."""
print("DEBUG: Updating job schedule:", job_name, new_start_date, new_end_date, foreman_name)
try:
project = frappe.get_doc("Project", job_name)
project.expected_start_date = getdate(new_start_date) if new_start_date else None
project.expected_end_date = getdate(new_end_date) if new_end_date else None
if new_start_date and new_end_date:
project.is_scheduled = 1
else:
project.is_scheduled = 0
if foreman_name:
project.custom_foreman = foreman_name
project.save()
return build_success_response(project.as_dict())
except Exception as e:
return build_error_response(str(e), 500)

View file

@ -1,6 +1,6 @@
import frappe
from custom_ui.services import AddressService, ClientService
from datetime import timedelta
def after_insert(doc, method):
print("DEBUG: After Insert Triggered for Project")
@ -30,8 +30,13 @@ def before_insert(doc, method):
def before_save(doc, method):
print("DEBUG: Before Save Triggered for Project:", doc.name)
if doc.expected_start_date and doc.expected_end_date:
print("DEBUG: Project has expected start and end dates, marking as scheduled")
doc.is_scheduled = 1
else:
while frappe.db.exists("Holiday", {"holiday_date": doc.expected_end_date}):
print("DEBUG: Expected end date falls on a holiday, extending end date by 1 day")
doc.expected_end_date += timedelta(days=1)
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):
@ -44,8 +49,10 @@ def after_save(doc, method):
"Closed": "Completed"
}
new_status = status_mapping.get(doc.status, "In Progress")
AddressService.update_value(
doc.job_address,
"job_status",
new_status
)
if frappe.db.get_value("Address", doc.job_address, "job_status") != new_status:
print("DEBUG: Updating Address job_status to:", new_status)
AddressService.update_value(
doc.job_address,
"job_status",
new_status
)

View file

@ -178,8 +178,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": null,
"modified": "2026-01-19 18:10:16.782664",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:39.681180",
"module": "Custom UI",
"name": "Customer Task Link",
"naming_rule": "",
@ -396,8 +396,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": null,
"modified": "2026-01-19 18:10:02.359022",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:39.752798",
"module": "Custom UI",
"name": "Address Task Link",
"naming_rule": "",
@ -550,8 +550,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:17.097017",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:39.827207",
"module": "Custom",
"name": "Lead Companies Link",
"naming_rule": "",
@ -768,8 +768,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:17.150584",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:39.914772",
"module": "Custom",
"name": "Address Project Link",
"naming_rule": "",
@ -986,8 +986,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:17.203403",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:40.049882",
"module": "Custom",
"name": "Address Quotation Link",
"naming_rule": "",
@ -1204,8 +1204,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:17.255846",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:40.145083",
"module": "Custom",
"name": "Address On-Site Meeting Link",
"naming_rule": "",
@ -1422,8 +1422,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:17.309600",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:40.270888",
"module": "Custom",
"name": "Address Sales Order Link",
"naming_rule": "",
@ -1576,8 +1576,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:17.361237",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:40.346187",
"module": "Custom",
"name": "Contact Address Link",
"naming_rule": "",
@ -1730,8 +1730,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:17.412683",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:40.418889",
"module": "Custom",
"name": "Lead On-Site Meeting Link",
"naming_rule": "",
@ -2332,8 +2332,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:17.483924",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:40.507246",
"module": "Selling",
"name": "Quotation Template",
"naming_rule": "",
@ -2830,8 +2830,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:17.558008",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:40.595751",
"module": "Selling",
"name": "Quotation Template Item",
"naming_rule": "",
@ -2984,8 +2984,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:17.609372",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:40.676141",
"module": "Custom UI",
"name": "Customer Company Link",
"naming_rule": "",
@ -3138,8 +3138,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:17.660893",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:40.749303",
"module": "Custom UI",
"name": "Customer Address Link",
"naming_rule": "",
@ -3292,8 +3292,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:17.712878",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:40.836296",
"module": "Custom UI",
"name": "Customer Contact Link",
"naming_rule": "",
@ -3446,8 +3446,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:17.765849",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:40.900156",
"module": "Custom",
"name": "Address Contact Link",
"naming_rule": "",
@ -3600,8 +3600,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:17.818352",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:40.986399",
"module": "Custom",
"name": "Customer On-Site Meeting Link",
"naming_rule": "",
@ -3754,8 +3754,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:17.870984",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:41.054749",
"module": "Custom",
"name": "Customer Project Link",
"naming_rule": "",
@ -3908,8 +3908,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:17.922695",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:41.114144",
"module": "Custom",
"name": "Customer Quotation Link",
"naming_rule": "",
@ -4062,8 +4062,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:17.975165",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:41.170115",
"module": "Custom",
"name": "Customer Sales Order Link",
"naming_rule": "",
@ -4216,8 +4216,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:18.027046",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:41.226997",
"module": "Custom",
"name": "Lead Address Link",
"naming_rule": "",
@ -4370,8 +4370,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:18.078476",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:41.283969",
"module": "Custom",
"name": "Lead Contact Link",
"naming_rule": "",
@ -4524,8 +4524,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:18.170095",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:41.344731",
"module": "Custom",
"name": "Lead Quotation Link",
"naming_rule": "",
@ -4678,8 +4678,8 @@
"make_attachments_public": 0,
"max_attachments": 0,
"menu_index": null,
"migration_hash": "0df0ede31f640435231ba887f40eca91",
"modified": "2026-01-19 20:52:18.238066",
"migration_hash": "9792f2dfc070efd283d24244c612c2d4",
"modified": "2026-01-20 12:56:41.401007",
"module": "Custom",
"name": "Address Company Link",
"naming_rule": "",

View file

@ -263,7 +263,8 @@ fixtures = [
"dt": "Property Setter",
"filters": [
["doc_type", "=", "Lead"],
["doc_type", "=", "Project"]
["doc_type", "=", "Project"],
["doc_type", "=", "Address"]
]
}

View file

@ -598,6 +598,12 @@ def add_custom_fields():
options="Company",
insert_after="project_type",
description="The company associated with this project template."
),
dict(
fieldname="calendar_color",
label="Calendar Color",
fieldtype="Color",
insert_after="company"
)
],
"Task": [