create estimate

This commit is contained in:
Casey 2025-11-26 16:47:53 -06:00
parent 2ea20a86e3
commit afa161a0cf
15 changed files with 1234 additions and 435 deletions

View file

@ -92,96 +92,45 @@ def get_client_status_counts(weekly=False, week_start_date=None, week_end_date=N
def get_client(client_name):
"""Get detailed information for a specific client including address, customer, and projects."""
try:
clientData = {"addresses": []}
clientData = {"addresses": [], "contacts": [], "jobs": [], "sales_invoices": [], "payment_entries": [], "sales_orders": [], "tasks": []}
customer = frappe.get_doc("Customer", client_name)
clientData = {**clientData, **customer.as_dict()}
addresses = frappe.db.get_all("Address", fields=["*"], filters={"custom_customer_to_bill": client_name})
contacts = frappe.db.get_all("Contact", fields=["*"], filters={"custom_customer": client_name})
clientData["contacts"] = contacts
for address in addresses if addresses else []:
addressData = {"jobs": []}
addressData = {**addressData, **address}
addressData["estimates"] = frappe.db.get_all("Quotation", fields=["*"], filters={"custom_installation_address": address.address_title})
addressData["onsite_meetings"] = frappe.db.get_all("On-Site Meeting", fields=["*"], filters={"address": address.address_title})
jobs = frappe.db.get_all("Project", fields=["*"], or_filters=[
["custom_installation_address", "=", address.address_title],
["custom_address", "=", address.address_title]
])
for job in jobs if jobs else []:
jobData = {}
jobData = {**jobData, **job}
jobData["sales_invoices"] = frappe.db.get_all("Sales Invoice", fields=["*"], filters={"project": job.name})
jobData["payment_entries"] = frappe.db.get_all(
"Payment Entry",
fields=["*"],
filters={"party_type": "Customer"},
or_filters=[
["party", "=", client_name],
["party_name", "=", client_name]
])
jobData["sales_orders"] = frappe.db.get_all("Sales Order", fields=["*"], filters={"project": job.name})
jobData["tasks"] = frappe.db.get_all("Task", fields=["*"], filters={"project": job.name})
addressData["jobs"].append(jobData)
clientData["addresses"].append(addressData)
for contact_link in customer.custom_add_contacts:
contact_doc = frappe.get_doc("Contact", contact_link.contact)
clientData["contacts"].append(contact_doc.as_dict())
for address_link in customer.custom_select_address:
address_doc = frappe.get_doc("Address", address_link.address_name)
# # addressData = {"jobs": [], "contacts": []}
# addressData = {**addressData, **address_doc.as_dict()}
# addressData["estimates"] = frappe.db.get_all("Quotation", fields=["*"], filters={"custom_installation_address": address_doc.address_title})
# addressData["onsite_meetings"] = frappe.db.get_all("On-Site Meeting", fields=["*"], filters={"address": address_doc.address_title})
# jobs = frappe.db.get_all("Project", fields=["*"], or_filters=[
# ["custom_installation_address", "=", address.address_title],
# ["custom_address", "=", address.address_title]
# ])
# for job in jobs if jobs else []:
# jobData = {}
# jobData = {**jobData, **job}
# jobData["sales_invoices"] = frappe.db.get_all("Sales Invoice", fields=["*"], filters={"project": job.name})
# jobData["payment_entries"] = frappe.db.get_all(
# "Payment Entry",
# fields=["*"],
# filters={"party_type": "Customer"},
# or_filters=[
# ["party", "=", client_name],
# ["party_name", "=", client_name]
# ])
# jobData["sales_orders"] = frappe.db.get_all("Sales Order", fields=["*"], filters={"project": job.name})
# jobData["tasks"] = frappe.db.get_all("Task", fields=["*"], filters={"project": job.name})
# addressData["jobs"].append(jobData)
clientData["addresses"].append(address_doc.as_dict())
return build_success_response(clientData)
except frappe.ValidationError as ve:
return build_error_response(str(ve), 400)
except Exception as e:
return build_error_response(str(e), 500)
# address = frappe.get_doc("Address", client_name)
# customer_name = address.custom_customer_to_bill if address.custom_customer_to_bill else [link.link_name for link in address.links if link.link_doctype == "Customer"][0] if address.links else None
# if not customer_name:
# raise Exception(f"No customer linked to address {client_name}. Suggested fix: Ensure the address is linked to a customer via the ERPnext UI.")
# project_names = frappe.db.get_all("Project", fields=["name"], or_filters=[
# ["custom_installation_address", "=", address.address_title],
# ["custom_address", "=", address.address_title]
# ], limit_page_length=100)
# # contacts = [] # currently not needed as the customer doctype comes with contacts
# onsite_meetings = frappe.db.get_all(
# "On-Site Meeting",
# fields=["*"],
# filters={"address": address.address_title}
# )
# quotations = frappe.db.get_all(
# "Quotation",
# fields=["*"],
# filters={"custom_installation_address": address.address_title}
# )
# sales_orders = []
# projects = [frappe.get_doc("Project", proj["name"]) for proj in project_names]
# sales_invoices = []
# payment_entries = frappe.db.get_all(
# "Payment Entry",
# fields=["*"],
# filters={"party_type": "Customer"},
# or_filters=[
# ["party", "=", customer_name],
# ["party_name", "=", customer_name]
# ])
# payment_orders = []
# jobs = []
# for project in projects:
# job = []
# jobs.append(job)
# customer = frappe.get_doc("Customer", customer_name)
# # get all associated data as needed
# return build_success_response({
# "address": address,
# "customer": customer,
# # "contacts": [], # currently not needed as the customer doctype comes with contacts
# "jobs": jobs,
# "sales_invoices": sales_invoices,
# "payment_entries": payment_entries,
# "sales_orders": sales_orders,
# "quotations": quotations,
# "onsite_meetings": onsite_meetings,
# })
except frappe.ValidationError as ve:
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(filters={}, sortings=[], page=1, page_size=10):
@ -253,10 +202,11 @@ def get_clients_table_data(filters={}, sortings=[], page=1, page_size=10):
def upsert_client(data):
"""Create or update a client (customer and address)."""
try:
data = json.loads(data)
# Handle customer creation/update
print("#####DEBUG: Upsert client data received:", data)
print("#####DEBUG: Checking for existing customer with name:", data.get("customer_name"))
customer = frappe.db.exists("Customer", {"customer_name": data.get("customer_name")})
if not customer:
customer_doc = frappe.get_doc({
@ -266,21 +216,20 @@ def upsert_client(data):
}).insert(ignore_permissions=True)
else:
customer_doc = frappe.get_doc("Customer", data.get("customer_name"))
print("Customer:", customer_doc.as_dict())
# Check for existing address
filters = {
"address_line1": data.get("address_line1"),
"city": data.get("city"),
"state": data.get("state"),
}
existing_address = frappe.db.exists("Address", filters)
# Handle address creation
print("#####DEBUG: Checking for existing address for customer:", data.get("customer_name"))
existing_address = frappe.db.exists(
"Address",
{
"address_line1": data.get("address_line1"),
"city": data.get("city"),
"state": data.get("state"),
})
print("Existing address check:", existing_address)
if existing_address:
frappe.throw(f"Address already exists for customer {data.get('customer_name')}.", frappe.ValidationError)
# Create address
address_doc = frappe.get_doc({
"doctype": "Address",
"address_title": data.get("address_title"),
@ -292,37 +241,97 @@ def upsert_client(data):
"pincode": data.get("pincode"),
"custom_customer_to_bill": customer_doc.name
}).insert(ignore_permissions=True)
print("Address:", address_doc.as_dict())
# Link address to customer
link = {
#Handle contact creation
contact_docs = []
for contact_data in data.get("contacts", []):
if isinstance(contact_data, str):
contact_data = json.loads(contact_data)
print("#####DEBUG: Processing contact data:", contact_data)
contact_exists = frappe.db.exists("Contact", {"email_id": contact_data.get("email"), "phone": contact_data.get("phone_number")})
if not contact_exists:
is_primary_contact = 1 if contact_data.get("is_primary_contact") else 0
contact_doc = frappe.get_doc({
"doctype": "Contact",
"first_name": contact_data.get("first_name"),
"last_name": contact_data.get("last_name"),
"email_id": contact_data.get("email"),
"phone": contact_data.get("phone_number"),
"custom_customer": customer_doc.name,
"role": contact_data.get("contact_role", "Other"),
"custom_email": contact_data.get("email"),
"is_primary_contact": is_primary_contact
}).insert(ignore_permissions=True)
print("Created new contact:", contact_doc.as_dict())
else:
contact_doc = frappe.get_doc("Contact", {"email_id": data.get("email")})
print("Contact already exists:", contact_doc.as_dict())
contact_docs.append(contact_doc)
##### Create links
# Customer -> Address
print("#####DEBUG: Creating links between customer, address, and contacts.")
customer_doc.append("custom_select_address", {
"address_name": address_doc.name,
"address_line_1": address_doc.address_line1,
"city": address_doc.city,
"state": address_doc.state,
"pincode": address_doc.pincode
})
# Customer -> Contact
print("#####DEBUG: Linking contacts to customer.")
for contact_doc in contact_docs:
print("Linking contact:", contact_doc.as_dict())
print("with role:", contact_doc.role)
print("customer to append to:", customer_doc.as_dict())
customer_doc.append("custom_add_contacts", {
"contact": contact_doc.name,
"email": contact_doc.custom_email,
"phone": contact_doc.phone,
"role": contact_doc.role
})
# Address -> Customer
print("#####DEBUG: Linking address to customer.")
address_doc.append("links", {
"link_doctype": "Customer",
"link_name": customer_doc.name
}
address_doc.append("links", link)
contact_exists = frappe.db.exists("Contact", {"email_id": data.get("contact_email")})
if not contact_exists:
contact_doc = frappe.get_doc({
"doctype": "Contact",
"first_name": data.get("first_name"),
"last_name": data.get("last_name"),
"email_id": data.get("email"),
"phone": data.get("phone_number"),
"custom_customer": customer_doc.name,
"links": [{
"link_doctype": "Customer",
"link_name": customer_doc.name
}]
}).insert(ignore_permissions=True)
print("Created new contact:", contact_doc.as_dict())
else:
contact_doc = frappe.get_doc("Contact", {"email_id": data.get("contact_email")})
print("Contact already exists:", contact_doc.as_dict())
address_doc.custom_contact = contact_doc.name
})
# Address -> Contact
print("#####DEBUG: Linking address to contacts.")
address_doc.custom_contact = next((c.name for c in contact_docs if c.is_primary_contact), contact_docs[0].name)
for contact_doc in contact_docs:
address_doc.append("custom_linked_contacts", {
"contact": contact_doc.name,
"email": contact_doc.email_id,
"phone": contact_doc.phone,
"role": contact_doc.role
})
# Contact -> Customer & Address
print("#####DEBUG: Linking contacts to customer.")
for contact_doc in contact_docs:
contact_doc.append("links", {
"link_doctype": "Customer",
"link_name": customer_doc.name
})
contact_doc.append("links", {
"link_doctype": "Address",
"link_name": address_doc.name
})
contact_doc.custom_customer = customer_doc.name
contact_doc.save(ignore_permissions=True)
address_doc.save(ignore_permissions=True)
customer_doc.save(ignore_permissions=True)
return build_success_response({
"customer": customer_doc.as_dict(),
"address": address_doc.as_dict(),
"contact": contact_doc.as_dict()
"contacts": [contact_doc.as_dict() for contact_doc in contact_docs]
})
except frappe.ValidationError as ve:
return build_error_response(str(ve), 400)